Subversion Repositories fastphp

Rev

Rev 24 | Rev 26 | 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???
16
// 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)
21 daniel-mar 19
// TODO: todo liste
2 daniel-mar 20
 
21
// Future ideas
21 daniel-mar 22
// - code explorer / code insight
2 daniel-mar 23
// - verschiedene php versionen?
24
// - webbrowser1 nur laden, wenn man den tab anwählt?
25
// - doppelklick auf tab soll diesen schließen
5 daniel-mar 26
// - Onlinehelp (www) aufrufen
13 daniel-mar 27
// - Let all colors be adjustable
21 daniel-mar 28
// - code in bildschirmmitte (horizontal)?
2 daniel-mar 29
 
30
interface
31
 
32
uses
33
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
4 daniel-mar 34
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
25 daniel-mar 35
  SynEditHighlighter, SynHighlighterPHP, SynEdit, FindReplace,
36
  ActnList, SynEditMiscClasses, SynEditSearch, SHDocVw{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF};
2 daniel-mar 37
 
23 daniel-mar 38
{.$DEFINE OnlineHelp}
39
 
2 daniel-mar 40
type
41
  TForm1 = class(TForm)
42
    PageControl1: TPageControl;
43
    PlaintextTabSheet: TTabSheet;
44
    HtmlTabSheet: TTabSheet;
45
    Memo2: TMemo;
46
    WebBrowser1: TWebBrowser;
47
    Splitter1: TSplitter;
48
    PageControl2: TPageControl;
20 daniel-mar 49
    CodeTabsheet: TTabSheet;
2 daniel-mar 50
    HelpTabsheet: TTabSheet;
51
    WebBrowser2: TWebBrowser;
52
    OpenDialog1: TOpenDialog;
53
    Panel1: TPanel;
54
    OpenDialog3: TOpenDialog;
4 daniel-mar 55
    SynEdit1: TSynEdit;
56
    SynPHPSyn1: TSynPHPSyn;
5 daniel-mar 57
    Panel2: TPanel;
58
    SynEditFocusTimer: TTimer;
59
    Button1: TButton;
60
    Button2: TButton;
61
    Button3: TButton;
13 daniel-mar 62
    Button4: TButton;
63
    Button5: TButton;
64
    Button6: TButton;
65
    ActionList: TActionList;
66
    ActionFind: TAction;
67
    ActionReplace: TAction;
68
    ActionFindNext: TAction;
69
    ActionGoto: TAction;
70
    ActionSave: TAction;
71
    ActionHelp: TAction;
72
    ActionRun: TAction;
73
    ActionESC: TAction;
74
    Button7: TButton;
15 daniel-mar 75
    ActionOpen: TAction;
76
    Button8: TButton;
22 daniel-mar 77
    Button9: TButton;
78
    ActionFindPrev: TAction;
23 daniel-mar 79
    Timer1: TTimer;
80
    ActionSpaceToTab: TAction;
81
    Button11: TButton;
24 daniel-mar 82
    SynEditSearch1: TSynEditSearch;
2 daniel-mar 83
    procedure Run(Sender: TObject);
84
    procedure FormShow(Sender: TObject);
85
    procedure FormCreate(Sender: TObject);
86
    procedure FormDestroy(Sender: TObject);
87
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
88
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
5 daniel-mar 89
    procedure Memo2DblClick(Sender: TObject);
90
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
25 daniel-mar 91
      const pDisp: IDispatch; {$IFDEF USE_SHDOCVW_TLB}const{$ELSE}var{$ENDIF} URL, Flags, TargetFrameName, PostData,
5 daniel-mar 92
      Headers: OleVariant; var Cancel: WordBool);
93
    procedure SynEditFocusTimerTimer(Sender: TObject);
13 daniel-mar 94
    procedure ActionFindExecute(Sender: TObject);
95
    procedure ActionReplaceExecute(Sender: TObject);
96
    procedure ActionFindNextExecute(Sender: TObject);
97
    procedure ActionGotoExecute(Sender: TObject);
98
    procedure ActionSaveExecute(Sender: TObject);
99
    procedure ActionHelpExecute(Sender: TObject);
100
    procedure ActionRunExecute(Sender: TObject);
101
    procedure ActionESCExecute(Sender: TObject);
102
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
103
      MousePos: TPoint; var Handled: Boolean);
104
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
105
      MousePos: TPoint; var Handled: Boolean);
