Login | ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/fastphp/trunk/EditorMain.pas
Revision: 66
Committed: Sun Mar 29 22:57:59 2020 UTC (44 hours, 29 minutes ago) by daniel-marschall
Content type: text/x-pascal
File size: 38755 byte(s)
Log Message:
Before theme change: Ask if the user wants to save their work

File Contents

# Content
1 unit EditorMain;
2
3 {$Include 'FastPHP.inc'}
4
5 // TODO 70423 * <fastphp> bug beheben, bei dem php.exe im hintergrund geöffnet bleibt, wenn man den editor schließt !!!!!!!!!
6
7 (*
8 This program requires
9 - Microsoft Internet Controls (TWebBrowser)
10 If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
11 "Microsoft Internet Controls"
12 - SynEdit
13 You can obtain SynEdit via Embarcadero GetIt
14 *)
15
16 // TODO: localize
17 // TODO: wieso geht copy paste im twebbrowser nicht???
18 // TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
19 // TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
20 // TODO: Browser titlebar (link preview)
21 // TODO: "jump to next/prev todo" buttons/shortcuts
22 // TODO: "increase/decrease indent" buttons/shortcuts
23
24 // Small things:
25 // - The scroll bars of SynEdit are not affected by the dark theme
26
27 // Future ideas
28 // - code insight
29 // - verschiedene php versionen?
30 // - webbrowser1 nur laden, wenn man den tab anwählt?
31 // - doppelklick auf tab soll diesen schließen
32 // - Onlinehelp (www) aufrufen
33 // - Let all colors be adjustable
34 // - code in bildschirmmitte (horizontal)?
35
36 interface
37
38 uses
39 // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
40 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
41 Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
42 SynEditHighlighter, SynHighlighterPHP, SynEdit, ShDocVw_TLB, FindReplace,
43 ActnList, SynEditMiscClasses, SynEditSearch, RunPHP, ImgList, SynUnicode,
44 System.ImageList, System.Actions, Vcl.Menus, SHDocVw, Vcl.Themes;
45
46 {.$DEFINE OnlineHelp}
47
48 type
49 TForm1 = class(TForm)
50 PageControl1: TPageControl;
51 PlaintextTabSheet: TTabSheet;
52 HtmlTabSheet: TTabSheet;
53 Memo2: TMemo;
54 WebBrowser1: TWebBrowser;
55 Splitter1: TSplitter;
56 PageControl2: TPageControl;
57 CodeTabsheet: TTabSheet;
58 HelpTabsheet: TTabSheet;
59 WebBrowser2: TWebBrowser;
60 OpenDialog1: TOpenDialog;
61 Panel1: TPanel;
62 OpenDialog3: TOpenDialog;
63 SynEdit1: TSynEdit;
64 SynPHPSyn1: TSynPHPSyn;
65 Panel2: TPanel;
66 SynEditFocusTimer: TTimer;
67 Button1: TButton;
68 Button2: TButton;
69 Button3: TButton;
70 Button4: TButton;
71 Button5: TButton;
72 Button6: TButton;
73 ActionList: TActionList;
74 ActionFind: TAction;
75 ActionReplace: TAction;
76 ActionFindNext: TAction;
77 ActionGoto: TAction;
78 ActionSave: TAction;
79 ActionHelp: TAction;
80 ActionRun: TAction;
81 ActionESC: TAction;
82 Button7: TButton;
83 ActionOpen: TAction;
84 Button8: TButton;
85 Button9: TButton;
86 ActionFindPrev: TAction;
87 Timer1: TTimer;
88 ActionSpaceToTab: TAction;
89 Button11: TButton;
90 SynEditSearch1: TSynEditSearch;
91 TreeView1: TTreeView;
92 Splitter2: TSplitter;
93 btnLint: TButton;
94 ActionLint: TAction;
95 ImageList1: TImageList;
96 RunPopup: TPopupMenu;
97 OpeninIDE1: TMenuItem;
98 ActionRunConsole: TAction;
99 Runinconsole1: TMenuItem;
100 SavePopup: TPopupMenu;
101 Saveas1: TMenuItem;
102 Save1: TMenuItem;
103 SaveDialog1: TSaveDialog;
104 BtnSpecialChars: TImage;
105 BtnSpecialCharsOff: TImage;
106 BtnSpecialCharsOn: TImage;
107 BtnLightOn: TImage;
108 BtnLightOff: TImage;
109 BtnLight: TImage;
110 StartUpTimer: TTimer;
111 procedure Run(Sender: TObject);
112 procedure RunConsole(Sender: TObject);
113 procedure FormShow(Sender: TObject);
114 procedure FormCreate(Sender: TObject);
115 procedure FormDestroy(Sender: TObject);
116 procedure FormClose(Sender: TObject; var Action: TCloseAction);
117 procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
118 procedure Memo2DblClick(Sender: TObject);
119 (*
120 {$IFDEF USE_SHDOCVW_TLB}
121 *)
122 procedure WebBrowser1BeforeNavigate2(ASender: TObject;
123 const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
124 Headers: OleVariant; var Cancel: WordBool);
125 (*
126 {$ELSE}
127 procedure WebBrowser1BeforeNavigate2(ASender: TObject;
128 const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
129 Headers: OleVariant; var Cancel: WordBool);
130 {$ENDIF}
131 *)
132 procedure BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
133 procedure SynEditFocusTimerTimer(Sender: TObject);
134 procedure ActionFindExecute(Sender: TObject);
135 procedure ActionReplaceExecute(Sender: TObject);
136 procedure ActionFindNextExecute(Sender: TObject);
137 procedure ActionGotoExecute(Sender: TObject);
138 procedure ActionSaveExecute(Sender: TObject);
139 procedure ActionHelpExecute(Sender: TObject);
140 procedure ActionRunExecute(Sender: TObject);
141 procedure ActionESCExecute(Sender: TObject);
142 procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
143 MousePos: TPoint; var Handled: Boolean);
144 procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
145 MousePos: TPoint; var Handled: Boolean);
146 procedure ActionOpenExecute(Sender: TObject);
147 procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
148 procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
149 procedure ActionFindPrevExecute(Sender: TObject);
150 procedure SynEdit1MouseCursor(Sender: TObject;
151 const aLineCharPos: TBufferCoord; var aCursor: TCursor);
152 procedure Timer1Timer(Sender: TObject);
153 procedure ActionSpaceToTabExecute(Sender: TObject);
154 procedure TreeView1DblClick(Sender: TObject);
155 procedure SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X, Y,
156 Line: Integer; Mark: TSynEditMark);
157 procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
158 TransientType: TTransientType);
159 procedure ActionLintExecute(Sender: TObject);
160 procedure ActionRunConsoleExecute(Sender: TObject);
161 procedure SynEdit1Change(Sender: TObject);
162 procedure Saveas1Click(Sender: TObject);
163 procedure Save1Click(Sender: TObject);
164 procedure BtnSpecialCharsClick(Sender: TObject);
165 procedure WebBrowser1WindowClosing(ASender: TObject;
166 IsChildWindow: WordBool; var Cancel: WordBool);
167 procedure BtnLightClick(Sender: TObject);
168 procedure StartUpTimerTimer(Sender: TObject);
169 private
170 CurSearchTerm: string;
171 HlpPrevPageIndex: integer;
172 SrcRep: TSynEditFindReplace;
173 {$IFDEF OnlineHelp}
174 gOnlineHelpWord: string;
175 {$ENDIF}
176 procedure Help;
177 function MarkUpLineReference(cont: string): string;
178 function InputRequestCallback(var data: AnsiString): boolean;
179 function OutputNotifyCallback(const data: AnsiString): boolean;
180 protected
181 ChmIndex: TMemIniFile;
182 FScrapFile: string;
183 FSaveAsFilename: string;
184 codeExplorer: TRunCodeExplorer;
185 procedure GotoLineNo(LineNo: integer);
186 function GetScrapFile: string;
187 procedure StartCodeExplorer;
188 procedure RefreshModifySign;
189 procedure Theme_Light;
190 procedure Theme_Dark;
191 function IsThemeDark: boolean;
192 end;
193
194 var
195 Form1: TForm1;
196
197 implementation
198
199 {$R *.dfm}
200
201 {$R Cursors.res}
202
203 uses
204 Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI, RichEdit,
205 FastPHPTreeView, ImageListEx, FastPHPConfig;
206
207 const
208 crMouseGutter = 1;
209
210 procedure TForm1.RefreshModifySign;
211 var
212 tmp: string;
213 begin
214 tmp := Caption;
215
216 tmp := StringReplace(tmp, '*', '', [rfReplaceAll]);
217 if SynEdit1.Modified then tmp := tmp + '*';
218
219 if Caption <> tmp then Caption := tmp;
220 end;
221
222 procedure TForm1.ActionFindNextExecute(Sender: TObject);
223 begin
224 SrcRep.FindNext;
225 end;
226
227 procedure TForm1.ActionFindPrevExecute(Sender: TObject);
228 begin
229 SrcRep.FindPrev;
230 end;
231
232 procedure TForm1.ActionGotoExecute(Sender: TObject);
233 var
234 val: string;
235 lineno: integer;
236 begin
237 // TODO: VK_LMENU does not work! only works with AltGr but not Alt
238 // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
239
240 InputQuery('Go to', 'Line number:', val);
241 if not TryStrToInt(val, lineno) then
242 begin
243 if SynEdit1.CanFocus then SynEdit1.SetFocus;
244 exit;
245 end;
246 GotoLineNo(lineno);
247 end;
248
249 procedure TForm1.ActionHelpExecute(Sender: TObject);
250 begin
251 Help;
252 if PageControl2.ActivePage = HelpTabsheet then
253 WebBrowser2.SetFocus
254 else if PageControl2.ActivePage = CodeTabsheet then
255 SynEdit1.SetFocus;
256 end;
257
258 procedure TForm1.ActionLintExecute(Sender: TObject);
259 begin
260 Run(Sender);
261 SynEdit1.SetFocus;
262 end;
263
264 procedure TForm1.ActionOpenExecute(Sender: TObject);
265 begin
266 If OpenDialog3.Execute then
267 begin
268 ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
269 end;
270 end;
271
272 procedure TForm1.ActionReplaceExecute(Sender: TObject);
273 begin
274 SrcRep.ReplaceExecute;
275 end;
276
277 procedure TForm1.ActionRunConsoleExecute(Sender: TObject);
278 begin
279 RunConsole(Sender);
280 SynEdit1.SetFocus;
281 end;
282
283 procedure TForm1.ActionRunExecute(Sender: TObject);
284 begin
285 Run(Sender);
286 SynEdit1.SetFocus;
287 end;
288
289 procedure TForm1.ActionSaveExecute(Sender: TObject);
290 begin
291 SynEdit1.Lines.SaveToFile(GetScrapFile);
292 SynEdit1.Modified := false;
293 RefreshModifySign;
294 end;
295
296 procedure TForm1.ActionSpaceToTabExecute(Sender: TObject);
297
298 function SpacesAtBeginning(line: string): integer;
299 begin
300 result := 0;
301 if Trim(line) = '' then exit;
302 while line[result+1] = ' ' do
303 begin
304 inc(result);
305 end;
306 end;
307
308 function GuessIndent(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): integer;
309 function _Check(indent: integer): boolean;
310 var
311 i: integer;
312 begin
313 result := true;
314 for i := 0 to lines.Count-1 do
315 if SpacesAtBeginning(lines.Strings[i]) mod indent <> 0 then
316 begin
317 // ShowMessageFmt('Zeile "%s" nicht durch %d teilbar!', [lines.strings[i], indent]);
318 result := false;
319 exit;
320 end;
321 end;
322 var
323 i: integer;
324 begin
325 for i := 8 downto 2 do
326 begin
327 if _Check(i) then
328 begin
329 result := i;
330 exit;
331 end;
332 end;
333 result := -1;
334 end;
335
336 procedure SpaceToTab(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}; indent: integer);
337 var
338 i, spaces: integer;
339 begin
340 for i := 0 to lines.Count-1 do
341 begin
342 spaces := SpacesAtBeginning(lines.Strings[i]);
343 lines.Strings[i] := StringOfChar(#9, spaces div indent) + StringOfChar(' ', spaces mod indent) + Copy(lines.Strings[i], spaces+1, Length(lines.Strings[i])-spaces);
344 end;
345 end;
346
347 function SpacesAvailable(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): boolean;
348 var
349 i, spaces: integer;
350 begin
351 for i := 0 to lines.Count-1 do
352 begin
353 spaces := SpacesAtBeginning(lines.Strings[i]);
354 if spaces > 0 then
355 begin
356 result := true;
357 exit;
358 end;
359 end;
360 result := false;
361 exit;
362 end;
363
364 var
365 val: string;
366 ind: integer;
367 resourcestring
368 SNoLinesAvailable = 'No lines with spaces at the beginning available';
369 begin
370 // TODO: if something is selected, only process the selected part
371
372 if not SpacesAvailable(SynEdit1.Lines) then
373 begin
374 MessageDlg(SNoLinesAvailable, mtInformation, [mbOk], 0);
375 exit;
376 end;
377
378 ind := GuessIndent(SynEdit1.Lines);
379 if ind <> -1 then val := IntToStr(ind);
380
381 InputQuery('Spaces to tabs', 'Indent:', val); // TODO: handle CANCEL correctly...
382 if TryStrToInt(Trim(val), ind) then
383 begin
384 if ind = 0 then exit;
385 SpaceToTab(SynEdit1.Lines, ind);
386 end;
387
388 if SynEdit1.CanFocus then SynEdit1.SetFocus;
389 end;
390
391 procedure TForm1.ActionESCExecute(Sender: TObject);
392 begin
393 if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
394 (HelpTabsheet.TabVisible) then
395 begin
396 PageControl2.ActivePageIndex := HlpPrevPageIndex;
397 HelpTabsheet.TabVisible := false;
398 end;
399
400 // Dirty hack...
401 SrcRep.CloseDialogs;
402 end;
403
404 procedure TForm1.ActionFindExecute(Sender: TObject);
405 begin
406 SrcRep.FindExecute;
407 end;
408
409 var
410 firstTimeBrowserLoad: boolean = true;
411 procedure TForm1.Run(Sender: TObject);
412 var
413 bakTS: TTabSheet;
414 ss: TStringStream;
415 bakPos: Int64;
416 begin
417 memo2.Lines.Text := '';
418
419 if firstTimeBrowserLoad then
420 begin
421 bakTS := PageControl1.ActivePage;
422 try
423 PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
424 Webbrowser1.Clear;
425 finally
426 PageControl1.ActivePage := bakTS;
427 end;
428 firstTimeBrowserLoad := false;
429 end
430 else
431 Webbrowser1.Clear;
432
433 Screen.Cursor := crHourGlass;
434 Application.ProcessMessages;
435
436 try
437 ActionSave.Execute; // TODO: if it is not the scrap file: do not save the file, since the user did not intended to save... better create a temporary file and run it instead.
438
439 // TODO 70421 * <fastphp> flush() mittels ContentCallBack implementieren... ich möchte bei langen scripts statusanzeigen realisieren können mit javascript das stück für stück geladen wird !!!!!!!!
440 // TODO 70422 * <fastphp> wenn ein script hängt, soll man es abwürgen dürfen!!!!!!
441 memo2.Lines.Text := RunPHPScript(GetScrapFile, Sender=ActionLint, False);
442
443
444 // Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
445
446 // Alternatively:
447 (*
448 ss := TstringStream.Create;
449 ss.WriteString(MarkUpLineReference(memo2.Lines.Text));
450 ss.Position := 0;
451 Webbrowser1.LoadStream(ss, GetScrapFile);
452 Webbrowser1.Wait;
453 ss.Free;
454 *)
455
456 if IsTextHTML(memo2.lines.text) then
457 PageControl1.ActivePage := HtmlTabSheet
458 else
459 PageControl1.ActivePage := PlaintextTabSheet;
460 finally
461 Screen.Cursor := crDefault;
462 end;
463 end;
464
465 procedure TForm1.RunConsole(Sender: TObject);
466 begin
467 ActionSave.Execute; // TODO: if it is not the scrap file: do not save the file, since the user did not intended to save... better create a temporary file and run it instead.
468 RunPHPScript(GetScrapFile, Sender=ActionLint, True);
469 end;
470
471 procedure TForm1.SynEdit1Change(Sender: TObject);
472 begin
473 RefreshModifySign;
474 end;
475
476 procedure TForm1.SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X,
477 Y, Line: Integer; Mark: TSynEditMark);
478 begin
479 (*
480 TSynEdit(Sender).CaretX := 1;
481 TSynEdit(Sender).CaretY := Line;
482 TSynEdit(Sender).SelLength := Length(TSynEdit(Sender).LineText);
483 *)
484 end;
485
486 procedure TForm1.SynEdit1MouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; var aCursor: TCursor);
487 {$IFDEF OnlineHelp}
488 var
489 Line: Integer;
490 Column: Integer;
491 word: string;
492 begin
493 Line := aLineCharPos.Line-1;
494 Column := aLineCharPos.Char-1;
495 word := GetWordUnderPos(TSynEdit(Sender), Line, Column);
496 if word <> gOnlineHelpWord then
497 begin
498 gOnlineHelpWord := word;
499 Timer1.Enabled := false;
500 Timer1.Enabled := true;
501 end;
502 {$ELSE}
503 begin
504 {$ENDIF}
505 end;
506
507 procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
508 MousePos: TPoint; var Handled: Boolean);
509 begin
510 if ssCtrl in Shift then
511 begin
512 SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
513 Handled := true;
514 end
515 else Handled := false;
516 end;
517
518 procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
519 MousePos: TPoint; var Handled: Boolean);
520 begin
521 if ssCtrl in Shift then
522 begin
523 SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
524 Handled := true;
525 end
526 else Handled := false;
527 end;
528
529 procedure TForm1.SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
530 var
531 Editor: TSynEdit;
532 OpenChars: array of WideChar;//[0..2] of WideChar=();
533 CloseChars: array of WideChar;//[0..2] of WideChar=();
534
535 function IsCharBracket(AChar: WideChar): Boolean;
536 begin
537 case AChar of
538 '{','[','(','<','}',']',')','>':
539 Result := True;
540 else
541 Result := False;
542 end;
543 end;
544
545 function CharToPixels(P: TBufferCoord): TPoint;
546 begin
547 Result := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
548 end;
549
550 var
551 COLOR_FG: TColor;
552 COLOR_BG: TColor;
553 P: TBufferCoord;
554 Pix: TPoint;
555 D: TDisplayCoord;
556 S: UnicodeString;
557 I: Integer;
558 Attri: TSynHighlighterAttributes;
559 ArrayLength: Integer;
560 start: Integer;
561 TmpCharA, TmpCharB: WideChar;
562 begin
563 // Source: https://github.com/SynEdit/SynEdit/blob/master/Demos/OnPaintTransientDemo/Unit1.pas
564
565 if IsThemeDark then
566 begin
567 COLOR_FG := clLime;
568 COLOR_BG := clGreen;
569 end
570 else
571 begin
572 COLOR_FG := clGreen;
573 COLOR_BG := clLime;
574 end;
575
576 if TSynEdit(Sender).SelAvail then exit;
577 Editor := TSynEdit(Sender);
578 ArrayLength:= 3;
579
580 (*
581 if (Editor.Highlighter = shHTML) or (Editor.Highlighter = shXML) then
582 inc(ArrayLength);
583 *)
584
585 SetLength(OpenChars, ArrayLength);
586 SetLength(CloseChars, ArrayLength);
587 for i := 0 to ArrayLength - 1 do
588 begin
589 case i of
590 0: begin OpenChars[i] := '('; CloseChars[i] := ')'; end;
591 1: begin OpenChars[i] := '{'; CloseChars[i] := '}'; end;
592 2: begin OpenChars[i] := '['; CloseChars[i] := ']'; end;
593 3: begin OpenChars[i] := '<'; CloseChars[i] := '>'; end;
594 end;
595 end;
596
597 P := Editor.CaretXY;
598 D := Editor.DisplayXY;
599
600 Start := Editor.SelStart;
601
602 if (Start > 0) and (Start <= length(Editor.Text)) then
603 TmpCharA := Editor.Text[Start]
604 else
605 TmpCharA := #0;
606
607 if (Start > 0){Added by VTS} and (Start < length(Editor.Text)) then
608 TmpCharB := Editor.Text[Start + 1]
609 else
610 TmpCharB := #0;
611
612 if not IsCharBracket(TmpCharA) and not IsCharBracket(TmpCharB) then exit;
613 S := TmpCharB;
614 if not IsCharBracket(TmpCharB) then
615 begin
616 P.Char := P.Char - 1;
617 S := TmpCharA;
618 end;
619 Editor.GetHighlighterAttriAtRowCol(P, S, Attri);
620
621 if (Editor.Highlighter.SymbolAttribute = Attri) then
622 begin
623 for i := low(OpenChars) to High(OpenChars) do
624 begin
625 if (S = OpenChars[i]) or (S = CloseChars[i]) then
626 begin
627 Pix := CharToPixels(P);
628
629 Editor.Canvas.Brush.Style := bsSolid;//Clear;
630 Editor.Canvas.Font.Assign(Editor.Font);
631 Editor.Canvas.Font.Style := Attri.Style;
632
633 if (TransientType = ttAfter) then
634 begin
635 Editor.Canvas.Font.Color := COLOR_FG;
636 Editor.Canvas.Brush.Color := COLOR_BG;
637 end
638 else
639 begin
640 Editor.Canvas.Font.Color := Attri.Foreground;
641 Editor.Canvas.Brush.Color := Attri.Background;
642 end;
643 if Editor.Canvas.Font.Color = clNone then
644 Editor.Canvas.Font.Color := Editor.Font.Color;
645 if Editor.Canvas.Brush.Color = clNone then
646 Editor.Canvas.Brush.Color := Editor.Color;
647
648 Editor.Canvas.TextOut(Pix.X, Pix.Y, S);
649 P := Editor.GetMatchingBracketEx(P);
650
651 if (P.Char > 0) and (P.Line > 0) then
652 begin
653 Pix := CharToPixels(P);
654 if Pix.X > Editor.Gutter.Width then
655 begin
656 {$REGION 'Added by ViaThinkSoft'}
657 if (TransientType = ttAfter) then
658 begin
659 Editor.Canvas.Font.Color := COLOR_FG;
660 Editor.Canvas.Brush.Color := COLOR_BG;
661 end
662 else
663 begin
664 Editor.Canvas.Font.Color := Attri.Foreground;
665 Editor.Canvas.Brush.Color := Attri.Background;
666 end;
667 if Editor.Canvas.Font.Color = clNone then
668 Editor.Canvas.Font.Color := Editor.Font.Color;
669 if Editor.Canvas.Brush.Color = clNone then
670 Editor.Canvas.Brush.Color := Editor.Color;
671 {$ENDREGION}
672 if S = OpenChars[i] then
673 Editor.Canvas.TextOut(Pix.X, Pix.Y, CloseChars[i])
674 else Editor.Canvas.TextOut(Pix.X, Pix.Y, OpenChars[i]);
675 end;
676 end;
677 end;
678 end;
679 Editor.Canvas.Brush.Style := bsSolid;
680 end;
681 end;
682
683 procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
684 begin
685 SynEditFocusTimer.Enabled := false;
686 Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
687 SynEdit1.SetFocus;
688 end;
689
690 procedure TForm1.Theme_Dark;
691 begin
692 if IsThemeDark then exit;
693 TStyleManager.TrySetStyle('Windows10 SlateGray');
694 Color := 1316887;
695 Font.Color := clCream;
696 //Memo2.Font.Color := clCream;
697 //Memo2.ParentColor := true;
698 SynEdit1.ActiveLineColor := 2238502;
699 SynEdit1.Color := 1316887;
700 SynEdit1.Font.Color := clCream;
701 SynEdit1.Gutter.Color := 1316887;
702 SynEdit1.Gutter.Font.Color := clCream;
703 SynEdit1.Gutter.GradientStartColor := 2238502;
704 SynEdit1.Gutter.GradientEndColor := 1316887;
705 SynPHPSyn1.CommentAttri.Foreground := $00837B82;
706 SynPHPSyn1.IdentifierAttri.Foreground := 9627120;
707 SynPHPSyn1.KeyAttri.Foreground := 4157595;
708 SynPHPSyn1.NumberAttri.Foreground := 5008079;
709 SynPHPSyn1.StringAttri.Foreground := 6987151;
710 SynPHPSyn1.SymbolAttri.Foreground := 8769754;
711 SynPHPSyn1.VariableAttri.Foreground := 6924493;
712 end;
713
714 procedure TForm1.Theme_Light;
715 begin
716 if not IsThemeDark then exit;
717 TStyleManager.TrySetStyle('Windows');
718 Color := clBtnFace;
719 Font.Color := clWindowText;
720 //Memo2.Font.Color := clWindowText;
721 SynEdit1.ActiveLineColor := 14680010;
722 SynEdit1.Color := clWindow;
723 SynEdit1.Font.Color := clWindowText;
724 SynEdit1.Gutter.Color := clBtnFace;
725 SynEdit1.Gutter.Font.Color := clWindowText;
726 SynEdit1.Gutter.GradientStartcolor := cl3dLight;
727 SynEdit1.Gutter.GradientEndColor := clBtnFace;;
728 SynPHPSyn1.CommentAttri.Foreground := 33023;
729 SynPHPSyn1.IdentifierAttri.Foreground := 4194304;
730 SynPHPSyn1.KeyAttri.Foreground := 4227072;
731 SynPHPSyn1.NumberAttri.Foreground := 213;
732 SynPHPSyn1.StringAttri.Foreground := 13762560;
733 SynPHPSyn1.SymbolAttri.Foreground := 4227072;
734 SynPHPSyn1.VariableAttri.Foreground := 213;
735 end;
736
737 procedure TForm1.Timer1Timer(Sender: TObject);
738 begin
739 {$IFDEF OnlineHelp}
740 Timer1.Enabled := false;
741
742 // TODO: Insert a small online help hint
743 //Caption := gOnlineHelpWord;
744 {$ENDIF}
745 end;
746
747 procedure TForm1.TreeView1DblClick(Sender: TObject);
748 var
749 tn: TTreeNode;
750 lineNo: integer;
751 begin
752 tn := TTreeView(Sender).Selected;
753 if tn = nil then exit;
754 lineNo := Integer(tn.Data);
755 if lineNo > 0 then GotoLineNo(lineNo);
756 end;
757
758 (*
759 {$IFDEF USE_SHDOCVW_TLB}
760 *)
761 procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
762 const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
763 Headers: OleVariant; var Cancel: WordBool);
764 begin
765 BeforeNavigate(URL, Cancel);
766 end;
767 procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
768 IsChildWindow: WordBool; var Cancel: WordBool);
769 resourcestring
770 LNG_CLOSE_REQUEST = 'A script has requested the window to be closed. The window of a standalone script would now close.';
771 begin
772 ShowMessage(LNG_CLOSE_REQUEST);
773 TWebBrowser(ASender).Clear;
774 Cancel := true;
775 end;
776
777 (*
778 {$ELSE}
779 procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
780 const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
781 Headers: OleVariant; var Cancel: WordBool);
782 begin
783 BeforeNavigate(URL, Cancel);
784 end;
785 {$ENDIF}
786 *)
787
788 procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
789 var
790 s, myURL: string;
791 lineno: integer;
792 p: integer;
793 begin
794 {$REGION 'Line number references (PHP errors and warnings)'}
795 if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
796 begin
797 try
798 s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
799 if not TryStrToInt(s, lineno) then exit;
800 GotoLineNo(lineno);
801 SynEditFocusTimer.Enabled := true;
802 finally
803 Cancel := true;
804 end;
805 Exit;
806 end;
807 {$ENDREGION}
808
809 {$REGION 'Intelligent browser (executes PHP scripts which are clicked in a hyperlink)'}
810 if URL <> 'about:blank' then
811 begin
812 myUrl := URL;
813
814 p := Pos('?', myUrl);
815 if p >= 1 then myURL := copy(myURL, 1, p-1);
816
817 // TODO: myURL urldecode
818 // TODO: maybe we could even open that file in the editor!
819 // TODO: ?parameter=....
820
821 if FileExists(myURL) and (EndsText('.php', myURL) or EndsText('.php3', myURL) or EndsText('.php4', myURL) or EndsText('.php5', myURL) or EndsText('.phps', myURL)) then
822 begin
823 WebBrowser1.LoadHTML(RunPHPScript(myURL), myUrl);
824 Cancel := true;
825 end;
826 end;
827 {$ENDREGION}
828 end;
829
830 procedure TForm1.BtnLightClick(Sender: TObject);
831 var
832 CanClose: boolean;
833 begin
834 FormCloseQuery(Form1, CanClose);
835 if not CanClose then exit;
836
837 if IsThemeDark then
838 begin
839 BtnLight.Picture.Assign(BtnLightOn.Picture);
840 Theme_Light;
841 TFastPHPConfig.DarkTheme := false;
842 end
843 else
844 begin
845 BtnLight.Picture.Assign(BtnLightOff.Picture);
846 Theme_Dark;
847 TFastPHPConfig.DarkTheme := true;
848 end;
849 end;
850
851 procedure TForm1.BtnSpecialCharsClick(Sender: TObject);
852 var
853 opts: TSynEditorOptions;
854 begin
855 opts := SynEdit1.Options;
856 if eoShowSpecialChars in SynEdit1.Options then
857 begin
858 BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
859 Exclude(opts, eoShowSpecialChars);
860 TFastPHPConfig.SpecialChars := false;
861 end
862 else
863 begin
864 BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
865 Include(opts, eoShowSpecialChars);
866 TFastPHPConfig.SpecialChars := true;
867 end;
868 SynEdit1.Options := opts;
869 end;
870
871 procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
872 begin
873 TFastPHPConfig.FontSize := SynEdit1.Font.Size;
874 end;
875
876 procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
877 var
878 r: integer;
879 begin
880 if SynEdit1.Modified then
881 begin
882 if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
883 begin
884 r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
885 if r = mrCancel then
886 begin
887 CanClose := false;
888 Exit;
889 end
890 else if r = mrYes then
891 begin
892 ActionSave.Execute;
893 CanClose := true;
894 end;
895 end
896 else
897 begin
898 ActionSave.Execute;
899 CanClose := true;
900 end;
901 end;
902 end;
903
904 procedure TForm1.FormCreate(Sender: TObject);
905 var
906 exeDir: string;
907 begin
908 HlpPrevPageIndex := -1;
909 CurSearchTerm := '';
910 Caption := Caption + ' - ' + GetScrapFile;
911 SrcRep := TSynEditFindReplace.Create(self);
912 SrcRep.Editor := SynEdit1;
913 SynEdit1.Gutter.Gradient := HighColorWindows;
914
915 Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
916 SynEdit1.Gutter.Cursor := crMouseGutter;
917
918 exeDir := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
919 if FileExists(exeDir + 'codeexplorer.bmp') then ImageList1.LoadAndSplitImages(exeDir + 'codeexplorer.bmp');
920 end;
921
922 procedure TForm1.FormDestroy(Sender: TObject);
923 begin
924 if Assigned(ChmIndex) then
925 begin
926 FreeAndNil(ChmIndex);
927 end;
928 FreeAndNil(SrcRep);
929
930 if Assigned(codeExplorer) then
931 begin
932 codeExplorer.Terminate;
933 codeExplorer.WaitFor;
934 FreeAndNil(codeExplorer);
935 end;
936 end;
937
938 procedure TForm1.FormShow(Sender: TObject);
939 var
940 ScrapFile: string;
941 tmpFontSize: integer;
942 opts: TSynEditorOptions;
943 begin
944 ScrapFile := GetScrapFile;
945 if ScrapFile = '' then
946 begin
947 Application.Terminate; // Close;
948 exit;
949 end;
950
951 opts := SynEdit1.Options;
952 if TFastPHPConfig.SpecialChars then
953 begin
954 BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
955 Include(opts, eoShowSpecialChars);
956 end
957 else
958 begin
959 BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
960 Exclude(opts, eoShowSpecialChars);
961 end;
962 SynEdit1.Options := opts;
963
964 if FileExists(ScrapFile) then
965 SynEdit1.Lines.LoadFromFile(ScrapFile)
966 else
967 SynEdit1.Lines.Clear;
968
969 PageControl1.ActivePage := PlaintextTabSheet;
970
971 PageControl2.ActivePage := CodeTabsheet;
972 HelpTabsheet.TabVisible := false;
973
974 tmpFontSize := TFastPHPConfig.FontSize;
975 if tmpFontSize <> -1 then SynEdit1.Font.Size := tmpFontSize;
976 SynEdit1.SetFocus;
977
978 DoubleBuffered := true;
979 StartCodeExplorer;
980
981 StartupTimer.Enabled := true;
982 end;
983
984 procedure TForm1.Save1Click(Sender: TObject);
985 begin
986 Button7.Click;
987 end;
988
989 procedure TForm1.Saveas1Click(Sender: TObject);
990 begin
991 if SaveDialog1.Execute then
992 begin
993 FSaveAsFilename := SaveDialog1.FileName;
994 Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
995 Button7.Click;
996 end;
997 end;
998
999 procedure TForm1.StartCodeExplorer;
1000 begin
1001 codeExplorer := TRunCodeExplorer.Create(true);
1002 codeExplorer.InputRequestCallback := InputRequestCallback;
1003 codeExplorer.OutputNotifyCallback := OutputNotifyCallback;
1004 codeExplorer.PhpExe := GetPHPExe;
1005 codeExplorer.PhpFile := IncludeTrailingPathDelimiter(ExtractFileDir(Application.ExeName)) + 'codeexplorer.php'; // GetScrapFile;
1006 codeExplorer.WorkDir := ExtractFileDir(Application.ExeName);
1007 codeExplorer.Resume;
1008 end;
1009
1010 procedure TForm1.StartUpTimerTimer(Sender: TObject);
1011 begin
1012 StartupTimer.Enabled := false;
1013
1014 // We need this timer because we cannot change the Theme during OnShow,
1015 // because the Delphi VCL Theme is buggy!
1016
1017 if TFastPHPConfig.DarkTheme then
1018 begin
1019 BtnLight.Picture.Assign(BtnLightOff.Picture);
1020 Theme_Dark;
1021 end
1022 else
1023 begin
1024 BtnLight.Picture.Assign(BtnLightOn.Picture);
1025 Theme_Light;
1026 end;
1027 end;
1028
1029 function TForm1.GetScrapFile: string;
1030 var
1031 tmpPath: string;
1032 begin
1033 if FSaveAsFilename <> '' then
1034 begin
1035 result := FSaveAsFilename;
1036 exit;
1037 end;
1038
1039 if FScrapFile <> '' then
1040 begin
1041 result := FScrapFile;
1042 exit;
1043 end;
1044
1045 if ParamStr(1) <> '' then
1046 begin
1047 // Program was started with a filename
1048
1049 result := ParamStr(1);
1050
1051 if not FileExists(result) then
1052 begin
1053 case MessageDlg(Format('File %s does not exist. Create it?', [result]), mtConfirmation, mbYesNoCancel, 0) of
1054 mrYes:
1055 try
1056 SynEdit1.Lines.SaveToFile(result);
1057 except
1058 on E: Exception do
1059 begin
1060 MessageDlg(E.Message, mtError, [mbOk], 0);
1061 Application.Terminate;
1062 result := '';
1063 exit;
1064 end;
1065 end;
1066 mrNo:
1067 begin
1068 Application.Terminate;
1069 result := '';
1070 exit;
1071 end;
1072 mrCancel:
1073 begin
1074 Application.Terminate;
1075 result := '';
1076 exit;
1077 end;
1078 end;
1079 end;
1080 end
1081 else
1082 begin
1083 // Program is started without filename -> use scrap file
1084
1085 result := TFastPHPConfig.ScrapFile;
1086
1087 if not FileExists(result) then
1088 begin
1089 repeat
1090 {$REGION 'Determinate opendialog initial directory'}
1091 if result <> '' then
1092 begin
1093 tmpPath := ExtractFilePath(result);
1094 if DirectoryExists(tmpPath) then
1095 begin
1096 OpenDialog3.InitialDir := tmpPath;
1097 OpenDialog3.FileName := Result;
1098 end
1099 else
1100 begin
1101 OpenDialog3.InitialDir := GetMyDocumentsFolder;
1102 end;
1103 end
1104 else
1105 begin
1106 OpenDialog3.InitialDir := GetMyDocumentsFolder;
1107 end;
1108 {$ENDREGION}
1109
1110 if not OpenDialog3.Execute then
1111 begin
1112 Application.Terminate;
1113 result := '';
1114 exit;
1115 end;
1116
1117 if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1118 begin
1119 MessageDlg('Path does not exist! Please try again.', mtWarning, [mbOk], 0);
1120 end
1121 else
1122 begin
1123 result := OpenDialog3.FileName;
1124 end;
1125 until result <> '';
1126
1127 if not FileExists(result) then
1128 begin
1129 try
1130 // Try saving the file; check if we have permissions
1131 //SynEdit1.Lines.Clear;
1132 SynEdit1.Lines.SaveToFile(result);
1133 except
1134 on E: Exception do
1135 begin
1136 MessageDlg(E.Message, mtError, [mbOk], 0);
1137 Application.Terminate;
1138 result := '';
1139 exit;
1140 end;
1141 end;
1142 end;
1143
1144 TFastPHPConfig.ScrapFile := result;
1145 FScrapFile := result;
1146 end;
1147 end;
1148 end;
1149
1150 procedure TForm1.Help;
1151 var
1152 IndexFile, chmFile, w, OriginalWord, url: string;
1153 internalHtmlFile: string;
1154 begin
1155 if not Assigned(ChmIndex) then
1156 begin
1157 IndexFile := TFastPHPConfig.HelpIndex;
1158 IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
1159 if FileExists(IndexFile) then
1160 begin
1161 ChmIndex := TMemIniFile.Create(IndexFile);
1162 end;
1163 end;
1164
1165 if Assigned(ChmIndex) then
1166 begin
1167 IndexFile := TFastPHPConfig.HelpIndex;
1168 // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
1169
1170 chmFile := ChangeFileExt(IndexFile, '.chm');
1171 if not FileExists(chmFile) then
1172 begin
1173 FreeAndNil(ChmIndex);
1174 end;
1175 end;
1176
1177 if not Assigned(ChmIndex) then
1178 begin
1179 if not OpenDialog1.Execute then exit;
1180
1181 chmFile := OpenDialog1.FileName;
1182 if not FileExists(chmFile) then exit;
1183
1184 IndexFile := ChangeFileExt(chmFile, '.ini');
1185
1186 if not FileExists(IndexFile) then
1187 begin
1188 Panel1.Align := alClient;
1189 Panel1.Visible := true;
1190 Panel1.BringToFront;
1191 Screen.Cursor := crHourGlass;
1192 Application.ProcessMessages;
1193 try
1194 if not ParseCHM(chmFile) then
1195 begin
1196 MessageDlg('The CHM file is not a valid PHP documentation. Cannot use help.', mtError, [mbOk], 0);
1197 exit;
1198 end;
1199 finally
1200 Screen.Cursor := crDefault;
1201 Panel1.Visible := false;
1202 end;
1203
1204 if not FileExists(IndexFile) then
1205 begin
1206 MessageDlg('Unknown error. Cannot use help.', mtError, [mbOk], 0);
1207 exit;
1208 end;
1209 end;
1210
1211 TFastPHPConfig.HelpIndex := IndexFile;
1212
1213 ChmIndex := TMemIniFile.Create(IndexFile);
1214 end;
1215
1216 w := GetWordUnderCaret(SynEdit1);
1217 if w = '' then exit;
1218 {$IFDEF UNICODE}
1219 if CharInSet(w[1], ['0'..'9']) then exit;
1220 {$ELSE}
1221 if w[1] in ['0'..'9'] then exit;
1222 {$ENDIF}
1223
1224 Originalword := w;
1225 // w := StringReplace(w, '_', '-', [rfReplaceAll]);
1226 w := LowerCase(w);
1227 CurSearchTerm := w;
1228
1229 internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
1230 if internalHtmlFile = '' then
1231 begin
1232 HelpTabsheet.TabVisible := false;
1233 HlpPrevPageIndex := -1;
1234 ShowMessageFmt('No help for "%s" available', [Originalword]);
1235 Exit;
1236 end;
1237
1238 url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1239
1240 HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
1241 HelpTabsheet.TabVisible := true;
1242 PageControl2.ActivePage := HelpTabsheet;
1243 WebBrowser2.Navigate(url);
1244 WebBrowser2.Wait;
1245 end;
1246
1247 procedure TForm1.GotoLineNo(LineNo:integer);
1248 var
1249 line: string;
1250 i: integer;
1251 begin
1252 SynEdit1.GotoLineAndCenter(LineNo);
1253
1254 // Skip indent
1255 line := SynEdit1.Lines[SynEdit1.CaretY];
1256 for i := 1 to Length(line) do
1257 begin
1258 {$IFDEF UNICODE}
1259 if not CharInSet(line[i], [' ', #9]) then
1260 {$ELSE}
1261 if not (line[i] in [' ', #9]) then
1262 {$ENDIF}
1263 begin
1264 SynEdit1.CaretX := i-1;
1265 break;
1266 end;
1267 end;
1268
1269 PageControl2.ActivePage := CodeTabsheet;
1270 if SynEdit1.CanFocus then SynEdit1.SetFocus;
1271 end;
1272
1273 procedure TForm1.PageControl2Changing(Sender: TObject;
1274 var AllowChange: Boolean);
1275 begin
1276 if PageControl2.ActivePage = HelpTabsheet then
1277 HlpPrevPageIndex := -1
1278 else
1279 HlpPrevPageIndex := PageControl2.ActivePageIndex;
1280
1281 AllowChange := true;
1282 end;
1283
1284 procedure TForm1.Memo2DblClick(Sender: TObject);
1285 var
1286 line: string;
1287
1288 procedure _process(toFind: string);
1289 var
1290 p, lineno: integer;
1291 begin
1292 if FileSystemCaseSensitive then
1293 p := Pos(toFind, line)
1294 else
1295 p := Pos(LowerCase(toFind), LowerCase(line));
1296 if p <> 0 then
1297 begin
1298 line := copy(line, p+length(toFind), 99);
1299 if not TryStrToInt(line, lineno) then exit;
1300 GotoLineNo(lineno);
1301 end;
1302 end;
1303
1304 begin
1305 line := memo2.Lines.Strings[Memo2.CaretPos.Y];
1306
1307 {$REGION 'Possibility 1: filename.php:lineno'}
1308 _process(ExtractFileName(GetScrapFile) + ':');
1309 {$ENDREGION}
1310
1311 {$REGION 'Possibility 2: on line xx'}
1312 _process(ExtractFileName(GetScrapFile) + ' on line ');
1313 {$ENDREGION}
1314 end;
1315
1316 procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1317 Shift: TShiftState);
1318 begin
1319 if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
1320 end;
1321
1322 function TForm1.MarkUpLineReference(cont: string): string;
1323
1324 procedure _process(toFind: string);
1325 var
1326 p, a, b: integer;
1327 num: integer;
1328 insert_a, insert_b: string;
1329 begin
1330 if FileSystemCaseSensitive then
1331 p := Pos(toFind, cont)
1332 else
1333 p := Pos(LowerCase(toFind), LowerCase(cont));
1334 while p >= 1 do
1335 begin
1336 a := p;
1337 b := p + length(toFind);
1338 num := 0;
1339 {$IFDEF UNICODE}
1340 while CharInSet(cont[b], ['0'..'9']) do
1341 {$ELSE}
1342 while cont[b] in ['0'..'9'] do
1343 {$ENDIF}
1344 begin
1345 num := num*10 + StrToInt(cont[b]);
1346 inc(b);
1347 end;
1348
1349 insert_b := '</a>';
1350 insert_a := '<a href="' + FASTPHP_GOTO_URI_PREFIX + IntToStr(num) + '">';
1351
1352 insert(insert_b, cont, b);
1353 insert(insert_a, cont, a);
1354
1355 p := b + Length(insert_a) + Length(insert_b);
1356
1357 p := PosEx(toFind, cont, p+1);
1358 end;
1359 end;
1360
1361 begin
1362 {$REGION 'Possibility 1: filename.php:lineno'}
1363 _process(ExtractFileName(GetScrapFile) + ':');
1364 {$ENDREGION}
1365
1366 {$REGION 'Possibility 2: on line xx'}
1367 _process(ExtractFileName(GetScrapFile) + ' on line ');
1368 {$ENDREGION}
1369
1370 result := cont;
1371 end;
1372
1373 function TForm1.InputRequestCallback(var data: AnsiString): boolean;
1374 begin
1375 data := UTF8Encode(SynEdit1.Text);
1376 result := true;
1377 end;
1378
1379 function TForm1.IsThemeDark: boolean;
1380 begin
1381 result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1382 end;
1383
1384 function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
1385 begin
1386 result := TreeView1.FillWithFastPHPData(data);
1387 end;
1388
1389 end.