Subversion Repositories fastphp

Rev

Rev 18 | Rev 20 | 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
 
4 daniel-mar 3
(*
4
  This program requires
5
  - Microsoft Internet Controls (TWebBrowser)
6
    If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
7
    "Microsoft Internet Controls"
8
  - SynEdit
9
    You can obtain SynEdit via Embarcadero GetIt
10
*)
11
 
2 daniel-mar 12
// TODO: localize
13
// TODO: wieso geht copy paste im twebbrowser nicht???
14
// Wieso dauert webbrowser1 erste kompilierung so lange???
5 daniel-mar 15
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
16
// TODO: Browser titlebar (link preview)
2 daniel-mar 17
 
18
// Future ideas
19
// - ToDo list
20
// - verschiedene php versionen?
21
// - webbrowser1 nur laden, wenn man den tab anwählt?
22
// - doppelklick auf tab soll diesen schließen
5 daniel-mar 23
// - Onlinehelp (www) aufrufen
13 daniel-mar 24
// - Let all colors be adjustable
25
// - code in bildschirmmitte?
2 daniel-mar 26
 
27
interface
28
 
29
uses
30
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
4 daniel-mar 31
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
13 daniel-mar 32
  SynEditHighlighter, SynHighlighterPHP, SynEdit, SHDocVw_TLB, FindReplace,
33
  System.Actions, Vcl.ActnList;
2 daniel-mar 34
 
35
type
36
  TForm1 = class(TForm)
37
    PageControl1: TPageControl;
38
    PlaintextTabSheet: TTabSheet;
39
    HtmlTabSheet: TTabSheet;
40
    Memo2: TMemo;
41
    WebBrowser1: TWebBrowser;
42
    Splitter1: TSplitter;
43
    PageControl2: TPageControl;
44
    TabSheet3: TTabSheet;
45
    HelpTabsheet: TTabSheet;
46
    WebBrowser2: TWebBrowser;
47
    OpenDialog1: TOpenDialog;
48
    Panel1: TPanel;
49
    OpenDialog3: TOpenDialog;
4 daniel-mar 50
    SynEdit1: TSynEdit;
51
    SynPHPSyn1: TSynPHPSyn;
5 daniel-mar 52
    Panel2: TPanel;
53
    SynEditFocusTimer: TTimer;
54
    Button1: TButton;
55
    Button2: TButton;
56
    Button3: TButton;
13 daniel-mar 57
    Button4: TButton;
58
    Button5: TButton;
59
    Button6: TButton;
60
    ActionList: TActionList;
61
    ActionFind: TAction;
62
    ActionReplace: TAction;
63
    ActionFindNext: TAction;
64
    ActionGoto: TAction;
65
    ActionSave: TAction;
66
    ActionHelp: TAction;
67
    ActionRun: TAction;
68
    ActionESC: TAction;
69
    Button7: TButton;
15 daniel-mar 70
    ActionOpen: TAction;
71
    Button8: TButton;
2 daniel-mar 72
    procedure Run(Sender: TObject);
73
    procedure FormShow(Sender: TObject);
74
    procedure FormCreate(Sender: TObject);
75
    procedure FormDestroy(Sender: TObject);
76
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
77
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
5 daniel-mar 78
    procedure Memo2DblClick(Sender: TObject);
79
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
80
      const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
81
      Headers: OleVariant; var Cancel: WordBool);
82
    procedure SynEditFocusTimerTimer(Sender: TObject);
13 daniel-mar 83
    procedure ActionFindExecute(Sender: TObject);
84
    procedure ActionReplaceExecute(Sender: TObject);
85
    procedure ActionFindNextExecute(Sender: TObject);
86
    procedure ActionGotoExecute(Sender: TObject);
87
    procedure ActionSaveExecute(Sender: TObject);
88
    procedure ActionHelpExecute(Sender: TObject);
89
    procedure ActionRunExecute(Sender: TObject);