15 daniel-mar 106
    procedure ActionOpenExecute(Sender: TObject);
107
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
17 daniel-mar 108
    procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
22 daniel-mar 109
    procedure ActionFindPrevExecute(Sender: TObject);
23 daniel-mar 110
    procedure SynEdit1MouseCursor(Sender: TObject;
111
      const aLineCharPos: TBufferCoord; var aCursor: TCursor);
112
    procedure Timer1Timer(Sender: TObject);
113
    procedure ActionSpaceToTabExecute(Sender: TObject);
2 daniel-mar 114
  private
115
    CurSearchTerm: string;
116
    HlpPrevPageIndex: integer;
24 daniel-mar 117
    SrcRep: TSynEditFindReplace;
23 daniel-mar 118
    {$IFDEF OnlineHelp}
119
    gOnlineHelpWord: string;
120
    {$ENDIF}
2 daniel-mar 121
    procedure Help;
5 daniel-mar 122
    function MarkUpLineReference(cont: string): string;
25 daniel-mar 123
    procedure SaveToFile(filename: string);
2 daniel-mar 124
  protected
125
    ChmIndex: TMemIniFile;
19 daniel-mar 126
    FScrapFile: string;
5 daniel-mar 127
    procedure GotoLineNo(LineNo:integer);
2 daniel-mar 128
    function GetScrapFile: string;
129
  end;
130
 
131
var
132
  Form1: TForm1;
133
 
134
implementation
135
 
136
{$R *.dfm}
137
 
138
uses
25 daniel-mar 139
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI, RichEdit,
140
  SynUnicode;
2 daniel-mar 141
 
13 daniel-mar 142
// TODO: FindPrev ?
143
procedure TForm1.ActionFindNextExecute(Sender: TObject);
144
begin
145
  SrcRep.FindNext;
146
end;
147
 
22 daniel-mar 148
procedure TForm1.ActionFindPrevExecute(Sender: TObject);
149
begin
150
  SrcRep.FindPrev;
151
end;
152
 
13 daniel-mar 153
procedure TForm1.ActionGotoExecute(Sender: TObject);
5 daniel-mar 154
var
155
  val: string;
156
  lineno: integer;
157
begin
13 daniel-mar 158
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
159
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
5 daniel-mar 160
 
13 daniel-mar 161
  InputQuery('Go to', 'Line number:', val);
162
  if not TryStrToInt(val, lineno) then
163
  begin
164
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
165
    exit;
166
  end;
167
  GotoLineNo(lineno);
168
end;
5 daniel-mar 169
 
13 daniel-mar 170
procedure TForm1.ActionHelpExecute(Sender: TObject);
171
begin
172
  Help;
173
  if PageControl2.ActivePage = HelpTabsheet then
174
    WebBrowser2.SetFocus
20 daniel-mar 175
  else if PageControl2.ActivePage = CodeTabsheet then
13 daniel-mar 176
    SynEdit1.SetFocus;
177
end;
8 daniel-mar 178
 
15 daniel-mar 179
procedure TForm1.ActionOpenExecute(Sender: TObject);
180
begin
181
  If OpenDialog3.Execute then
182
  begin
183
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar(OpenDialog3.FileName), '', SW_NORMAL);
184
  end;
185
end;
186
 
13 daniel-mar 187
procedure TForm1.ActionReplaceExecute(Sender: TObject);
188
begin
189
  SrcRep.ReplaceExecute;
190
end;
5 daniel-mar 191
 
13 daniel-mar 192
procedure TForm1.ActionRunExecute(Sender: TObject);
193
begin
194
  Run(Sender);
195
  SynEdit1.SetFocus;
196
end;
5 daniel-mar 197
 
13 daniel-mar 198
procedure TForm1.ActionSaveExecute(Sender: TObject);
199
begin
25 daniel-mar 200
  SaveToFile(GetScrapFile);
16 daniel-mar 201
  SynEdit1.Modified := false;
13 daniel-mar 202
end;
203
 
23 daniel-mar 204
procedure TForm1.ActionSpaceToTabExecute(Sender: TObject);
205
 
206
    function SpacesAtBeginning(line: string): integer;
207
    begin
208
      result := 0;
25 daniel-mar 209
      if Trim(line) = '' then exit;
23 daniel-mar 210
      while line[result+1] = ' ' do
211
      begin
212
        inc(result);
213
      end;
214
    end;
215
 
