Subversion Repositories fastphp

Rev

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