90
    procedure ActionESCExecute(Sender: TObject);
91
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
92
      MousePos: TPoint; var Handled: Boolean);
93
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
94
      MousePos: TPoint; var Handled: Boolean);
15 daniel-mar 95
    procedure ActionOpenExecute(Sender: TObject);
96
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
17 daniel-mar 97
    procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
2 daniel-mar 98
  private
99
    CurSearchTerm: string;
100
    HlpPrevPageIndex: integer;
13 daniel-mar 101
    SrcRep: TFindReplace;
2 daniel-mar 102
    procedure Help;
5 daniel-mar 103
    function MarkUpLineReference(cont: string): string;
2 daniel-mar 104
  protected
105
    ChmIndex: TMemIniFile;
19 daniel-mar 106
    FScrapFile: string;
5 daniel-mar 107
    procedure GotoLineNo(LineNo:integer);
2 daniel-mar 108
    function GetScrapFile: string;
109
  end;
110
 
111
var
112
  Form1: TForm1;
113
 
114
implementation
115
 
116
{$R *.dfm}
117
 
118
uses
15 daniel-mar 119
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI;
2 daniel-mar 120
 
13 daniel-mar 121
// TODO: FindPrev ?
122
procedure TForm1.ActionFindNextExecute(Sender: TObject);
123
begin
124
  SrcRep.FindNext;
125
end;
126
 
127
procedure TForm1.ActionGotoExecute(Sender: TObject);
5 daniel-mar 128
var
129
  val: string;
130
  lineno: integer;
131
begin
13 daniel-mar 132
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
133
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
5 daniel-mar 134
 
13 daniel-mar 135
  InputQuery('Go to', 'Line number:', val);
136
  if not TryStrToInt(val, lineno) then
137
  begin
138
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
139
    exit;
140
  end;
141
  GotoLineNo(lineno);
142
end;
5 daniel-mar 143
 
13 daniel-mar 144
procedure TForm1.ActionHelpExecute(Sender: TObject);
145
begin
146
  Help;
147
  if PageControl2.ActivePage = HelpTabsheet then
148
    WebBrowser2.SetFocus
149
  else if PageControl2.ActivePage = TabSheet3{Scrap} then
150
    SynEdit1.SetFocus;
151
end;
8 daniel-mar 152
 
15 daniel-mar 153
procedure TForm1.ActionOpenExecute(Sender: TObject);
154
begin
155
  If OpenDialog3.Execute then
156
  begin
157
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar(OpenDialog3.FileName), '', SW_NORMAL);
158
  end;
159
end;
160
 
13 daniel-mar 161
procedure TForm1.ActionReplaceExecute(Sender: TObject);
162
begin
163
  SrcRep.ReplaceExecute;
164
end;
5 daniel-mar 165
 
13 daniel-mar 166
procedure TForm1.ActionRunExecute(Sender: TObject);
167
begin
168
  Run(Sender);
169
  SynEdit1.SetFocus;
170
end;
5 daniel-mar 171
 
13 daniel-mar 172
procedure TForm1.ActionSaveExecute(Sender: TObject);
173
begin
174
  SynEdit1.Lines.SaveToFile(GetScrapFile);
16 daniel-mar 175
  SynEdit1.Modified := false;
13 daniel-mar 176
end;
177
 
178
procedure TForm1.ActionESCExecute(Sender: TObject);
179
begin
180
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
181
     (HelpTabsheet.TabVisible) then
182
  begin
183
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
184
    HelpTabsheet.TabVisible := false;
2 daniel-mar 185
  end;
13 daniel-mar 186
 
187
  // Dirty hack...
188
  SrcRep._FindDialog.CloseDialog;
189
  SrcRep._ReplaceDialog.CloseDialog;
2 daniel-mar 190
end;
191
 
13 daniel-mar 192
procedure TForm1.ActionFindExecute(Sender: TObject);
193
begin
194
  SrcRep.FindExecute;