25 daniel-mar 216
    function GuessIndent(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): integer;
23 daniel-mar 217
      function _Check(indent: integer): boolean;
218
      var
219
        i: integer;
220
      begin
221
        result := true;
222
        for i := 0 to lines.Count-1 do
223
          if SpacesAtBeginning(lines.Strings[i]) mod indent <> 0 then
224
          begin
225
            // ShowMessageFmt('Zeile "%s" nicht durch %d teilbar!', [lines.strings[i], indent]);
25 daniel-mar 226
            result := false;
227
            exit;
23 daniel-mar 228
          end;
229
      end;
230
    var
231
      i: integer;
232
    begin
233
      for i := 8 downto 2 do
234
      begin
25 daniel-mar 235
        if _Check(i) then
236
        begin
237
          result := i;
238
          exit;
239
        end;
23 daniel-mar 240
      end;
241
      result := -1;
242
    end;
243
 
25 daniel-mar 244
    procedure SpaceToTab(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}; indent: integer);
23 daniel-mar 245
    var
246
      i, spaces: integer;
247
    begin
248
      for i := 0 to lines.Count-1 do
249
      begin
250
        spaces := SpacesAtBeginning(lines.Strings[i]);
251
        lines.Strings[i] := StringOfChar(#9, spaces div indent) + StringOfChar(' ', spaces mod indent) + Copy(lines.Strings[i], spaces+1, Length(lines.Strings[i])-spaces);
252
      end;
253
    end;
254
 
25 daniel-mar 255
    function SpacesAvailable(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): boolean;
23 daniel-mar 256
    var
257
      i, spaces: integer;
258
    begin
259
      for i := 0 to lines.Count-1 do
260
      begin
261
        spaces := SpacesAtBeginning(lines.Strings[i]);
25 daniel-mar 262
        if spaces > 0 then
263
        begin
264
          result := true;
265
          exit;
266
        end;
23 daniel-mar 267
      end;
25 daniel-mar 268
      result := false;
269
      exit;
23 daniel-mar 270
    end;
271
 
272
var
273
  val: string;
274
  ind: integer;
275
resourcestring
276
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
277
begin
278
  // TODO: if something is selected, only process the selected part
279
 
280
  if not SpacesAvailable(SynEdit1.Lines) then
281
  begin
282
    ShowMessage(SNoLinesAvailable);
283
    exit;
284
  end;
285
 
286
  ind := GuessIndent(SynEdit1.Lines);
287
  if ind <> -1 then val := IntToStr(ind);
288
 
289
  InputQuery('Spaces to tabs', 'Indent:', val); // TODO: handle CANCEL correctly...
25 daniel-mar 290
  if TryStrToInt(Trim(val), ind) then
23 daniel-mar 291
  begin
292
    if ind = 0 then exit;
293
    SpaceToTab(SynEdit1.Lines, ind);
294
  end;
295
 
296
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
297
end;
298
 
13 daniel-mar 299
procedure TForm1.ActionESCExecute(Sender: TObject);
300
begin
301
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
302
     (HelpTabsheet.TabVisible) then
303
  begin
304
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
305
    HelpTabsheet.TabVisible := false;
2 daniel-mar 306
  end;
13 daniel-mar 307
 
308
  // Dirty hack...
22 daniel-mar 309
  SrcRep.CloseDialogs;
2 daniel-mar 310
end;
311
 
13 daniel-mar 312
procedure TForm1.ActionFindExecute(Sender: TObject);
313
begin
314
  SrcRep.FindExecute;
315
end;
316
 
16 daniel-mar 317
var
318
  firstTimeBrowserLoad: boolean = true;
2 daniel-mar 319
procedure TForm1.Run(Sender: TObject);
16 daniel-mar 320
var
321
  bakTS: TTabSheet;
2 daniel-mar 322
begin
5 daniel-mar 323
  memo2.Lines.Text := '';
16 daniel-mar 324
 
325
  if firstTimeBrowserLoad then
326
  begin
327
    bakTS := PageControl1.ActivePage;
328
    try
329
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
330
      Webbrowser1.Clear;
331
    finally
332
      PageControl1.ActivePage := bakTS;
333
    end;
334
    firstTimeBrowserLoad := false;
335
  end
336
  else
337
    Webbrowser1.Clear;
338
 
5 daniel-mar 339
  Screen.Cursor := crHourGlass;
340
  Application.ProcessMessages;
341
 
342
  try
25 daniel-mar 343
    SaveToFile(GetScrapFile);
5 daniel-mar 344
 
8 daniel-mar 345
    memo2.Lines.Text := RunPHPScript(GetScrapFile);
5 daniel-mar 346
 
8 daniel-mar 347
    Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
5 daniel-mar 348
 
349
    if IsTextHTML(memo2.lines.text) then
350
      PageControl1.ActivePage := HtmlTabSheet
351
    else
352
      PageControl1.ActivePage := PlaintextTabSheet;
353
  finally
354
    Screen.Cursor := crDefault;
2 daniel-mar 355
  end;
5 daniel-mar 356
end;
2 daniel-mar 357
 
25 daniel-mar 358
procedure TForm1.SaveToFile(filename: string);
359
{$IFNDEF UNICODE}
360
var
361
  sl: TStringList;
362
{$ENDIF}
363
begin
364
  {$IFDEF UNICODE}
365
  SynEdit1.Lines.SaveToFile(filename);
366
  {$ELSE}
367
  sl := TStringList.Create;
368
  try
369
    sl.Text := UTF8String(SynEdit1.Lines.Text);
370
    sl.SaveToFile(GetScrapFile);
371
  finally
372
    FreeAndNil(sl);
373
  end;
374
  {$ENDIF}
375
end;
376
 
23 daniel-mar 377
procedure TForm1.SynEdit1MouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; var aCursor: TCursor);
378
{$IFDEF OnlineHelp}
379
var
380
  Line: Integer;
