Subversion Repositories fastphp

Rev

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

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