195
end;
196
 
16 daniel-mar 197
var
198
  firstTimeBrowserLoad: boolean = true;
2 daniel-mar 199
procedure TForm1.Run(Sender: TObject);
16 daniel-mar 200
var
201
  bakTS: TTabSheet;
2 daniel-mar 202
begin
5 daniel-mar 203
  memo2.Lines.Text := '';
16 daniel-mar 204
 
205
  if firstTimeBrowserLoad then
206
  begin
207
    bakTS := PageControl1.ActivePage;
208
    try
209
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
210
      Webbrowser1.Clear;
211
    finally
212
      PageControl1.ActivePage := bakTS;
213
    end;
214
    firstTimeBrowserLoad := false;
215
  end
216
  else
217
    Webbrowser1.Clear;
218
 
5 daniel-mar 219
  Screen.Cursor := crHourGlass;
220
  Application.ProcessMessages;
221
 
222
  try
223
    SynEdit1.Lines.SaveToFile(GetScrapFile);
224
 
8 daniel-mar 225
    memo2.Lines.Text := RunPHPScript(GetScrapFile);
5 daniel-mar 226
 
8 daniel-mar 227
    Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
5 daniel-mar 228
 
229
    if IsTextHTML(memo2.lines.text) then
230
      PageControl1.ActivePage := HtmlTabSheet
231
    else
232
      PageControl1.ActivePage := PlaintextTabSheet;
233
  finally
234
    Screen.Cursor := crDefault;
2 daniel-mar 235
  end;
5 daniel-mar 236
end;
2 daniel-mar 237
 
13 daniel-mar 238
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
239
  MousePos: TPoint; var Handled: Boolean);
240
begin
241
  if ssCtrl in Shift then
242
  begin
243
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
244
  end;
245
end;
246
 
247
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
248
  MousePos: TPoint; var Handled: Boolean);
249
begin
250
  if ssCtrl in Shift then
251
  begin
252
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
253
  end;
254
end;
255
 
5 daniel-mar 256
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
257
begin
258
  SynEditFocusTimer.Enabled := false;
259
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
260
  SynEdit1.SetFocus;
261
end;
2 daniel-mar 262
 
5 daniel-mar 263
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
264
  const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
265
  Headers: OleVariant; var Cancel: WordBool);
266
var
8 daniel-mar 267
  s, myURL: string;
5 daniel-mar 268
  lineno: integer;
7 daniel-mar 269
  p: integer;
5 daniel-mar 270
begin
7 daniel-mar 271
  {$REGION 'Line number references (PHP errors and warnings)'}
8 daniel-mar 272
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
5 daniel-mar 273
  begin
274
    try
8 daniel-mar 275
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
5 daniel-mar 276
      if not TryStrToInt(s, lineno) then exit;
277
      GotoLineNo(lineno);
278
      SynEditFocusTimer.Enabled := true;
279
    finally
280
      Cancel := true;
281
    end;
8 daniel-mar 282
    Exit;
5 daniel-mar 283
  end;
7 daniel-mar 284
  {$ENDREGION}
285
 
8 daniel-mar 286
  {$REGION 'Intelligent browser (executes PHP scripts)'}
7 daniel-mar 287
  if URL <> 'about:blank' then
288
  begin
289
    myUrl := URL;
290
 
8 daniel-mar 291
    p := Pos('?', myUrl);
292
    if p >= 1 then myURL := copy(myURL, 1, p-1);
7 daniel-mar 293
 
8 daniel-mar 294
    // TODO: myURL urldecode
295
    // TODO: maybe we could even open that file in the editor!
7 daniel-mar 296
 
8 daniel-mar 297
    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 298
    begin
8 daniel-mar 299
      WebBrowser1.LoadHTML(GetDosOutput('"'+GetPHPExe+'" "'+myURL+'"', ExtractFileDir(Application.ExeName)), myUrl);
7 daniel-mar 300
      Cancel := true;