381
  Column: Integer;
382
  word: string;
383
begin
384
  Line  := aLineCharPos.Line-1;
385
  Column := aLineCharPos.Char-1;
386
  word := GetWordUnderPos(TSynEdit(Sender), Line, Column);
387
  if word <> gOnlineHelpWord then
388
  begin
389
    gOnlineHelpWord := word;
390
    Timer1.Enabled := false;
391
    Timer1.Enabled := true;
392
  end;
393
{$ELSE}
394
begin
395
{$ENDIF}
396
end;
397
 
13 daniel-mar 398
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
399
  MousePos: TPoint; var Handled: Boolean);
400
begin
401
  if ssCtrl in Shift then
402
  begin
403
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
23 daniel-mar 404
    Handled := true;
405
  end
406
  else Handled := false;
13 daniel-mar 407
end;
408
 
409
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
410
  MousePos: TPoint; var Handled: Boolean);
411
begin
412
  if ssCtrl in Shift then
413
  begin
414
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
23 daniel-mar 415
    Handled := true;
416
  end
417
  else Handled := false;
13 daniel-mar 418
end;
419
 
5 daniel-mar 420
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
421
begin
422
  SynEditFocusTimer.Enabled := false;
423
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
424
  SynEdit1.SetFocus;
425
end;
2 daniel-mar 426
 
23 daniel-mar 427
procedure TForm1.Timer1Timer(Sender: TObject);
428
begin
429
  {$IFDEF OnlineHelp}
430
  Timer1.Enabled := false;
431
 
432
  // TODO: Insert a small online help hint
433
  //Caption := gOnlineHelpWord;
434
  {$ENDIF}
435
end;
436
 
5 daniel-mar 437
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
25 daniel-mar 438
  const pDisp: IDispatch; {$IFDEF USE_SHDOCVW_TLB}const{$ELSE}var{$ENDIF} URL, Flags, TargetFrameName, PostData,
5 daniel-mar 439
  Headers: OleVariant; var Cancel: WordBool);
440
var
8 daniel-mar 441
  s, myURL: string;
5 daniel-mar 442
  lineno: integer;
7 daniel-mar 443
  p: integer;
5 daniel-mar 444
begin
7 daniel-mar 445
  {$REGION 'Line number references (PHP errors and warnings)'}
8 daniel-mar 446
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
5 daniel-mar 447
  begin
448
    try
8 daniel-mar 449
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
5 daniel-mar 450
      if not TryStrToInt(s, lineno) then exit;
451
      GotoLineNo(lineno);
452
      SynEditFocusTimer.Enabled := true;
453
    finally
454
      Cancel := true;
455
    end;
8 daniel-mar 456
    Exit;
5 daniel-mar 457
  end;
7 daniel-mar 458
  {$ENDREGION}
459
 
8 daniel-mar 460
  {$REGION 'Intelligent browser (executes PHP scripts)'}
