Subversion Repositories fastphp

Rev

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