301
    end;
302
  end;
303
  {$ENDREGION}
5 daniel-mar 304
end;
2 daniel-mar 305
 
306
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
307
begin
13 daniel-mar 308
  FastPHPConfig.WriteInteger('User', 'FontSize', SynEdit1.Font.Size);
2 daniel-mar 309
end;
310
 
15 daniel-mar 311
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
312
var
313
  r: integer;
314
begin
315
  if SynEdit1.Modified then
316
  begin
317
    if ParamStr(1) <> '' then
318
    begin
319
      r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
320
      if r = mrCancel then
321
      begin
322
        CanClose := false;
323
        Exit;
324
      end
325
      else if r = mrYes then
326
      begin
327
        SynEdit1.Lines.SaveToFile(GetScrapFile);
328
        CanClose := true;
329
      end;
330
    end
331
    else
332
    begin
333
      SynEdit1.Lines.SaveToFile(GetScrapFile);
334
      CanClose := true;
335
    end;
336
  end;
337
end;
338
 
2 daniel-mar 339
procedure TForm1.FormCreate(Sender: TObject);
340
begin
341
  HlpPrevPageIndex := -1;
342
  CurSearchTerm := '';
13 daniel-mar 343
  Caption := Caption + ' - ' + GetScrapFile;
344
  SrcRep := TFindReplace.Create(self);
345
  SrcRep.Editor := SynEdit1;
2 daniel-mar 346
end;
347
 
348
procedure TForm1.FormDestroy(Sender: TObject);
349
begin
350
  if Assigned(ChmIndex) then
351
  begin
352
    FreeAndNil(ChmIndex);
353
  end;
13 daniel-mar 354
  FreeAndNil(SrcRep);
2 daniel-mar 355
end;
356
 
357
procedure TForm1.FormShow(Sender: TObject);
358
var
359
  ScrapFile: string;
360
begin
361
  ScrapFile := GetScrapFile;
362
  if ScrapFile = '' then
363
  begin
10 daniel-mar 364
    Application.Terminate; // Close;
2 daniel-mar 365
    exit;
366
  end;
15 daniel-mar 367
  if FileExists(ScrapFile) then
368
    SynEdit1.Lines.LoadFromFile(ScrapFile)
369
  else
370
    SynEdit1.Lines.Clear;
2 daniel-mar 371
 
372
  PageControl1.ActivePage := PlaintextTabSheet;
373
 
374
  PageControl2.ActivePageIndex := 0; // Scraps
375
  HelpTabsheet.TabVisible := false;
5 daniel-mar 376
 
13 daniel-mar 377
  SynEdit1.Font.Size := FastPHPConfig.ReadInteger('User', 'FontSize', SynEdit1.Font.Size);
5 daniel-mar 378
  SynEdit1.SetFocus;
2 daniel-mar 379
end;
380
 
381
function TForm1.GetScrapFile: string;
382
begin
19 daniel-mar 383
  if FScrapFile <> '' then exit(FScrapFile);
384
 
15 daniel-mar 385
  if ParamStr(1) <> '' then
13 daniel-mar 386
    result := ParamStr(1)
387
  else
388
    result := FastPHPConfig.ReadString('Paths', 'ScrapFile', '');
2 daniel-mar 389
  if not FileExists(result) then
390
  begin
19 daniel-mar 391
    repeat
392
      if not OpenDialog3.Execute then
393
      begin
394
        Application.Terminate;
395
        exit('');
396
      end;
2 daniel-mar 397
 
19 daniel-mar 398
      if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
399
      begin
400
        ShowMessage('Path does not exist! Please try again.');
401
      end
402
      else
403
      begin
404
        result := OpenDialog3.FileName;
405
      end;
406
    until result <> '';
2 daniel-mar 407
 
4 daniel-mar 408
    SynEdit1.Lines.Clear;
409
    SynEdit1.Lines.SaveToFile(result);
2 daniel-mar 410
 