7 daniel-mar 461
  if URL <> 'about:blank' then
462
  begin
463
    myUrl := URL;
464
 
8 daniel-mar 465
    p := Pos('?', myUrl);
466
    if p >= 1 then myURL := copy(myURL, 1, p-1);
7 daniel-mar 467
 
8 daniel-mar 468
    // TODO: myURL urldecode
469
    // TODO: maybe we could even open that file in the editor!
7 daniel-mar 470
 
8 daniel-mar 471
    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 472
    begin
8 daniel-mar 473
      WebBrowser1.LoadHTML(GetDosOutput('"'+GetPHPExe+'" "'+myURL+'"', ExtractFileDir(Application.ExeName)), myUrl);
7 daniel-mar 474
      Cancel := true;
475
    end;
476
  end;
477
  {$ENDREGION}
5 daniel-mar 478
end;
2 daniel-mar 479
 
480
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
481
begin
13 daniel-mar 482
  FastPHPConfig.WriteInteger('User', 'FontSize', SynEdit1.Font.Size);
2 daniel-mar 483
end;
484
 
15 daniel-mar 485
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
486
var
487
  r: integer;
488
begin
489
  if SynEdit1.Modified then
490
  begin
491
    if ParamStr(1) <> '' then
492
    begin
493
      r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
494
      if r = mrCancel then
495
      begin
496
        CanClose := false;
497
        Exit;
498
      end
499
      else if r = mrYes then
500
      begin
25 daniel-mar 501
        SaveToFile(GetScrapFile);
15 daniel-mar 502
        CanClose := true;
503
      end;
504
    end
505
    else
506
    begin
25 daniel-mar 507
      SaveToFile(GetScrapFile);
15 daniel-mar 508
      CanClose := true;
509
    end;
510
  end;
511
end;
512
 
2 daniel-mar 513
procedure TForm1.FormCreate(Sender: TObject);
514
begin
515
  HlpPrevPageIndex := -1;
516
  CurSearchTerm := '';
13 daniel-mar 517
  Caption := Caption + ' - ' + GetScrapFile;
24 daniel-mar 518
  SrcRep := TSynEditFindReplace.Create(self);
13 daniel-mar 519
  SrcRep.Editor := SynEdit1;
2 daniel-mar 520
end;
521
 
522
procedure TForm1.FormDestroy(Sender: TObject);
523
begin
524
  if Assigned(ChmIndex) then
525
  begin
526
    FreeAndNil(ChmIndex);
527
  end;
13 daniel-mar 528
  FreeAndNil(SrcRep);
2 daniel-mar 529
end;
530
 
531
procedure TForm1.FormShow(Sender: TObject);
532
var
533
  ScrapFile: string;
534
begin
535
  ScrapFile := GetScrapFile;
536
  if ScrapFile = '' then
537
  begin
10 daniel-mar 538
    Application.Terminate; // Close;
2 daniel-mar 539
    exit;
540
  end;
15 daniel-mar 541
  if FileExists(ScrapFile) then
542
    SynEdit1.Lines.LoadFromFile(ScrapFile)
543
  else
544
    SynEdit1.Lines.Clear;
2 daniel-mar 545
 
546
  PageControl1.ActivePage := PlaintextTabSheet;
547
 
20 daniel-mar 548
  PageControl2.ActivePage := CodeTabsheet;
2 daniel-mar 549
  HelpTabsheet.TabVisible := false;
5 daniel-mar 550
 
13 daniel-mar 551
  SynEdit1.Font.Size := FastPHPConfig.ReadInteger('User', 'FontSize', SynEdit1.Font.Size);
5 daniel-mar 552
  SynEdit1.SetFocus;
2 daniel-mar 553
end;
554
 
555
function TForm1.GetScrapFile: string;
556
begin
25 daniel-mar 557
  if FScrapFile <> '' then
558
  begin
559
    result := FScrapFile;
560
    exit;
561
  end;
19 daniel-mar 562
 
15 daniel-mar 563
  if ParamStr(1) <> '' then
13 daniel-mar 564
    result := ParamStr(1)
565
  else
566
    result := FastPHPConfig.ReadString('Paths', 'ScrapFile', '');
2 daniel-mar 567
  if not FileExists(result) then
568
  begin
19 daniel-mar 569
    repeat
570
      if not OpenDialog3.Execute then
571
      begin
572
        Application.Terminate;
