Subversion Repositories fastphp

Rev

Rev 93 | Rev 96 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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