411
    FastPHPConfig.WriteString('Paths', 'ScrapFile', result);
19 daniel-mar 412
    FScrapFile := result;
2 daniel-mar 413
  end;
414
end;
415
 
416
procedure TForm1.Help;
417
var
19 daniel-mar 418
  IndexFile, chmFile, w, OriginalWord, url: string;
2 daniel-mar 419
  internalHtmlFile: string;
420
begin
421
  if not Assigned(ChmIndex) then
422
  begin
423
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
424
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
425
    if FileExists(IndexFile) then
426
    begin
427
      ChmIndex := TMemIniFile.Create(IndexFile);
428
    end;
429
  end;
430
 
431
  if Assigned(ChmIndex) then
432
  begin
433
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
434
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
435
 
436
    chmFile := ChangeFileExt(IndexFile, '.chm');
437
    if not FileExists(chmFile) then
438
    begin
439
      FreeAndNil(ChmIndex);
440
    end;
441
  end;
442
 
443
  if not Assigned(ChmIndex) then
444
  begin
445
    if not OpenDialog1.Execute then exit;
446
 
447
    chmFile := OpenDialog1.FileName;
448
    if not FileExists(chmFile) then exit;
449
 
450
    IndexFile := ChangeFileExt(chmFile, '.ini');
451
 
452
    if not FileExists(IndexFile) then
453
    begin
454
      Panel1.Align := alClient;
455
      Panel1.Visible := true;
456
      Panel1.BringToFront;
457
      Screen.Cursor := crHourGlass;
458
      Application.ProcessMessages;
459
      try
460
        if not ParseCHM(chmFile) then
461
        begin
462
          ShowMessage('The CHM file is not a valid PHP documentation. Cannot use help.');
463
          exit;
464
        end;
465
      finally
466
        Screen.Cursor := crDefault;
467
        Panel1.Visible := false;
468
      end;
469
 
470
      if not FileExists(IndexFile) then
471
      begin
472
        ShowMessage('Unknown error. Cannot use help.');
473
        exit;
474
      end;
475
    end;
476
 
477
    FastPHPConfig.WriteString('Paths', 'HelpIndex', IndexFile);
478
    FastPHPConfig.UpdateFile;
479
 
480
    ChmIndex := TMemIniFile.Create(IndexFile);
481
  end;
482
 
4 daniel-mar 483
  w := GetWordUnderCaret(SynEdit1);
2 daniel-mar 484
  if w = '' then exit;
8 daniel-mar 485
  if CharInSet(w[1], ['0'..'9']) then exit;
19 daniel-mar 486
 
487
  Originalword := w;
488
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
2 daniel-mar 489
  w := LowerCase(w);
490
  CurSearchTerm := w;
491
 
492
  internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
493
  if internalHtmlFile = '' then
494
  begin
495
    HelpTabsheet.TabVisible := false;
496
    HlpPrevPageIndex := -1;
19 daniel-mar 497
    ShowMessageFmt('No help for "%s" available', [Originalword]);
2 daniel-mar 498
    Exit;
499
  end;
500
 
501
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
502
 
503
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
504
  HelpTabsheet.TabVisible := true;
505
  PageControl2.ActivePage := HelpTabsheet;
8 daniel-mar 506
  WebBrowser2.Navigate(url);
507
  WebBrowser2.Wait;
2 daniel-mar 508
end;
509
 
5 daniel-mar 510
procedure TForm1.GotoLineNo(LineNo:integer);
511
var
512
  line: string;
513
  i: integer;
2 daniel-mar 514
begin
5 daniel-mar 515
  SynEdit1.GotoLineAndCenter(LineNo);
516
 
517
  // Skip indent
518
  line := SynEdit1.Lines[SynEdit1.CaretY];
519
  for i := 1 to Length(line) do
520
  begin