25 daniel-mar 573
        result := '';
574
        exit;
19 daniel-mar 575
      end;
2 daniel-mar 576
 
19 daniel-mar 577
      if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
578
      begin
579
        ShowMessage('Path does not exist! Please try again.');
580
      end
581
      else
582
      begin
583
        result := OpenDialog3.FileName;
584
      end;
585
    until result <> '';
2 daniel-mar 586
 
4 daniel-mar 587
    SynEdit1.Lines.Clear;
25 daniel-mar 588
    SaveToFile(result);
2 daniel-mar 589
 
590
    FastPHPConfig.WriteString('Paths', 'ScrapFile', result);
19 daniel-mar 591
    FScrapFile := result;
2 daniel-mar 592
  end;
593
end;
594
 
595
procedure TForm1.Help;
596
var
19 daniel-mar 597
  IndexFile, chmFile, w, OriginalWord, url: string;
2 daniel-mar 598
  internalHtmlFile: string;
599
begin
600
  if not Assigned(ChmIndex) then
601
  begin
602
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
603
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
604
    if FileExists(IndexFile) then
605
    begin
606
      ChmIndex := TMemIniFile.Create(IndexFile);
607
    end;
608
  end;
609
 
610
  if Assigned(ChmIndex) then
611
  begin
612
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
613
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
614
 
615
    chmFile := ChangeFileExt(IndexFile, '.chm');
616
    if not FileExists(chmFile) then
617
    begin
618
      FreeAndNil(ChmIndex);
619
    end;
620
  end;
621
 
622
  if not Assigned(ChmIndex) then
623
  begin
624
    if not OpenDialog1.Execute then exit;
625
 
626
    chmFile := OpenDialog1.FileName;
627
    if not FileExists(chmFile) then exit;
628
 
629
    IndexFile := ChangeFileExt(chmFile, '.ini');
630
 
631
    if not FileExists(IndexFile) then
632
    begin
633
      Panel1.Align := alClient;
634
      Panel1.Visible := true;
635
      Panel1.BringToFront;
636
      Screen.Cursor := crHourGlass;
637
      Application.ProcessMessages;
638
      try
639
        if not ParseCHM(chmFile) then
640
        begin
641
          ShowMessage('The CHM file is not a valid PHP documentation. Cannot use help.');
642
          exit;
643
        end;
644
      finally
645
        Screen.Cursor := crDefault;
646
        Panel1.Visible := false;
647
      end;
648
 
649
      if not FileExists(IndexFile) then
650
      begin
651
        ShowMessage('Unknown error. Cannot use help.');
652
        exit;
653
      end;
654
    end;
655
 
656
    FastPHPConfig.WriteString('Paths', 'HelpIndex', IndexFile);
657
    FastPHPConfig.UpdateFile;
658
 
659
    ChmIndex := TMemIniFile.Create(IndexFile);
660
  end;
661
 
4 daniel-mar 662
  w := GetWordUnderCaret(SynEdit1);
2 daniel-mar 663
  if w = '' then exit;
8 daniel-mar 664
  if CharInSet(w[1], ['0'..'9']) then exit;
19 daniel-mar 665
 
666
  Originalword := w;
667
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
2 daniel-mar 668
  w := LowerCase(w);
669
  CurSearchTerm := w;
670
 
671
  internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
672
  if internalHtmlFile = '' then
673
  begin
674
    HelpTabsheet.TabVisible := false;
675
    HlpPrevPageIndex := -1;
19 daniel-mar 676
    ShowMessageFmt('No help for "%s" available', [Originalword]);
2 daniel-mar 677
    Exit;
678
  end;
679
 
680
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
681
 
682
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
683
  HelpTabsheet.TabVisible := true;
684
  PageControl2.ActivePage := HelpTabsheet;
8 daniel-mar 685
  WebBrowser2.Navigate(url);
686
  WebBrowser2.Wait;
2 daniel-mar 687
end;
688
 
5 daniel-mar 689
procedure TForm1.GotoLineNo(LineNo:integer);
690
var
691
  line: string;
692
  i: integer;
2 daniel-mar 693
begin
5 daniel-mar 694
  SynEdit1.GotoLineAndCenter(LineNo);
695
 
696
  // Skip indent
697
  line := SynEdit1.Lines[SynEdit1.CaretY];
698
  for i := 1 to Length(line) do
699
  begin