8 daniel-mar 521
    if not CharInSet(line[i], [' ', #9]) then
5 daniel-mar 522
    begin
523
      SynEdit1.CaretX := i-1;
524
      break;
525
    end;
526
  end;
527
 
528
  PageControl2.ActivePage := TabSheet3{Scrap};
529
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
2 daniel-mar 530
end;
531
 
8 daniel-mar 532
procedure TForm1.PageControl2Changing(Sender: TObject;
533
  var AllowChange: Boolean);
534
begin
535
  if PageControl2.ActivePage = HelpTabsheet then
536
    HlpPrevPageIndex := -1
537
  else
538
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
539
 
540
  AllowChange := true;
541
end;
542
 
5 daniel-mar 543
procedure TForm1.Memo2DblClick(Sender: TObject);
544
var
16 daniel-mar 545
  pfx, line: string;
5 daniel-mar 546
  p, lineno: integer;
547
begin
548
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
16 daniel-mar 549
 
18 daniel-mar 550
  {$REGION 'Possibility 1: filename.php:lineno'}
16 daniel-mar 551
  pfx := ExtractFileName(GetScrapFile)+':';
552
  p := Pos(pfx, line);
553
  if p <> 0 then
554
  begin
555
    line := copy(line, p+length(pfx), 99);
556
    if not TryStrToInt(line, lineno) then exit;
557
    GotoLineNo(lineno);
558
  end;
18 daniel-mar 559
  {$ENDREGION}
16 daniel-mar 560
 
18 daniel-mar 561
  {$REGION 'Possibility 2: on line xx'}
16 daniel-mar 562
  pfx := ' on line ';
563
  p := Pos(pfx, line);
564
  if p <> 0 then
565
  begin
566
    line := copy(line, p+length(pfx), 99);
567
    if not TryStrToInt(line, lineno) then exit;
568
    GotoLineNo(lineno);
569
  end;
18 daniel-mar 570
  {$ENDREGION}
5 daniel-mar 571
end;
572
 
17 daniel-mar 573
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
574
  Shift: TShiftState);
575
begin
576
  if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
577
end;
578
 
5 daniel-mar 579
function TForm1.MarkUpLineReference(cont: string): string;
580
var
581
  p, a, b: integer;
582
  num: integer;
583
  insert_a, insert_b: string;
18 daniel-mar 584
 
585
  procedure _process(toFind: string);
5 daniel-mar 586
  begin
18 daniel-mar 587
    p := Pos(toFind, cont);
588
    while p >= 1 do
5 daniel-mar 589
    begin
18 daniel-mar 590
      a := p+1;
591
      b := p+length(toFind);
592
      num := 0;
593
      while CharInSet(cont[b], ['0'..'9']) do
594
      begin
595
        num := num*10 + StrToInt(cont[b]);
596
        inc(b);
597
      end;
5 daniel-mar 598
 
18 daniel-mar 599
      insert_b := '</a>';
600
      insert_a := '<a href="'+FASTPHP_GOTO_URI_PREFIX+IntToStr(num)+'">';
5 daniel-mar 601
 
18 daniel-mar 602
      insert(insert_b, cont, b);
603
      insert(insert_a, cont, a);
5 daniel-mar 604
 
18 daniel-mar 605
      p := b + Length(insert_a) + Length(insert_b);
5 daniel-mar 606
 
18 daniel-mar 607
      p := PosEx(toFind, cont, p+1);
608
    end;
5 daniel-mar 609
  end;
18 daniel-mar 610
begin
611
  {$REGION 'Possibility 1: filename.php:lineno'}
612
  _process(ExtractFileName(GetScrapFile)+':');
613
  {$ENDREGION}
5 daniel-mar 614
 
18 daniel-mar 615
  {$REGION 'Possibility 2: on line xx'}
616
  // TODO: make it more specific to PHP error messages. "on line" is too broad.
617
  _process(' on line ');
618
  {$ENDREGION}
619
 
5 daniel-mar 620
  result := cont;
621
end;
622
 
2 daniel-mar 623
end.