8 daniel-mar 700
    if not CharInSet(line[i], [' ', #9]) then
5 daniel-mar 701
    begin
702
      SynEdit1.CaretX := i-1;
703
      break;
704
    end;
705
  end;
706
 
20 daniel-mar 707
  PageControl2.ActivePage := CodeTabsheet;
5 daniel-mar 708
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
2 daniel-mar 709
end;
710
 
8 daniel-mar 711
procedure TForm1.PageControl2Changing(Sender: TObject;
712
  var AllowChange: Boolean);
713
begin
714
  if PageControl2.ActivePage = HelpTabsheet then
715
    HlpPrevPageIndex := -1
716
  else
717
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
718
 
719
  AllowChange := true;
720
end;
721
 
5 daniel-mar 722
procedure TForm1.Memo2DblClick(Sender: TObject);
723
var
22 daniel-mar 724
  line: string;
725
 
726
  procedure _process(toFind: string);
727
  var
728
    p, lineno: integer;
729
  begin
730
    if FileSystemCaseSensitive then
731
      p := Pos(toFind, line)
732
    else
25 daniel-mar 733
      p := Pos(LowerCase(toFind), LowerCase(line));
22 daniel-mar 734
    if p <> 0 then
735
    begin
736
      line := copy(line, p+length(toFind), 99);
737
      if not TryStrToInt(line, lineno) then exit;
738
      GotoLineNo(lineno);
739
    end;
740
  end;
741
 
5 daniel-mar 742
begin
743
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
16 daniel-mar 744
 
18 daniel-mar 745
  {$REGION 'Possibility 1: filename.php:lineno'}
22 daniel-mar 746
  _process(ExtractFileName(GetScrapFile) + ':');
18 daniel-mar 747
  {$ENDREGION}
16 daniel-mar 748
 
18 daniel-mar 749
  {$REGION 'Possibility 2: on line xx'}
22 daniel-mar 750
  _process(ExtractFileName(GetScrapFile) + ' on line ');
18 daniel-mar 751
  {$ENDREGION}
5 daniel-mar 752
end;
753
 
17 daniel-mar 754
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
755
  Shift: TShiftState);
756
begin
757
  if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
758
end;
759
 
5 daniel-mar 760
function TForm1.MarkUpLineReference(cont: string): string;
18 daniel-mar 761
 
762
  procedure _process(toFind: string);
22 daniel-mar 763
  var
764
    p, a, b: integer;
765
    num: integer;
766
    insert_a, insert_b: string;
5 daniel-mar 767
  begin
22 daniel-mar 768
    if FileSystemCaseSensitive then
769
      p := Pos(toFind, cont)
770
    else
25 daniel-mar 771
      p := Pos(LowerCase(toFind), LowerCase(cont));
18 daniel-mar 772
    while p >= 1 do
5 daniel-mar 773
    begin
22 daniel-mar 774
      a := p;
775
      b := p + length(toFind);
18 daniel-mar 776
      num := 0;
777
      while CharInSet(cont[b], ['0'..'9']) do
778
      begin
779
        num := num*10 + StrToInt(cont[b]);
780
        inc(b);
781
      end;
5 daniel-mar 782
 
18 daniel-mar 783
      insert_b := '</a>';
22 daniel-mar 784
      insert_a := '<a href="' + FASTPHP_GOTO_URI_PREFIX + IntToStr(num) + '">';
5 daniel-mar 785
 
18 daniel-mar 786
      insert(insert_b, cont, b);
787
      insert(insert_a, cont, a);
5 daniel-mar 788
 
18 daniel-mar 789
      p := b + Length(insert_a) + Length(insert_b);
5 daniel-mar 790
 
18 daniel-mar 791
      p := PosEx(toFind, cont, p+1);
792
    end;
5 daniel-mar 793
  end;
22 daniel-mar 794
 
18 daniel-mar 795
begin
796
  {$REGION 'Possibility 1: filename.php:lineno'}
22 daniel-mar 797
  _process(ExtractFileName(GetScrapFile) + ':');
18 daniel-mar 798
  {$ENDREGION}
5 daniel-mar 799
 
18 daniel-mar 800
  {$REGION 'Possibility 2: on line xx'}
22 daniel-mar 801
  _process(ExtractFileName(GetScrapFile) + ' on line ');
18 daniel-mar 802
  {$ENDREGION}
803
 
5 daniel-mar 804
  result := cont;
805
end;
806
 
2 daniel-mar 807
end.