Subversion Repositories fastphp

Rev

Rev 93 | Rev 96 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 93 Rev 94
1
unit EditorMain;
1
unit EditorMain;
2
 
2
 
3
{$Include 'FastPHP.inc'}
3
{$Include 'FastPHP.inc'}
4
 
4
 
5
(*
5
(*
6
  This program requires
6
  This program requires
7
  - Microsoft Internet Controls (TWebBrowser)
7
  - Microsoft Internet Controls (TWebBrowser)
8
    If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
8
    If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
9
    "Microsoft Internet Controls"
9
    "Microsoft Internet Controls"
10
  - SynEdit
10
  - SynEdit
11
    You can obtain SynEdit via Embarcadero GetIt
11
    You can obtain SynEdit via Embarcadero GetIt
12
*)
12
*)
13
 
13
 
14
// TODO: "crHourGlass" does not work if F9 is pressed!
14
// TODO: "crHourGlass" does not work if F9 is pressed!
15
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
15
// TODO: if a scrapfile is already open, create a new scrap file (scrap2.php)
16
// TODO: localize
16
// TODO: localize
17
// TODO: wieso geht copy paste im twebbrowser nicht???
17
// TODO: wieso geht copy paste im twebbrowser nicht???
18
// TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
18
// TODO: Wieso dauert webbrowser1 erste kompilierung so lange???
19
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
19
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
20
// TODO: Browser titlebar (link preview)
20
// TODO: Browser titlebar (link preview)
21
// TODO: "jump to next/prev todo" buttons/shortcuts
21
// TODO: "jump to next/prev todo" buttons/shortcuts
22
// TODO: "increase/decrease indent" buttons/shortcuts
22
// TODO: "increase/decrease indent" buttons/shortcuts
23
 
23
 
24
// In regards Unicode:
24
// In regards Unicode:
25
// - Solve compiler warnings
25
// - Solve compiler warnings
26
// - If you place Unicode symbols in a ANSI file, they will be replaced during saving
26
// - If you place Unicode symbols in a ANSI file, they will be replaced during saving
27
//   by "?" without asking the user if the code should be converted to Unicode!
27
//   by "?" without asking the user if the code should be converted to Unicode!
28
// - FastPHP can only read a UTF-8 file correctly if it has a BOM
-
 
29
//   However, the PSR-1 standard requires that files have UTF-8 without BOM!
-
 
30
//   So we need auto-detect (since many people are working with ANSI!)
-
 
31
// - When a file is correctly loaded with UTF-8/BOM,
-
 
32
//   the run output (Plaintext and HTML) will show UTF-8 instead of Unicode
-
 
33
//   (that COULD be intended since the Windows CMD is not Unicode ready?)
-
 
34
//   But HTML is also shown as UTF-8 even though I have added <meta charset="UTF-8"> ?!
-
 
35
// - Is it possible that UTF8 BOM automatically gets removed by FastPHP, generating pure ANSI?
28
// - Is it possible that UTF8 BOM automatically gets removed by FastPHP, generating pure ANSI?
36
 
29
 
-
 
30
// Note in re Unicode:
-
 
31
// - In Embarcadero® Delphi 10.4 Version 27.0.40680.4203:
-
 
32
//   SynEdit correctly detects UTF-8 files without BOM as well as ANSI files with Umlauts.
-
 
33
//   (Previous versions could not detect UTF-8 files without BOM?!)
-
 
34
// - If BOM is existing, it will be removed. (which is good, because this is defined by PSR-1)
-
 
35
 
37
// Small things:
36
// Small things:
38
// - The scroll bars of SynEdit are not affected by the dark theme
37
// - The scroll bars of SynEdit are not affected by the dark theme
39
 
38
 
40
// Future ideas
39
// Future ideas
41
// - code insight
40
// - code insight
42
// - verschiedene php versionen?
41
// - verschiedene php versionen?
43
// - webbrowser1 nur laden, wenn man den tab anwählt?
42
// - webbrowser1 nur laden, wenn man den tab anw�hlt?
44
// - doppelklick auf tab soll diesen schließen
43
// - doppelklick auf tab soll diesen schlie�en
45
// - Onlinehelp (www) aufrufen oder CHM datei
44
// - Onlinehelp (www) aufrufen oder CHM datei
46
// - Let all colors be adjustable
45
// - Let all colors be adjustable
47
// - code in bildschirmmitte (horizontal)?
46
// - code in bildschirmmitte (horizontal)?
48
// - search in files of a directory
47
// - search in files of a directory
49
// - Files in multiple tabs?
48
// - Files in multiple tabs?
50
// - Configurable tabulator display-width
49
// - Configurable tabulator display-width
51
 
50
 
52
interface
51
interface
53
 
52
 
54
uses
53
uses
55
  // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
54
  // TODO: "{$IFDEF USE_SHDOCVW_TLB}_TLB{$ENDIF}" does not work with Delphi 10.2
56
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
55
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
57
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
56
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
58
  SynEditHighlighter, SynHighlighterPHP, SynEdit, ShDocVw, FindReplace,
57
  SynEditHighlighter, SynHighlighterPHP, SynEdit, ShDocVw, FindReplace,
59
  ActnList, SynEditMiscClasses, SynEditSearch, RunPHP, ImgList, SynUnicode,
58
  ActnList, SynEditMiscClasses, SynEditSearch, RunPHP, ImgList, SynUnicode,
60
  System.ImageList, System.Actions, Vcl.Menus, Vcl.Themes, System.UITypes;
59
  System.ImageList, System.Actions, Vcl.Menus, Vcl.Themes, System.UITypes,
-
 
60
  SynEditCodeFolding;
61
 
61
 
62
{.$DEFINE OnlineHelp}
62
{.$DEFINE OnlineHelp}
63
 
63
 
64
type
64
type
65
  TForm1 = class(TForm)
65
  TForm1 = class(TForm)
66
    PageControl1: TPageControl;
66
    PageControl1: TPageControl;
67
    PlaintextTabSheet: TTabSheet;
67
    PlaintextTabSheet: TTabSheet;
68
    HtmlTabSheet: TTabSheet;
68
    HtmlTabSheet: TTabSheet;
69
    Memo2: TMemo;
69
    Memo2: TMemo;
70
    WebBrowser1: TWebBrowser;
70
    WebBrowser1: TWebBrowser;
71
    Splitter1: TSplitter;
71
    Splitter1: TSplitter;
72
    PageControl2: TPageControl;
72
    PageControl2: TPageControl;
73
    CodeTabsheet: TTabSheet;
73
    CodeTabsheet: TTabSheet;
74
    HelpTabsheet: TTabSheet;
74
    HelpTabsheet: TTabSheet;
75
    WebBrowser2: TWebBrowser;
75
    WebBrowser2: TWebBrowser;
76
    OpenDialog1: TOpenDialog;
76
    OpenDialog1: TOpenDialog;
77
    Panel1: TPanel;
77
    Panel1: TPanel;
78
    OpenDialog3: TOpenDialog;
78
    OpenDialog3: TOpenDialog;
79
    SynEdit1: TSynEdit;
79
    SynEdit1: TSynEdit;
80
    SynPHPSyn1: TSynPHPSyn;
80
    SynPHPSyn1: TSynPHPSyn;
81
    Panel2: TPanel;
81
    Panel2: TPanel;
82
    SynEditFocusTimer: TTimer;
82
    SynEditFocusTimer: TTimer;
83
    Button1: TButton;
83
    Button1: TButton;
84
    Button2: TButton;
84
    Button2: TButton;
85
    Button3: TButton;
85
    Button3: TButton;
86
    Button4: TButton;
86
    Button4: TButton;
87
    Button5: TButton;
87
    Button5: TButton;
88
    Button6: TButton;
88
    Button6: TButton;
89
    ActionList: TActionList;
89
    ActionList: TActionList;
90
    ActionFind: TAction;
90
    ActionFind: TAction;
91
    ActionReplace: TAction;
91
    ActionReplace: TAction;
92
    ActionFindNext: TAction;
92
    ActionFindNext: TAction;
93
    ActionGoto: TAction;
93
    ActionGoto: TAction;
94
    ActionSave: TAction;
94
    ActionSave: TAction;
95
    ActionHelp: TAction;
95
    ActionHelp: TAction;
96
    ActionRun: TAction;
96
    ActionRun: TAction;
97
    ActionESC: TAction;
97
    ActionESC: TAction;
98
    Button7: TButton;
98
    Button7: TButton;
99
    ActionOpen: TAction;
99
    ActionOpen: TAction;
100
    Button8: TButton;
100
    Button8: TButton;
101
    Button9: TButton;
101
    Button9: TButton;
102
    ActionFindPrev: TAction;
102
    ActionFindPrev: TAction;
103
    Timer1: TTimer;
103
    Timer1: TTimer;
104
    ActionSpaceToTab: TAction;
104
    ActionSpaceToTab: TAction;
105
    Button11: TButton;
105
    Button11: TButton;
106
    SynEditSearch1: TSynEditSearch;
106
    SynEditSearch1: TSynEditSearch;
107
    TreeView1: TTreeView;
107
    TreeView1: TTreeView;
108
    Splitter2: TSplitter;
108
    Splitter2: TSplitter;
109
    btnLint: TButton;
109
    btnLint: TButton;
110
    ActionLint: TAction;
110
    ActionLint: TAction;
111
    ImageList1: TImageList;
111
    ImageList1: TImageList;
112
    RunPopup: TPopupMenu;
112
    RunPopup: TPopupMenu;
113
    OpeninIDE1: TMenuItem;
113
    OpeninIDE1: TMenuItem;
114
    ActionRunConsole: TAction;
114
    ActionRunConsole: TAction;
115
    Runinconsole1: TMenuItem;
115
    Runinconsole1: TMenuItem;
116
    SavePopup: TPopupMenu;
116
    SavePopup: TPopupMenu;
117
    Saveas1: TMenuItem;
117
    Saveas1: TMenuItem;
118
    Save1: TMenuItem;
118
    Save1: TMenuItem;
119
    SaveDialog1: TSaveDialog;
119
    SaveDialog1: TSaveDialog;
120
    BtnSpecialChars: TImage;
120
    BtnSpecialChars: TImage;
121
    BtnSpecialCharsOff: TImage;
121
    BtnSpecialCharsOff: TImage;
122
    BtnSpecialCharsOn: TImage;
122
    BtnSpecialCharsOn: TImage;
123
    BtnLightOn: TImage;
123
    BtnLightOn: TImage;
124
    BtnLightOff: TImage;
124
    BtnLightOff: TImage;
125
    BtnLight: TImage;
125
    BtnLight: TImage;
126
    StartUpTimer: TTimer;
126
    StartUpTimer: TTimer;
127
    FileModTimer: TTimer;
127
    FileModTimer: TTimer;
128
    GotoPHPdir1: TMenuItem;
128
    GotoPHPdir1: TMenuItem;
129
    PHPShell1: TMenuItem;
129
    PHPShell1: TMenuItem;
130
    ActionSaveAs: TAction;
130
    ActionSaveAs: TAction;
131
    ActionGoToPHPDir: TAction;
131
    ActionGoToPHPDir: TAction;
132
    ActionPHPInteractiveShell: TAction;
132
    ActionPHPInteractiveShell: TAction;
133
    procedure Run(Sender: TObject);
133
    procedure Run(Sender: TObject);
134
    procedure RunConsole(Sender: TObject);
134
    procedure RunConsole(Sender: TObject);
135
    procedure FormShow(Sender: TObject);
135
    procedure FormShow(Sender: TObject);
136
    procedure FormCreate(Sender: TObject);
136
    procedure FormCreate(Sender: TObject);
137
    procedure FormDestroy(Sender: TObject);
137
    procedure FormDestroy(Sender: TObject);
138
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
138
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
139
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
139
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
140
    procedure Memo2DblClick(Sender: TObject);
140
    procedure Memo2DblClick(Sender: TObject);
141
    (*
141
    (*
142
    {$IFDEF USE_SHDOCVW_TLB}
142
    {$IFDEF USE_SHDOCVW_TLB}
143
    *)
143
    *)
144
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
144
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
145
      const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
145
      const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
146
      Headers: OleVariant; var Cancel: WordBool);
146
      Headers: OleVariant; var Cancel: WordBool);
147
    (*
147
    (*
148
    {$ELSE}
148
    {$ELSE}
149
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
149
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
150
      const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
150
      const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
151
      Headers: OleVariant; var Cancel: WordBool);
151
      Headers: OleVariant; var Cancel: WordBool);
152
    {$ENDIF}
152
    {$ENDIF}
153
    *)
153
    *)
154
    procedure BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
154
    procedure BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
155
    procedure SynEditFocusTimerTimer(Sender: TObject);
155
    procedure SynEditFocusTimerTimer(Sender: TObject);
156
    procedure ActionFindExecute(Sender: TObject);
156
    procedure ActionFindExecute(Sender: TObject);
157
    procedure ActionReplaceExecute(Sender: TObject);
157
    procedure ActionReplaceExecute(Sender: TObject);
158
    procedure ActionFindNextExecute(Sender: TObject);
158
    procedure ActionFindNextExecute(Sender: TObject);
159
    procedure ActionGotoExecute(Sender: TObject);
159
    procedure ActionGotoExecute(Sender: TObject);
160
    procedure ActionSaveExecute(Sender: TObject);
160
    procedure ActionSaveExecute(Sender: TObject);
161
    procedure ActionHelpExecute(Sender: TObject);
161
    procedure ActionHelpExecute(Sender: TObject);
162
    procedure ActionRunExecute(Sender: TObject);
162
    procedure ActionRunExecute(Sender: TObject);
163
    procedure ActionESCExecute(Sender: TObject);
163
    procedure ActionESCExecute(Sender: TObject);
164
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
164
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
165
      MousePos: TPoint; var Handled: Boolean);
165
      MousePos: TPoint; var Handled: Boolean);
166
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
166
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
167
      MousePos: TPoint; var Handled: Boolean);
167
      MousePos: TPoint; var Handled: Boolean);
168
    procedure ActionOpenExecute(Sender: TObject);
168
    procedure ActionOpenExecute(Sender: TObject);
169
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
169
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
170
    procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
170
    procedure Memo2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
171
    procedure ActionFindPrevExecute(Sender: TObject);
171
    procedure ActionFindPrevExecute(Sender: TObject);
172
    procedure SynEdit1MouseCursor(Sender: TObject;
172
    procedure SynEdit1MouseCursor(Sender: TObject;
173
      const aLineCharPos: TBufferCoord; var aCursor: TCursor);
173
      const aLineCharPos: TBufferCoord; var aCursor: TCursor);
174
    procedure Timer1Timer(Sender: TObject);
174
    procedure Timer1Timer(Sender: TObject);
175
    procedure ActionSpaceToTabExecute(Sender: TObject);
175
    procedure ActionSpaceToTabExecute(Sender: TObject);
176
    procedure TreeView1DblClick(Sender: TObject);
176
    procedure TreeView1DblClick(Sender: TObject);
177
    procedure SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X, Y,
177
    procedure SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X, Y,
178
      Line: Integer; Mark: TSynEditMark);
178
      Line: Integer; Mark: TSynEditMark);
179
    procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
179
    procedure SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas;
180
      TransientType: TTransientType);
180
      TransientType: TTransientType);
181
    procedure ActionLintExecute(Sender: TObject);
181
    procedure ActionLintExecute(Sender: TObject);
182
    procedure ActionRunConsoleExecute(Sender: TObject);
182
    procedure ActionRunConsoleExecute(Sender: TObject);
183
    procedure SynEdit1Change(Sender: TObject);
183
    procedure SynEdit1Change(Sender: TObject);
184
    procedure BtnSpecialCharsClick(Sender: TObject);
184
    procedure BtnSpecialCharsClick(Sender: TObject);
185
    procedure WebBrowser1WindowClosing(ASender: TObject;
185
    procedure WebBrowser1WindowClosing(ASender: TObject;
186
      IsChildWindow: WordBool; var Cancel: WordBool);
186
      IsChildWindow: WordBool; var Cancel: WordBool);
187
    procedure BtnLightClick(Sender: TObject);
187
    procedure BtnLightClick(Sender: TObject);
188
    procedure StartUpTimerTimer(Sender: TObject);
188
    procedure StartUpTimerTimer(Sender: TObject);
189
    procedure FileModTimerTimer(Sender: TObject);
189
    procedure FileModTimerTimer(Sender: TObject);
190
    procedure SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
190
    procedure SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
191
      AFiles: TStrings);
191
      AFiles: TStrings);
192
    procedure ActionSaveAsExecute(Sender: TObject);
192
    procedure ActionSaveAsExecute(Sender: TObject);
193
    procedure ActionGoToPHPDirExecute(Sender: TObject);
193
    procedure ActionGoToPHPDirExecute(Sender: TObject);
194
    procedure ActionPHPInteractiveShellExecute(Sender: TObject);
194
    procedure ActionPHPInteractiveShellExecute(Sender: TObject);
195
  private
195
  private
196
    hMutex: THandle;
196
    hMutex: THandle;
197
    CurSearchTerm: string;
197
    CurSearchTerm: string;
198
    HlpPrevPageIndex: integer;
198
    HlpPrevPageIndex: integer;
199
    SrcRep: TSynEditFindReplace;
199
    SrcRep: TSynEditFindReplace;
200
    {$IFDEF OnlineHelp}
200
    {$IFDEF OnlineHelp}
201
    gOnlineHelpWord: string;
201
    gOnlineHelpWord: string;
202
    {$ENDIF}
202
    {$ENDIF}
203
    FileModLast: TDateTime;
203
    FileModLast: TDateTime;
204
    FormShowRanOnce: boolean;
204
    FormShowRanOnce: boolean;
205
    BrowserLoadedOnce: boolean;
205
    BrowserLoadedOnce: boolean;
206
    procedure Help;
206
    procedure Help;
207
    function InputRequestCallback(var data: AnsiString): boolean;
207
    function InputRequestCallback(var data: AnsiString): boolean;
208
    function OutputNotifyCallback(const data: AnsiString): boolean;
208
    function OutputNotifyCallback(const data: AnsiString): boolean;
209
    procedure RightTrimAll;
209
    procedure RightTrimAll;
210
  protected
210
  protected
211
    ChmIndex: TMemIniFile;
211
    ChmIndex: TMemIniFile;
212
    FScrapFile: string;
212
    FScrapFile: string;
213
    FSaveAsFilename: string;
213
    FSaveAsFilename: string;
214
    codeExplorer: TRunCodeExplorer;
214
    codeExplorer: TRunCodeExplorer;
215
    procedure GotoLineNo(LineNo: integer);
215
    procedure GotoLineNo(LineNo: integer);
216
    function GetScrapFile: string;
216
    function GetScrapFile: string;
217
    procedure StartCodeExplorer;
217
    procedure StartCodeExplorer;
218
    procedure RefreshModifySign;
218
    procedure RefreshModifySign;
219
    procedure Theme_Light;
219
    procedure Theme_Light;
220
    procedure Theme_Dark;
220
    procedure Theme_Dark;
221
    function IsThemeDark: boolean;
221
    function IsThemeDark: boolean;
222
    function MarkUpLineReference(cont: string): string;
222
    function MarkUpLineReference(cont: string): string;
223
    procedure SaveToFile(filename: string);
223
    procedure SaveToFile(filename: string);
224
  end;
224
  end;
225
 
225
 
226
var
226
var
227
  Form1: TForm1;
227
  Form1: TForm1;
228
 
228
 
229
implementation
229
implementation
230
 
230
 
231
{$R *.dfm}
231
{$R *.dfm}
232
 
232
 
233
{$R Cursors.res}
233
{$R Cursors.res}
234
 
234
 
235
uses
235
uses
236
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI, RichEdit,
236
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI, RichEdit,
237
  FastPHPTreeView, ImageListEx, FastPHPConfig;
237
  FastPHPTreeView, ImageListEx, FastPHPConfig;
238
 
238
 
239
const
239
const
240
  crMouseGutter = 1;
240
  crMouseGutter = 1;
241
 
241
 
242
procedure TForm1.RefreshModifySign;
242
procedure TForm1.RefreshModifySign;
243
var
243
var
244
  tmp: string;
244
  tmp: string;
245
begin
245
begin
246
  tmp := Caption;
246
  tmp := Caption;
247
 
247
 
248
  tmp := StringReplace(tmp, '*', '', [rfReplaceAll]);
248
  tmp := StringReplace(tmp, '*', '', [rfReplaceAll]);
249
  if SynEdit1.Modified then tmp := tmp + '*';
249
  if SynEdit1.Modified then tmp := tmp + '*';
250
 
250
 
251
  if Caption <> tmp then Caption := tmp;
251
  if Caption <> tmp then Caption := tmp;
252
end;
252
end;
253
 
253
 
254
procedure TForm1.ActionFindNextExecute(Sender: TObject);
254
procedure TForm1.ActionFindNextExecute(Sender: TObject);
255
begin
255
begin
256
  SrcRep.FindNext;
256
  SrcRep.FindNext;
257
end;
257
end;
258
 
258
 
259
procedure TForm1.ActionFindPrevExecute(Sender: TObject);
259
procedure TForm1.ActionFindPrevExecute(Sender: TObject);
260
begin
260
begin
261
  SrcRep.FindPrev;
261
  SrcRep.FindPrev;
262
end;
262
end;
263
 
263
 
264
procedure TForm1.ActionGotoExecute(Sender: TObject);
264
procedure TForm1.ActionGotoExecute(Sender: TObject);
265
var
265
var
266
  val: string;
266
  val: string;
267
  lineno: integer;
267
  lineno: integer;
268
resourcestring
268
resourcestring
269
  SGoTo = 'Go to';
269
  SGoTo = 'Go to';
270
  SLineNumber = 'Line number:';
270
  SLineNumber = 'Line number:';
271
begin
271
begin
272
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
272
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
273
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
273
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
274
 
274
 
275
  if not InputQuery(SGoTo, SLineNumber, val) or
275
  if not InputQuery(SGoTo, SLineNumber, val) or
276
     not TryStrToInt(val, lineno) then
276
     not TryStrToInt(val, lineno) then
277
  begin
277
  begin
278
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
278
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
279
    exit;
279
    exit;
280
  end;
280
  end;
281
  GotoLineNo(lineno);
281
  GotoLineNo(lineno);
282
end;
282
end;
283
 
283
 
284
procedure TForm1.ActionGoToPHPDirExecute(Sender: TObject);
284
procedure TForm1.ActionGoToPHPDirExecute(Sender: TObject);
285
var
285
var
286
  phpExe: string;
286
  phpExe: string;
287
begin
287
begin
288
  phpExe := GetPHPExe;
288
  phpExe := GetPHPExe;
289
  if phpExe <> '' then
289
  if phpExe <> '' then
290
    ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
290
    ShellExecute(Handle, 'open', 'explorer.exe', PChar(ExtractFilePath(phpExe)), '', SW_NORMAL);
291
end;
291
end;
292
 
292
 
293
procedure TForm1.ActionHelpExecute(Sender: TObject);
293
procedure TForm1.ActionHelpExecute(Sender: TObject);
294
begin
294
begin
295
  Help;
295
  Help;
296
  if PageControl2.ActivePage = HelpTabsheet then
296
  if PageControl2.ActivePage = HelpTabsheet then
297
    WebBrowser2.SetFocus
297
    WebBrowser2.SetFocus
298
  else if PageControl2.ActivePage = CodeTabsheet then
298
  else if PageControl2.ActivePage = CodeTabsheet then
299
    SynEdit1.SetFocus;
299
    SynEdit1.SetFocus;
300
end;
300
end;
301
 
301
 
302
procedure TForm1.ActionLintExecute(Sender: TObject);
302
procedure TForm1.ActionLintExecute(Sender: TObject);
303
begin
303
begin
304
  Run(Sender);
304
  Run(Sender);
305
  SynEdit1.SetFocus;
305
  SynEdit1.SetFocus;
306
end;
306
end;
307
 
307
 
308
procedure TForm1.ActionOpenExecute(Sender: TObject);
308
procedure TForm1.ActionOpenExecute(Sender: TObject);
309
begin
309
begin
310
  If OpenDialog3.Execute then
310
  If OpenDialog3.Execute then
311
  begin
311
  begin
312
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
312
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + OpenDialog3.FileName + '"'), '', SW_NORMAL);
313
  end;
313
  end;
314
end;
314
end;
315
 
315
 
316
procedure TForm1.ActionPHPInteractiveShellExecute(Sender: TObject);
316
procedure TForm1.ActionPHPInteractiveShellExecute(Sender: TObject);
317
var
317
var
318
  phpExe: string;
318
  phpExe: string;
319
begin
319
begin
320
  phpExe := GetPHPExe;
320
  phpExe := GetPHPExe;
321
  if phpExe <> '' then
321
  if phpExe <> '' then
322
    ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
322
    ShellExecute(Handle, 'open', PChar(phpExe), '-a', PChar(ExtractFilePath(phpExe)), SW_NORMAL);
323
end;
323
end;
324
 
324
 
325
procedure TForm1.ActionReplaceExecute(Sender: TObject);
325
procedure TForm1.ActionReplaceExecute(Sender: TObject);
326
begin
326
begin
327
  SrcRep.ReplaceExecute;
327
  SrcRep.ReplaceExecute;
328
end;
328
end;
329
 
329
 
330
procedure TForm1.ActionRunConsoleExecute(Sender: TObject);
330
procedure TForm1.ActionRunConsoleExecute(Sender: TObject);
331
begin
331
begin
332
  RunConsole(Sender);
332
  RunConsole(Sender);
333
  SynEdit1.SetFocus;
333
  SynEdit1.SetFocus;
334
end;
334
end;
335
 
335
 
336
procedure TForm1.ActionRunExecute(Sender: TObject);
336
procedure TForm1.ActionRunExecute(Sender: TObject);
337
begin
337
begin
338
  Run(Sender);
338
  Run(Sender);
339
  SynEdit1.SetFocus;
339
  SynEdit1.SetFocus;
340
end;
340
end;
341
 
341
 
342
procedure TForm1.RightTrimAll;
342
procedure TForm1.RightTrimAll;
343
var
343
var
344
  i: integer;
344
  i: integer;
345
begin
345
begin
346
  for i := 0 to SynEdit1.Lines.Count-1 do
346
  for i := 0 to SynEdit1.Lines.Count-1 do
347
  begin
347
  begin
348
    SynEdit1.Lines.Strings[i] := TrimRight(SynEdit1.Lines.Strings[i]);
348
    SynEdit1.Lines.Strings[i] := TrimRight(SynEdit1.Lines.Strings[i]);
349
  end;
349
  end;
350
 
350
 
351
  (*
351
  (*
352
  while (SynEdit1.Lines.Count > 0) and (SynEdit1.Lines.Strings[SynEdit1.Lines.Count-1] = '') do
352
  while (SynEdit1.Lines.Count > 0) and (SynEdit1.Lines.Strings[SynEdit1.Lines.Count-1] = '') do
353
  begin
353
  begin
354
    SynEdit1.Lines.Delete(SynEdit1.Lines.Count-1);
354
    SynEdit1.Lines.Delete(SynEdit1.Lines.Count-1);
355
  end;
355
  end;
356
  if SynEdit1.SelStart > Length(SynEdit1.Text)-1 then
356
  if SynEdit1.SelStart > Length(SynEdit1.Text)-1 then
357
  begin
357
  begin
358
    // TODO: This code does not work...
358
    // TODO: This code does not work...
359
    SynEdit1.SelStart := Length(SynEdit1.Text)-1;
359
    SynEdit1.SelStart := Length(SynEdit1.Text)-1;
360
    SynEdit1.SelEnd   := Length(SynEdit1.Text)-1;
360
    SynEdit1.SelEnd   := Length(SynEdit1.Text)-1;
361
  end;
361
  end;
362
  *)
362
  *)
363
end;
363
end;
364
 
364
 
365
procedure TForm1.ActionSaveAsExecute(Sender: TObject);
365
procedure TForm1.ActionSaveAsExecute(Sender: TObject);
366
var
366
var
367
  hMutexNew: THandle;
367
  hMutexNew: THandle;
368
resourcestring
368
resourcestring
369
  SCannotSaveBecauseMutex = 'Cannot save because file "%s", because it is alrady open in another FastPHP window!';
369
  SCannotSaveBecauseMutex = 'Cannot save because file "%s", because it is alrady open in another FastPHP window!';
370
begin
370
begin
371
  if SaveDialog1.Execute then
371
  if SaveDialog1.Execute then
372
  begin
372
  begin
373
    {$REGION 'Switch mutex'}
373
    {$REGION 'Switch mutex'}
374
    hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
374
    hMutexNew := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(SaveDialog1.FileName))));
375
    if GetLastError = ERROR_ALREADY_EXISTS then
375
    if GetLastError = ERROR_ALREADY_EXISTS then
376
    begin
376
    begin
377
      ShowMessageFmt(SCannotSaveBecauseMutex, [SaveDialog1.FileName]);
377
      ShowMessageFmt(SCannotSaveBecauseMutex, [SaveDialog1.FileName]);
378
      Close;
378
      Close;
379
    end;
379
    end;
380
 
380
 
381
    if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
381
    if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
382
    hMutex := hMutexNew;
382
    hMutex := hMutexNew;
383
    {$ENDREGION}
383
    {$ENDREGION}
384
 
384
 
385
    FSaveAsFilename := SaveDialog1.FileName;
385
    FSaveAsFilename := SaveDialog1.FileName;
386
    Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
386
    Caption := Copy(Caption, 1, Pos(' - ', Caption)-1) + ' - ' + FSaveAsFilename;
387
    Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]); // do not translate!
387
    Application.Title := Format('%s - FastPHP', [ExtractFileName(FSaveAsFilename)]); // do not translate!
388
    Button7.Click;
388
    Button7.Click;
389
  end;
389
  end;
390
end;
390
end;
391
 
391
 
392
procedure TForm1.ActionSaveExecute(Sender: TObject);
392
procedure TForm1.ActionSaveExecute(Sender: TObject);
393
begin
393
begin
394
  RightTrimAll;
394
  RightTrimAll;
395
  SaveToFile(GetScrapFile);
395
  SaveToFile(GetScrapFile);
396
  SynEdit1.Modified := false;
396
  SynEdit1.Modified := false;
397
  RefreshModifySign;
397
  RefreshModifySign;
398
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
398
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
399
end;
399
end;
400
 
400
 
401
procedure TForm1.ActionSpaceToTabExecute(Sender: TObject);
401
procedure TForm1.ActionSpaceToTabExecute(Sender: TObject);
402
 
402
 
403
    function SpacesAtBeginning(line: string): integer;
403
    function SpacesAtBeginning(line: string): integer;
404
    begin
404
    begin
405
      result := 0;
405
      result := 0;
406
      if Trim(line) = '' then exit;
406
      if Trim(line) = '' then exit;
407
      while line[result+1] = ' ' do
407
      while line[result+1] = ' ' do
408
      begin
408
      begin
409
        inc(result);
409
        inc(result);
410
      end;
410
      end;
411
    end;
411
    end;
412
 
412
 
413
    function GuessIndent(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): integer;
413
    function GuessIndent(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): integer;
414
      function _Check(indent: integer): boolean;
414
      function _Check(indent: integer): boolean;
415
      var
415
      var
416
        i: integer;
416
        i: integer;
417
      begin
417
      begin
418
        result := true;
418
        result := true;
419
        for i := 0 to lines.Count-1 do
419
        for i := 0 to lines.Count-1 do
420
          if SpacesAtBeginning(lines.Strings[i]) mod indent <> 0 then
420
          if SpacesAtBeginning(lines.Strings[i]) mod indent <> 0 then
421
          begin
421
          begin
422
            // ShowMessageFmt('Zeile "%s" nicht durch %d teilbar!', [lines.strings[i], indent]);
422
            // ShowMessageFmt('Zeile "%s" nicht durch %d teilbar!', [lines.strings[i], indent]);
423
            result := false;
423
            result := false;
424
            exit;
424
            exit;
425
          end;
425
          end;
426
      end;
426
      end;
427
    var
427
    var
428
      i: integer;
428
      i: integer;
429
    begin
429
    begin
430
      for i := 8 downto 2 do
430
      for i := 8 downto 2 do
431
      begin
431
      begin
432
        if _Check(i) then
432
        if _Check(i) then
433
        begin
433
        begin
434
          result := i;
434
          result := i;
435
          exit;
435
          exit;
436
        end;
436
        end;
437
      end;
437
      end;
438
      result := -1;
438
      result := -1;
439
    end;
439
    end;
440
 
440
 
441
    procedure SpaceToTab(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}; indent: integer);
441
    procedure SpaceToTab(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}; indent: integer);
442
    var
442
    var
443
      i, spaces: integer;
443
      i, spaces: integer;
444
      newval: string;
444
      newval: string;
445
      somethingchanged: boolean;
445
      somethingchanged: boolean;
446
    begin
446
    begin
447
      somethingchanged := false;
447
      somethingchanged := false;
448
      for i := 0 to lines.Count-1 do
448
      for i := 0 to lines.Count-1 do
449
      begin
449
      begin
450
        spaces := SpacesAtBeginning(lines.Strings[i]);
450
        spaces := SpacesAtBeginning(lines.Strings[i]);
451
        newval := StringOfChar(#9, spaces div indent) + StringOfChar(' ', spaces mod indent) + Copy(lines.Strings[i], spaces+1, Length(lines.Strings[i])-spaces);
451
        newval := StringOfChar(#9, spaces div indent) + StringOfChar(' ', spaces mod indent) + Copy(lines.Strings[i], spaces+1, Length(lines.Strings[i])-spaces);
452
        if lines.Strings[i] <> newval then
452
        if lines.Strings[i] <> newval then
453
        begin
453
        begin
454
          somethingchanged := true;
454
          somethingchanged := true;
455
          lines.Strings[i] := newval;
455
          lines.Strings[i] := newval;
456
        end;
456
        end;
457
      end;
457
      end;
458
      if somethingchanged then
458
      if somethingchanged then
459
      begin
459
      begin
460
        SynEdit1Change(SynEdit1); // set the "changed" flag
460
        SynEdit1Change(SynEdit1); // set the "changed" flag
461
      end;
461
      end;
462
    end;
462
    end;
463
 
463
 
464
    function SpacesAvailable(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): boolean;
464
    function SpacesAvailable(lines: {$IFDEF UNICODE}TStrings{$ELSE}TUnicodeStrings{$ENDIF}): boolean;
465
    var
465
    var
466
      i, spaces: integer;
466
      i, spaces: integer;
467
    begin
467
    begin
468
      for i := 0 to lines.Count-1 do
468
      for i := 0 to lines.Count-1 do
469
      begin
469
      begin
470
        spaces := SpacesAtBeginning(lines.Strings[i]);
470
        spaces := SpacesAtBeginning(lines.Strings[i]);
471
        if spaces > 0 then
471
        if spaces > 0 then
472
        begin
472
        begin
473
          result := true;
473
          result := true;
474
          exit;
474
          exit;
475
        end;
475
        end;
476
      end;
476
      end;
477
      result := false;
477
      result := false;
478
      exit;
478
      exit;
479
    end;
479
    end;
480
 
480
 
481
var
481
var
482
  val: string;
482
  val: string;
483
  ind: integer;
483
  ind: integer;
484
resourcestring
484
resourcestring
485
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
485
  SNoLinesAvailable = 'No lines with spaces at the beginning available';
486
  SSpacesToLabs = 'Spaces to tabs';
486
  SSpacesToLabs = 'Spaces to tabs';
487
  SIndent = 'Indent:';
487
  SIndent = 'Indent:';
488
begin
488
begin
489
  // TODO: if something is selected, only process the selected part
489
  // TODO: if something is selected, only process the selected part
490
 
490
 
491
  if not SpacesAvailable(SynEdit1.Lines) then
491
  if not SpacesAvailable(SynEdit1.Lines) then
492
  begin
492
  begin
493
    MessageDlg(SNoLinesAvailable, mtInformation, [mbOk], 0);
493
    MessageDlg(SNoLinesAvailable, mtInformation, [mbOk], 0);
494
    exit;
494
    exit;
495
  end;
495
  end;
496
 
496
 
497
  ind := GuessIndent(SynEdit1.Lines);
497
  ind := GuessIndent(SynEdit1.Lines);
498
  if ind <> -1 then val := IntToStr(ind);
498
  if ind <> -1 then val := IntToStr(ind);
499
 
499
 
500
  if not InputQuery(SSpacesToLabs, SIndent, val) or
500
  if not InputQuery(SSpacesToLabs, SIndent, val) or
501
     not TryStrToInt(Trim(val), ind) then
501
     not TryStrToInt(Trim(val), ind) then
502
  begin
502
  begin
503
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
503
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
504
    exit;
504
    exit;
505
  end;
505
  end;
506
 
506
 
507
  if ind = 0 then exit;
507
  if ind = 0 then exit;
508
  SpaceToTab(SynEdit1.Lines, ind);
508
  SpaceToTab(SynEdit1.Lines, ind);
509
end;
509
end;
510
 
510
 
511
procedure TForm1.ActionESCExecute(Sender: TObject);
511
procedure TForm1.ActionESCExecute(Sender: TObject);
512
begin
512
begin
513
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
513
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
514
     (HelpTabsheet.TabVisible) then
514
     (HelpTabsheet.TabVisible) then
515
  begin
515
  begin
516
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
516
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
517
    HelpTabsheet.TabVisible := false;
517
    HelpTabsheet.TabVisible := false;
518
  end;
518
  end;
519
 
519
 
520
  // Dirty hack...
520
  // Dirty hack...
521
  SrcRep.CloseDialogs;
521
  SrcRep.CloseDialogs;
522
end;
522
end;
523
 
523
 
524
procedure TForm1.ActionFindExecute(Sender: TObject);
524
procedure TForm1.ActionFindExecute(Sender: TObject);
525
begin
525
begin
526
  SrcRep.FindExecute;
526
  SrcRep.FindExecute;
527
end;
527
end;
528
 
528
 
529
procedure TForm1.Run(Sender: TObject);
529
procedure TForm1.Run(Sender: TObject);
530
var
530
var
531
  bakTS: TTabSheet;
531
  bakTS: TTabSheet;
532
  //ss: TStringStream;
532
  //ss: TStringStream;
533
  //bakPos: Int64;
533
  //bakPos: Int64;
534
begin
534
begin
535
  memo2.Lines.Text := '';
535
  memo2.Lines.Text := '';
536
 
536
 
537
  if not BrowserLoadedOnce then
537
  if not BrowserLoadedOnce then
538
  begin
538
  begin
539
    bakTS := PageControl1.ActivePage;
539
    bakTS := PageControl1.ActivePage;
540
    try
540
    try
541
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
541
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
542
      Webbrowser1.Clear;
542
      Webbrowser1.Clear;
543
    finally
543
    finally
544
      PageControl1.ActivePage := bakTS;
544
      PageControl1.ActivePage := bakTS;
545
    end;
545
    end;
546
    BrowserLoadedOnce := true;
546
    BrowserLoadedOnce := true;
547
  end
547
  end
548
  else
548
  else
549
    Webbrowser1.Clear;
549
    Webbrowser1.Clear;
550
 
550
 
551
  Screen.Cursor := crHourGlass; // TODO: Doesn't work with F9
551
  Screen.Cursor := crHourGlass; // TODO: Doesn't work with F9
552
  Application.ProcessMessages;
552
  Application.ProcessMessages;
553
 
553
 
554
  try
554
  try
555
    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.
555
    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.
556
 
556
 
557
    // TODO 70421 * <fastphp> flush() mittels ContentCallBack implementieren... ich möchte bei langen scripts statusanzeigen realisieren können mit javascript das stück für stück geladen wird !!!!!!!!
557
    // TODO 70421 * <fastphp> implement flush() with ContentCallBack implementieren... For long running scripts I want to see status changes via javascript which are loaded step by step
558
    // TODO 70422 * <fastphp> wenn ein script hängt, soll man es abwürgen dürfen!!!!!!
558
    // TODO 70422 * <fastphp> when a script has an endless loop, i want to have a possibility to cancel it
-
 
559
    if SynEdit1.Lines.Encoding = TEncoding.UTF8 then
-
 
560
      memo2.Lines.Text := Utf8Decode(RunPHPScript(GetScrapFile, Sender=ActionLint, False)) // if we have a UTF-8 file, then the DOS output is double-UTF8 encoded
-
 
561
    else
559
    memo2.Lines.Text := RunPHPScript(GetScrapFile, Sender=ActionLint, False);
562
      memo2.Lines.Text := RunPHPScript(GetScrapFile, Sender=ActionLint, False);
560
 
563
 
561
    {$REGION 'Show in Web Browser'}
564
    {$REGION 'Show in Web Browser'}
-
 
565
    if SynEdit1.Lines.Encoding = TEncoding.UTF8 then
-
 
566
      Webbrowser1.LoadHTML(MarkUpLineReference('<meta charset="utf-8">'+memo2.Lines.Text), GetScrapFile)
-
 
567
    else
562
    Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
568
      Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
563
 
569
 
564
    // Alternatively:
570
    // Alternatively:
565
    (*
571
    (*
566
    ss := TstringStream.Create;
572
    ss := TstringStream.Create;
567
    ss.WriteString(MarkUpLineReference(memo2.Lines.Text));
573
    ss.WriteString(MarkUpLineReference(memo2.Lines.Text));
568
    ss.Position := 0;
574
    ss.Position := 0;
569
    Webbrowser1.LoadStream(ss, GetScrapFile);
575
    Webbrowser1.LoadStream(ss, GetScrapFile);
570
    Webbrowser1.Wait;
576
    Webbrowser1.Wait;
571
    ss.Free;
577
    ss.Free;
572
    *)
578
    *)
573
    {$ENDREGION}
579
    {$ENDREGION}
574
 
580
 
575
    if IsTextHTML(memo2.lines.text) then
581
    if IsTextHTML(memo2.lines.text) then
576
      PageControl1.ActivePage := HtmlTabSheet
582
      PageControl1.ActivePage := HtmlTabSheet
577
    else
583
    else
578
      PageControl1.ActivePage := PlaintextTabSheet;
584
      PageControl1.ActivePage := PlaintextTabSheet;
579
  finally
585
  finally
580
    Screen.Cursor := crDefault;
586
    Screen.Cursor := crDefault;
581
  end;
587
  end;
582
end;
588
end;
583
 
589
 
584
procedure TForm1.RunConsole(Sender: TObject);
590
procedure TForm1.RunConsole(Sender: TObject);
585
begin
591
begin
586
  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.
592
  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.
587
  RunPHPScript(GetScrapFile, Sender=ActionLint, True);
593
  RunPHPScript(GetScrapFile, Sender=ActionLint, True);
588
end;
594
end;
589
 
595
 
590
procedure TForm1.SynEdit1Change(Sender: TObject);
596
procedure TForm1.SynEdit1Change(Sender: TObject);
591
begin
597
begin
592
  RefreshModifySign;
598
  RefreshModifySign;
593
end;
599
end;
594
 
600
 
595
procedure TForm1.SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
601
procedure TForm1.SynEdit1DropFiles(Sender: TObject; X, Y: Integer;
596
  AFiles: TStrings);
602
  AFiles: TStrings);
597
var
603
var
598
  FileName: string;
604
  FileName: string;
599
const
605
const
600
  WARN_FILE_COUNT = 10;
606
  WARN_FILE_COUNT = 10;
601
resourcestring
607
resourcestring
602
  SAreYouSure = 'Are you sure you want to open %d files?';
608
  SAreYouSure = 'Are you sure you want to open %d files?';
603
begin
609
begin
604
  if AFiles.Count > WARN_FILE_COUNT then
610
  if AFiles.Count > WARN_FILE_COUNT then
605
  begin
611
  begin
606
    if not MessageDlg(Format(SAreYouSure, [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
612
    if not MessageDlg(Format(SAreYouSure, [WARN_FILE_COUNT]), mtConfirmation, mbYesNoCancel, 0) <> mrYes then
607
      exit;
613
      exit;
608
  end;
614
  end;
609
 
615
 
610
  for FileName in AFiles do
616
  for FileName in AFiles do
611
  begin
617
  begin
612
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + FileName + '"'), '', SW_NORMAL);
618
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar('"' + FileName + '"'), '', SW_NORMAL);
613
  end;
619
  end;
614
end;
620
end;
615
 
621
 
616
procedure TForm1.SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X,
622
procedure TForm1.SynEdit1GutterClick(Sender: TObject; Button: TMouseButton; X,
617
  Y, Line: Integer; Mark: TSynEditMark);
623
  Y, Line: Integer; Mark: TSynEditMark);
618
begin
624
begin
619
  (*
625
  (*
620
  TSynEdit(Sender).CaretX := 1;
626
  TSynEdit(Sender).CaretX := 1;
621
  TSynEdit(Sender).CaretY := Line;
627
  TSynEdit(Sender).CaretY := Line;
622
  TSynEdit(Sender).SelLength := Length(TSynEdit(Sender).LineText);
628
  TSynEdit(Sender).SelLength := Length(TSynEdit(Sender).LineText);
623
  *)
629
  *)
624
end;
630
end;
625
 
631
 
626
procedure TForm1.SynEdit1MouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; var aCursor: TCursor);
632
procedure TForm1.SynEdit1MouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; var aCursor: TCursor);
627
{$IFDEF OnlineHelp}
633
{$IFDEF OnlineHelp}
628
var
634
var
629
  Line: Integer;
635
  Line: Integer;
630
  Column: Integer;
636
  Column: Integer;
631
  word: string;
637
  word: string;
632
begin
638
begin
633
  Line  := aLineCharPos.Line-1;
639
  Line  := aLineCharPos.Line-1;
634
  Column := aLineCharPos.Char-1;
640
  Column := aLineCharPos.Char-1;
635
  word := GetWordUnderPos(TSynEdit(Sender), Line, Column);
641
  word := GetWordUnderPos(TSynEdit(Sender), Line, Column);
636
  if word <> gOnlineHelpWord then
642
  if word <> gOnlineHelpWord then
637
  begin
643
  begin
638
    gOnlineHelpWord := word;
644
    gOnlineHelpWord := word;
639
    Timer1.Enabled := false;
645
    Timer1.Enabled := false;
640
    Timer1.Enabled := true;
646
    Timer1.Enabled := true;
641
  end;
647
  end;
642
{$ELSE}
648
{$ELSE}
643
begin
649
begin
644
{$ENDIF}
650
{$ENDIF}
645
end;
651
end;
646
 
652
 
647
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
653
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
648
  MousePos: TPoint; var Handled: Boolean);
654
  MousePos: TPoint; var Handled: Boolean);
649
begin
655
begin
650
  if ssCtrl in Shift then
656
  if ssCtrl in Shift then
651
  begin
657
  begin
652
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
658
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
653
    Handled := true;
659
    Handled := true;
654
  end
660
  end
655
  else Handled := false;
661
  else Handled := false;
656
end;
662
end;
657
 
663
 
658
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
664
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
659
  MousePos: TPoint; var Handled: Boolean);
665
  MousePos: TPoint; var Handled: Boolean);
660
begin
666
begin
661
  if ssCtrl in Shift then
667
  if ssCtrl in Shift then
662
  begin
668
  begin
663
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
669
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
664
    Handled := true;
670
    Handled := true;
665
  end
671
  end
666
  else Handled := false;
672
  else Handled := false;
667
end;
673
end;
668
 
674
 
669
procedure TForm1.SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
675
procedure TForm1.SynEdit1PaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
670
var
676
var
671
  Editor: TSynEdit;
677
  Editor: TSynEdit;
672
  OpenChars: array of WideChar;//[0..2] of WideChar=();
678
  OpenChars: array of WideChar;//[0..2] of WideChar=();
673
  CloseChars: array of WideChar;//[0..2] of WideChar=();
679
  CloseChars: array of WideChar;//[0..2] of WideChar=();
674
 
680
 
675
  function IsCharBracket(AChar: WideChar): Boolean;
681
  function IsCharBracket(AChar: WideChar): Boolean;
676
  begin
682
  begin
677
    case AChar of
683
    case AChar of
678
      '{','[','(','<','}',']',')','>':
684
      '{','[','(','<','}',']',')','>':
679
        Result := True;
685
        Result := True;
680
      else
686
      else
681
        Result := False;
687
        Result := False;
682
    end;
688
    end;
683
  end;
689
  end;
684
 
690
 
685
  function CharToPixels(P: TBufferCoord): TPoint;
691
  function CharToPixels(P: TBufferCoord): TPoint;
686
  begin
692
  begin
687
    Result := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
693
    Result := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
688
  end;
694
  end;
689
 
695
 
690
var
696
var
691
  COLOR_FG: TColor;
697
  COLOR_FG: TColor;
692
  COLOR_BG: TColor;
698
  COLOR_BG: TColor;
693
  P: TBufferCoord;
699
  P: TBufferCoord;
694
  Pix: TPoint;
700
  Pix: TPoint;
695
  D: TDisplayCoord;
701
  D: TDisplayCoord;
696
  S: UnicodeString;
702
  S: UnicodeString;
697
  I: Integer;
703
  I: Integer;
698
  Attri: TSynHighlighterAttributes;
704
  Attri: TSynHighlighterAttributes;
699
  ArrayLength: Integer;
705
  ArrayLength: Integer;
700
  start: Integer;
706
  start: Integer;
701
  TmpCharA, TmpCharB: WideChar;
707
  TmpCharA, TmpCharB: WideChar;
702
begin
708
begin
703
  // Source: https://github.com/SynEdit/SynEdit/blob/master/Demos/OnPaintTransientDemo/Unit1.pas
709
  // Source: https://github.com/SynEdit/SynEdit/blob/master/Demos/OnPaintTransientDemo/Unit1.pas
704
 
710
 
705
  if IsThemeDark then
711
  if IsThemeDark then
706
  begin
712
  begin
707
    COLOR_FG := clLime;
713
    COLOR_FG := clLime;
708
    COLOR_BG := clGreen;
714
    COLOR_BG := clGreen;
709
  end
715
  end
710
  else
716
  else
711
  begin
717
  begin
712
    COLOR_FG := clGreen;
718
    COLOR_FG := clGreen;
713
    COLOR_BG := clLime;
719
    COLOR_BG := clLime;
714
  end;
720
  end;
715
 
721
 
716
  if TSynEdit(Sender).SelAvail then exit;
722
  if TSynEdit(Sender).SelAvail then exit;
717
  Editor := TSynEdit(Sender);
723
  Editor := TSynEdit(Sender);
718
  ArrayLength:= 3;
724
  ArrayLength:= 3;
719
 
725
 
720
  (*
726
  (*
721
  if (Editor.Highlighter = shHTML) or (Editor.Highlighter = shXML) then
727
  if (Editor.Highlighter = shHTML) or (Editor.Highlighter = shXML) then
722
    inc(ArrayLength);
728
    inc(ArrayLength);
723
  *)
729
  *)
724
 
730
 
725
  SetLength(OpenChars, ArrayLength);
731
  SetLength(OpenChars, ArrayLength);
726
  SetLength(CloseChars, ArrayLength);
732
  SetLength(CloseChars, ArrayLength);
727
  for i := 0 to ArrayLength - 1 do
733
  for i := 0 to ArrayLength - 1 do
728
  begin
734
  begin
729
    case i of
735
    case i of
730
      0: begin OpenChars[i] := '('; CloseChars[i] := ')'; end;
736
      0: begin OpenChars[i] := '('; CloseChars[i] := ')'; end;
731
      1: begin OpenChars[i] := '{'; CloseChars[i] := '}'; end;
737
      1: begin OpenChars[i] := '{'; CloseChars[i] := '}'; end;
732
      2: begin OpenChars[i] := '['; CloseChars[i] := ']'; end;
738
      2: begin OpenChars[i] := '['; CloseChars[i] := ']'; end;
733
      3: begin OpenChars[i] := '<'; CloseChars[i] := '>'; end;
739
      3: begin OpenChars[i] := '<'; CloseChars[i] := '>'; end;
734
    end;
740
    end;
735
  end;
741
  end;
736
 
742
 
737
  P := Editor.CaretXY;
743
  P := Editor.CaretXY;
738
  D := Editor.DisplayXY;
744
  D := Editor.DisplayXY;
739
 
745
 
740
  Start := Editor.SelStart;
746
  Start := Editor.SelStart;
741
 
747
 
742
  if (Start > 0) and (Start <= length(Editor.Text)) then
748
  if (Start > 0) and (Start <= length(Editor.Text)) then
743
    TmpCharA := Editor.Text[Start]
749
    TmpCharA := Editor.Text[Start]
744
  else
750
  else
745
    TmpCharA := #0;
751
    TmpCharA := #0;
746
 
752
 
747
  if (Start > 0){Added by VTS} and (Start < length(Editor.Text)) then
753
  if (Start > 0){Added by VTS} and (Start < length(Editor.Text)) then
748
    TmpCharB := Editor.Text[Start + 1]
754
    TmpCharB := Editor.Text[Start + 1]
749
  else
755
  else
750
    TmpCharB := #0;
756
    TmpCharB := #0;
751
 
757
 
752
  if not IsCharBracket(TmpCharA) and not IsCharBracket(TmpCharB) then exit;
758
  if not IsCharBracket(TmpCharA) and not IsCharBracket(TmpCharB) then exit;
753
  S := TmpCharB;
759
  S := TmpCharB;
754
  if not IsCharBracket(TmpCharB) then
760
  if not IsCharBracket(TmpCharB) then
755
  begin
761
  begin
756
    P.Char := P.Char - 1;
762
    P.Char := P.Char - 1;
757
    S := TmpCharA;
763
    S := TmpCharA;
758
  end;
764
  end;
759
  Editor.GetHighlighterAttriAtRowCol(P, S, Attri);
765
  Editor.GetHighlighterAttriAtRowCol(P, S, Attri);
760
 
766
 
761
  if (Editor.Highlighter.SymbolAttribute = Attri) then
767
  if (Editor.Highlighter.SymbolAttribute = Attri) then
762
  begin
768
  begin
763
    for i := low(OpenChars) to High(OpenChars) do
769
    for i := low(OpenChars) to High(OpenChars) do
764
    begin
770
    begin
765
      if (S = OpenChars[i]) or (S = CloseChars[i]) then
771
      if (S = OpenChars[i]) or (S = CloseChars[i]) then
766
      begin
772
      begin
767
        Pix := CharToPixels(P);
773
        Pix := CharToPixels(P);
768
 
774
 
769
        Editor.Canvas.Brush.Style := bsSolid;//Clear;
775
        Editor.Canvas.Brush.Style := bsSolid;//Clear;
770
        Editor.Canvas.Font.Assign(Editor.Font);
776
        Editor.Canvas.Font.Assign(Editor.Font);
771
        Editor.Canvas.Font.Style := Attri.Style;
777
        Editor.Canvas.Font.Style := Attri.Style;
772
 
778
 
773
        if (TransientType = ttAfter) then
779
        if (TransientType = ttAfter) then
774
        begin
780
        begin
775
          Editor.Canvas.Font.Color := COLOR_FG;
781
          Editor.Canvas.Font.Color := COLOR_FG;
776
          Editor.Canvas.Brush.Color := COLOR_BG;
782
          Editor.Canvas.Brush.Color := COLOR_BG;
777
        end
783
        end
778
        else
784
        else
779
        begin
785
        begin
780
          Editor.Canvas.Font.Color := Attri.Foreground;
786
          Editor.Canvas.Font.Color := Attri.Foreground;
781
          Editor.Canvas.Brush.Color := Attri.Background;
787
          Editor.Canvas.Brush.Color := Attri.Background;
782
        end;
788
        end;
783
        if Editor.Canvas.Font.Color = clNone then
789
        if Editor.Canvas.Font.Color = clNone then
784
          Editor.Canvas.Font.Color := Editor.Font.Color;
790
          Editor.Canvas.Font.Color := Editor.Font.Color;
785
        if Editor.Canvas.Brush.Color = clNone then
791
        if Editor.Canvas.Brush.Color = clNone then
786
          Editor.Canvas.Brush.Color := Editor.Color;
792
          Editor.Canvas.Brush.Color := Editor.Color;
787
 
793
 
788
        Editor.Canvas.TextOut(Pix.X, Pix.Y, S);
794
        Editor.Canvas.TextOut(Pix.X, Pix.Y, S);
789
        P := Editor.GetMatchingBracketEx(P);
795
        P := Editor.GetMatchingBracketEx(P);
790
 
796
 
791
        if (P.Char > 0) and (P.Line > 0) then
797
        if (P.Char > 0) and (P.Line > 0) then
792
        begin
798
        begin
793
          Pix := CharToPixels(P);
799
          Pix := CharToPixels(P);
794
          if Pix.X > Editor.Gutter.Width then
800
          if Pix.X > Editor.Gutter.Width then
795
          begin
801
          begin
796
            {$REGION 'Added by ViaThinkSoft'}
802
            {$REGION 'Added by ViaThinkSoft'}
797
            if (TransientType = ttAfter) then
803
            if (TransientType = ttAfter) then
798
            begin
804
            begin
799
              Editor.Canvas.Font.Color := COLOR_FG;
805
              Editor.Canvas.Font.Color := COLOR_FG;
800
              Editor.Canvas.Brush.Color := COLOR_BG;
806
              Editor.Canvas.Brush.Color := COLOR_BG;
801
            end
807
            end
802
            else
808
            else
803
            begin
809
            begin
804
              Editor.Canvas.Font.Color := Attri.Foreground;
810
              Editor.Canvas.Font.Color := Attri.Foreground;
805
              Editor.Canvas.Brush.Color := Attri.Background;
811
              Editor.Canvas.Brush.Color := Attri.Background;
806
            end;
812
            end;
807
            if Editor.Canvas.Font.Color = clNone then
813
            if Editor.Canvas.Font.Color = clNone then
808
              Editor.Canvas.Font.Color := Editor.Font.Color;
814
              Editor.Canvas.Font.Color := Editor.Font.Color;
809
            if Editor.Canvas.Brush.Color = clNone then
815
            if Editor.Canvas.Brush.Color = clNone then
810
              Editor.Canvas.Brush.Color := Editor.Color;
816
              Editor.Canvas.Brush.Color := Editor.Color;
811
            {$ENDREGION}
817
            {$ENDREGION}
812
            if S = OpenChars[i] then
818
            if S = OpenChars[i] then
813
              Editor.Canvas.TextOut(Pix.X, Pix.Y, CloseChars[i])
819
              Editor.Canvas.TextOut(Pix.X, Pix.Y, CloseChars[i])
814
            else Editor.Canvas.TextOut(Pix.X, Pix.Y, OpenChars[i]);
820
            else Editor.Canvas.TextOut(Pix.X, Pix.Y, OpenChars[i]);
815
          end;
821
          end;
816
        end;
822
        end;
817
      end;
823
      end;
818
    end;
824
    end;
819
    Editor.Canvas.Brush.Style := bsSolid;
825
    Editor.Canvas.Brush.Style := bsSolid;
820
  end;
826
  end;
821
end;
827
end;
822
 
828
 
823
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
829
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
824
begin
830
begin
825
  SynEditFocusTimer.Enabled := false;
831
  SynEditFocusTimer.Enabled := false;
826
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
832
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
827
  SynEdit1.SetFocus;
833
  SynEdit1.SetFocus;
828
end;
834
end;
829
 
835
 
830
procedure TForm1.Theme_Dark;
836
procedure TForm1.Theme_Dark;
831
begin
837
begin
832
  if IsThemeDark then exit;
838
  if IsThemeDark then exit;
833
  TStyleManager.TrySetStyle('Windows10 SlateGray'); // do not translate
839
  TStyleManager.TrySetStyle('Windows10 SlateGray'); // do not translate
834
  Color := 1316887;
840
  Color := 1316887;
835
  Font.Color := clCream;
841
  Font.Color := clCream;
836
  //Memo2.Font.Color := clCream;
842
  //Memo2.Font.Color := clCream;
837
  //Memo2.ParentColor := true;
843
  //Memo2.ParentColor := true;
838
  SynEdit1.ActiveLineColor := 2238502;
844
  SynEdit1.ActiveLineColor := 2238502;
839
  SynEdit1.Color := 1316887;
845
  SynEdit1.Color := 1316887;
840
  SynEdit1.Font.Color := clCream;
846
  SynEdit1.Font.Color := clCream;
841
  SynEdit1.Gutter.Color := 1316887;
847
  SynEdit1.Gutter.Color := 1316887;
842
  SynEdit1.Gutter.Font.Color := clCream;
848
  SynEdit1.Gutter.Font.Color := clCream;
843
  SynEdit1.Gutter.GradientStartColor := 2238502;
849
  SynEdit1.Gutter.GradientStartColor := 2238502;
844
  SynEdit1.Gutter.GradientEndColor := 1316887;
850
  SynEdit1.Gutter.GradientEndColor := 1316887;
845
  SynPHPSyn1.CommentAttri.Foreground := $00837B82;
851
  SynPHPSyn1.CommentAttri.Foreground := $00837B82;
846
  SynPHPSyn1.IdentifierAttri.Foreground := 9627120;
852
  SynPHPSyn1.IdentifierAttri.Foreground := 9627120;
847
  SynPHPSyn1.KeyAttri.Foreground := 4157595;
853
  SynPHPSyn1.KeyAttri.Foreground := 4157595;
848
  SynPHPSyn1.NumberAttri.Foreground := 5008079;
854
  SynPHPSyn1.NumberAttri.Foreground := 5008079;
849
  SynPHPSyn1.StringAttri.Foreground := 6987151;
855
  SynPHPSyn1.StringAttri.Foreground := 6987151;
850
  SynPHPSyn1.SymbolAttri.Foreground := 8769754;
856
  SynPHPSyn1.SymbolAttri.Foreground := 8769754;
851
  SynPHPSyn1.VariableAttri.Foreground := 6924493;
857
  SynPHPSyn1.VariableAttri.Foreground := 6924493;
852
end;
858
end;
853
 
859
 
854
procedure TForm1.Theme_Light;
860
procedure TForm1.Theme_Light;
855
begin
861
begin
856
  if not IsThemeDark then exit;
862
  if not IsThemeDark then exit;
857
  TStyleManager.TrySetStyle('Windows'); // do not translate
863
  TStyleManager.TrySetStyle('Windows'); // do not translate
858
  Color := clBtnFace;
864
  Color := clBtnFace;
859
  Font.Color := clWindowText;
865
  Font.Color := clWindowText;
860
  //Memo2.Font.Color := clWindowText;
866
  //Memo2.Font.Color := clWindowText;
861
  SynEdit1.ActiveLineColor := 14680010;
867
  SynEdit1.ActiveLineColor := 14680010;
862
  SynEdit1.Color := clCream;
868
  SynEdit1.Color := clCream;
863
  SynEdit1.Font.Color := clWindowText;
869
  SynEdit1.Font.Color := clWindowText;
864
  SynEdit1.Gutter.Color := clBtnFace;
870
  SynEdit1.Gutter.Color := clBtnFace;
865
  SynEdit1.Gutter.Font.Color := clWindowText;
871
  SynEdit1.Gutter.Font.Color := clWindowText;
866
  SynEdit1.Gutter.GradientStartcolor := cl3dLight;
872
  SynEdit1.Gutter.GradientStartcolor := cl3dLight;
867
  SynEdit1.Gutter.GradientEndColor := clBtnFace;;
873
  SynEdit1.Gutter.GradientEndColor := clBtnFace;;
868
  SynPHPSyn1.CommentAttri.Foreground := 33023;
874
  SynPHPSyn1.CommentAttri.Foreground := 33023;
869
  SynPHPSyn1.IdentifierAttri.Foreground := 4194304;
875
  SynPHPSyn1.IdentifierAttri.Foreground := 4194304;
870
  SynPHPSyn1.KeyAttri.Foreground := 4227072;
876
  SynPHPSyn1.KeyAttri.Foreground := 4227072;
871
  SynPHPSyn1.NumberAttri.Foreground := 213;
877
  SynPHPSyn1.NumberAttri.Foreground := 213;
872
  SynPHPSyn1.StringAttri.Foreground := 13762560;
878
  SynPHPSyn1.StringAttri.Foreground := 13762560;
873
  SynPHPSyn1.SymbolAttri.Foreground := 4227072;
879
  SynPHPSyn1.SymbolAttri.Foreground := 4227072;
874
  SynPHPSyn1.VariableAttri.Foreground := 213;
880
  SynPHPSyn1.VariableAttri.Foreground := 213;
875
end;
881
end;
876
 
882
 
877
procedure TForm1.Timer1Timer(Sender: TObject);
883
procedure TForm1.Timer1Timer(Sender: TObject);
878
begin
884
begin
879
  {$IFDEF OnlineHelp}
885
  {$IFDEF OnlineHelp}
880
  Timer1.Enabled := false;
886
  Timer1.Enabled := false;
881
 
887
 
882
  // TODO: Insert a small online help hint
888
  // TODO: Insert a small online help hint
883
  //Caption := gOnlineHelpWord;
889
  //Caption := gOnlineHelpWord;
884
  {$ENDIF}
890
  {$ENDIF}
885
end;
891
end;
886
 
892
 
887
procedure TForm1.TreeView1DblClick(Sender: TObject);
893
procedure TForm1.TreeView1DblClick(Sender: TObject);
888
var
894
var
889
  tn: TTreeNode;
895
  tn: TTreeNode;
890
  lineNo: integer;
896
  lineNo: integer;
891
begin
897
begin
892
  tn := TTreeView(Sender).Selected;
898
  tn := TTreeView(Sender).Selected;
893
  if tn = nil then exit;
899
  if tn = nil then exit;
894
  lineNo := Integer(tn.Data);
900
  lineNo := Integer(tn.Data);
895
  if lineNo > 0 then GotoLineNo(lineNo);
901
  if lineNo > 0 then GotoLineNo(lineNo);
896
end;
902
end;
897
 
903
 
898
(*
904
(*
899
{$IFDEF USE_SHDOCVW_TLB}
905
{$IFDEF USE_SHDOCVW_TLB}
900
*)
906
*)
901
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
907
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
902
  const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
908
  const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
903
  Headers: OleVariant; var Cancel: WordBool);
909
  Headers: OleVariant; var Cancel: WordBool);
904
begin
910
begin
905
  BeforeNavigate(URL, Cancel);
911
  BeforeNavigate(URL, Cancel);
906
end;
912
end;
907
(*
913
(*
908
{$ELSE}
914
{$ELSE}
909
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
915
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
910
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
916
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
911
  Headers: OleVariant; var Cancel: WordBool);
917
  Headers: OleVariant; var Cancel: WordBool);
912
begin
918
begin
913
  BeforeNavigate(URL, Cancel);
919
  BeforeNavigate(URL, Cancel);
914
end;
920
end;
915
{$ENDIF}
921
{$ENDIF}
916
*)
922
*)
917
 
923
 
918
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
924
procedure TForm1.WebBrowser1WindowClosing(ASender: TObject;
919
  IsChildWindow: WordBool; var Cancel: WordBool);
925
  IsChildWindow: WordBool; var Cancel: WordBool);
920
resourcestring
926
resourcestring
921
  SCloseRequest = 'A script has requested the window to be closed. The window of a standalone script would now close.';
927
  SCloseRequest = 'A script has requested the window to be closed. The window of a standalone script would now close.';
922
begin
928
begin
923
  ShowMessage(SCloseRequest);
929
  ShowMessage(SCloseRequest);
924
  TWebBrowser(ASender).Clear;
930
  TWebBrowser(ASender).Clear;
925
  Cancel := true;
931
  Cancel := true;
926
end;
932
end;
927
 
933
 
928
procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
934
procedure TForm1.BeforeNavigate(const URL: OleVariant; var Cancel: WordBool);
929
var
935
var
930
  s, myURL: string;
936
  s, myURL: string;
931
  lineno: integer;
937
  lineno: integer;
932
  p: integer;
938
  p: integer;
933
begin
939
begin
934
  {$REGION 'Line number references (PHP errors and warnings)'}
940
  {$REGION 'Line number references (PHP errors and warnings)'}
935
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
941
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
936
  begin
942
  begin
937
    try
943
    try
938
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
944
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
939
      if not TryStrToInt(s, lineno) then exit;
945
      if not TryStrToInt(s, lineno) then exit;
940
      GotoLineNo(lineno);
946
      GotoLineNo(lineno);
941
      SynEditFocusTimer.Enabled := true;
947
      SynEditFocusTimer.Enabled := true;
942
    finally
948
    finally
943
      Cancel := true;
949
      Cancel := true;
944
    end;
950
    end;
945
    Exit;
951
    Exit;
946
  end;
952
  end;
947
  {$ENDREGION}
953
  {$ENDREGION}
948
 
954
 
949
  {$REGION 'Intelligent browser (executes PHP scripts which are clicked in a hyperlink)'}
955
  {$REGION 'Intelligent browser (executes PHP scripts which are clicked in a hyperlink)'}
950
  if URL <> 'about:blank' then
956
  if URL <> 'about:blank' then
951
  begin
957
  begin
952
    myUrl := URL;
958
    myUrl := URL;
953
 
959
 
954
    p := Pos('?', myUrl);
960
    p := Pos('?', myUrl);
955
    if p >= 1 then myURL := copy(myURL, 1, p-1);
961
    if p >= 1 then myURL := copy(myURL, 1, p-1);
956
 
962
 
957
    // TODO: myURL urldecode
963
    // TODO: myURL urldecode
958
    // TODO: maybe we could even open that file in the editor!
964
    // TODO: maybe we could even open that file in the editor!
959
    // TODO: ?parameter=....
965
    // TODO: ?parameter=....
960
 
966
 
961
    if FileExists(myURL) and (EndsText('.php', myURL) or EndsText('.php3', myURL) or EndsText('.php4', myURL) or EndsText('.php5', myURL) or EndsText('.phps', myURL)) then
967
    if FileExists(myURL) and (EndsText('.php', myURL) or EndsText('.php3', myURL) or EndsText('.php4', myURL) or EndsText('.php5', myURL) or EndsText('.phps', myURL)) then
962
    begin
968
    begin
963
      WebBrowser1.LoadHTML(RunPHPScript(myURL), myUrl);
969
      WebBrowser1.LoadHTML(RunPHPScript(myURL), myUrl);
964
      Cancel := true;
970
      Cancel := true;
965
    end;
971
    end;
966
  end;
972
  end;
967
  {$ENDREGION}
973
  {$ENDREGION}
968
end;
974
end;
969
 
975
 
970
procedure TForm1.BtnLightClick(Sender: TObject);
976
procedure TForm1.BtnLightClick(Sender: TObject);
971
var
977
var
972
  CanClose: boolean;
978
  CanClose: boolean;
973
begin
979
begin
974
  FormCloseQuery(Form1, CanClose);
980
  FormCloseQuery(Form1, CanClose);
975
  if not CanClose then exit;
981
  if not CanClose then exit;
976
 
982
 
977
  if IsThemeDark then
983
  if IsThemeDark then
978
  begin
984
  begin
979
    BtnLight.Picture.Assign(BtnLightOn.Picture);
985
    BtnLight.Picture.Assign(BtnLightOn.Picture);
980
    Theme_Light;
986
    Theme_Light;
981
    TFastPHPConfig.DarkTheme := false;
987
    TFastPHPConfig.DarkTheme := false;
982
  end
988
  end
983
  else
989
  else
984
  begin
990
  begin
985
    BtnLight.Picture.Assign(BtnLightOff.Picture);
991
    BtnLight.Picture.Assign(BtnLightOff.Picture);
986
    Theme_Dark;
992
    Theme_Dark;
987
    TFastPHPConfig.DarkTheme := true;
993
    TFastPHPConfig.DarkTheme := true;
988
  end;
994
  end;
989
end;
995
end;
990
 
996
 
991
procedure TForm1.BtnSpecialCharsClick(Sender: TObject);
997
procedure TForm1.BtnSpecialCharsClick(Sender: TObject);
992
var
998
var
993
  opts: TSynEditorOptions;
999
  opts: TSynEditorOptions;
994
begin
1000
begin
995
  opts := SynEdit1.Options;
1001
  opts := SynEdit1.Options;
996
  if eoShowSpecialChars in SynEdit1.Options then
1002
  if eoShowSpecialChars in SynEdit1.Options then
997
  begin
1003
  begin
998
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
1004
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
999
    Exclude(opts, eoShowSpecialChars);
1005
    Exclude(opts, eoShowSpecialChars);
1000
    TFastPHPConfig.SpecialChars := false;
1006
    TFastPHPConfig.SpecialChars := false;
1001
  end
1007
  end
1002
  else
1008
  else
1003
  begin
1009
  begin
1004
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
1010
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
1005
    Include(opts, eoShowSpecialChars);
1011
    Include(opts, eoShowSpecialChars);
1006
    TFastPHPConfig.SpecialChars := true;
1012
    TFastPHPConfig.SpecialChars := true;
1007
  end;
1013
  end;
1008
  SynEdit1.Options := opts;
1014
  SynEdit1.Options := opts;
1009
end;
1015
end;
1010
 
1016
 
1011
procedure TForm1.FileModTimerTimer(Sender: TObject);
1017
procedure TForm1.FileModTimerTimer(Sender: TObject);
1012
resourcestring
1018
resourcestring
1013
  SChangeConflict = 'The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?';
1019
  SChangeConflict = 'The file was changed in a different application BUT IT WAS ALSO MODIFIED HERE! Reload file AND LOSE CHANGES HERE?';
1014
  SChangeNotify = 'The file was changed in a different application! Reload file?';
1020
  SChangeNotify = 'The file was changed in a different application! Reload file?';
1015
begin
1021
begin
1016
  FileModTimer.Enabled := false;
1022
  FileModTimer.Enabled := false;
1017
  if FileModLast <> FileAge(GetScrapFile) then
1023
  if FileModLast <> FileAge(GetScrapFile) then
1018
  begin
1024
  begin
1019
    FileModLast := FileAge(GetScrapFile);
1025
    FileModLast := FileAge(GetScrapFile);
1020
    if SynEdit1.Modified then
1026
    if SynEdit1.Modified then
1021
    begin
1027
    begin
1022
      if MessageDlg(SChangeConflict, mtWarning, mbYesNoCancel, 0) = mrYes then
1028
      if MessageDlg(SChangeConflict, mtWarning, mbYesNoCancel, 0) = mrYes then
1023
      begin
1029
      begin
1024
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1030
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1025
      end;
1031
      end;
1026
    end
1032
    end
1027
    else
1033
    else
1028
    begin
1034
    begin
1029
      if MessageDlg(SChangeNotify, mtConfirmation, mbYesNoCancel, 0) = mrYes then
1035
      if MessageDlg(SChangeNotify, mtConfirmation, mbYesNoCancel, 0) = mrYes then
1030
      begin
1036
      begin
1031
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1037
        SynEdit1.Lines.LoadFromFile(GetScrapFile);
1032
      end;
1038
      end;
1033
    end;
1039
    end;
1034
  end;
1040
  end;
1035
  FileModTimer.Enabled := true;
1041
  FileModTimer.Enabled := true;
1036
end;
1042
end;
1037
 
1043
 
1038
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
1044
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
1039
begin
1045
begin
1040
  DragAcceptFiles(Handle, False);
1046
  DragAcceptFiles(Handle, False);
1041
  TFastPHPConfig.FontSize := SynEdit1.Font.Size;
1047
  TFastPHPConfig.FontSize := SynEdit1.Font.Size;
1042
end;
1048
end;
1043
 
1049
 
1044
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
1050
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
1045
var
1051
var
1046
  r: integer;
1052
  r: integer;
1047
resourcestring
1053
resourcestring
1048
  SWantToSave = 'Do you want to save?';
1054
  SWantToSave = 'Do you want to save?';
1049
begin
1055
begin
1050
  if SynEdit1.Modified then
1056
  if SynEdit1.Modified then
1051
  begin
1057
  begin
1052
    if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
1058
    if (ParamStr(1) <> '') or (FSaveAsFilename <> '') then
1053
    begin
1059
    begin
1054
      r := MessageDlg(SWantToSave, mtConfirmation, mbYesNoCancel, 0);
1060
      r := MessageDlg(SWantToSave, mtConfirmation, mbYesNoCancel, 0);
1055
      if r = mrCancel then
1061
      if r = mrCancel then
1056
      begin
1062
      begin
1057
        CanClose := false;
1063
        CanClose := false;
1058
        Exit;
1064
        Exit;
1059
      end
1065
      end
1060
      else if r = mrYes then
1066
      else if r = mrYes then
1061
      begin
1067
      begin
1062
        ActionSave.Execute;
1068
        ActionSave.Execute;
1063
        CanClose := true;
1069
        CanClose := true;
1064
      end;
1070
      end;
1065
    end
1071
    end
1066
    else
1072
    else
1067
    begin
1073
    begin
1068
      ActionSave.Execute;
1074
      ActionSave.Execute;
1069
      CanClose := true;
1075
      CanClose := true;
1070
    end;
1076
    end;
1071
  end;
1077
  end;
1072
end;
1078
end;
1073
 
1079
 
1074
procedure TForm1.FormCreate(Sender: TObject);
1080
procedure TForm1.FormCreate(Sender: TObject);
1075
var
1081
var
1076
  exeDir: string;
1082
  exeDir: string;
1077
  sScrapFile: string;
1083
  sScrapFile: string;
1078
begin
1084
begin
1079
  HlpPrevPageIndex := -1;
1085
  HlpPrevPageIndex := -1;
1080
  CurSearchTerm := '';
1086
  CurSearchTerm := '';
1081
  sScrapFile := GetScrapFile;
1087
  sScrapFile := GetScrapFile;
1082
  Caption := Caption + ' - ' + sScrapFile;
1088
  Caption := Caption + ' - ' + sScrapFile;
1083
  Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]); // do not translate!
1089
  Application.Title := Format('%s - FastPHP', [ExtractFileName(sScrapFile)]); // do not translate!
1084
  SrcRep := TSynEditFindReplace.Create(self);
1090
  SrcRep := TSynEditFindReplace.Create(self);
1085
  SrcRep.Editor := SynEdit1;
1091
  SrcRep.Editor := SynEdit1;
1086
  SynEdit1.Gutter.Gradient := HighColorWindows;
1092
  SynEdit1.Gutter.Gradient := HighColorWindows;
1087
 
1093
 
1088
  Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
1094
  Screen.Cursors[crMouseGutter] := LoadCursor(hInstance, 'MOUSEGUTTER');
1089
  SynEdit1.Gutter.Cursor := crMouseGutter;
1095
  SynEdit1.Gutter.Cursor := crMouseGutter;
1090
 
1096
 
1091
  exeDir := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
1097
  exeDir := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
1092
  if FileExists(exeDir + 'codeexplorer.bmp') then ImageList1.LoadAndSplitImages(exeDir + 'codeexplorer.bmp');
1098
  if FileExists(exeDir + 'codeexplorer.bmp') then ImageList1.LoadAndSplitImages(exeDir + 'codeexplorer.bmp');
1093
 
1099
 
1094
  FileModLast := FileAge(sScrapFile);
1100
  FileModLast := FileAge(sScrapFile);
1095
  FileModTimer.Enabled := True;
1101
  FileModTimer.Enabled := True;
1096
end;
1102
end;
1097
 
1103
 
1098
procedure TForm1.FormDestroy(Sender: TObject);
1104
procedure TForm1.FormDestroy(Sender: TObject);
1099
begin
1105
begin
1100
  if Assigned(ChmIndex) then
1106
  if Assigned(ChmIndex) then
1101
  begin
1107
  begin
1102
    FreeAndNil(ChmIndex);
1108
    FreeAndNil(ChmIndex);
1103
  end;
1109
  end;
1104
  FreeAndNil(SrcRep);
1110
  FreeAndNil(SrcRep);
1105
 
1111
 
1106
  if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
1112
  if hMutex <> 0 then CloseHandle(hMutex); // Note: ReleaseMutex does not work as expected!
1107
 
1113
 
1108
  if Assigned(codeExplorer) then
1114
  if Assigned(codeExplorer) then
1109
  begin
1115
  begin
1110
    codeExplorer.Terminate;
1116
    codeExplorer.Terminate;
1111
    codeExplorer.WaitFor;
1117
    codeExplorer.WaitFor;
1112
    FreeAndNil(codeExplorer);
1118
    FreeAndNil(codeExplorer);
1113
  end;
1119
  end;
1114
end;
1120
end;
1115
 
1121
 
1116
procedure TForm1.FormShow(Sender: TObject);
1122
procedure TForm1.FormShow(Sender: TObject);
1117
var
1123
var
1118
  ScrapFile: string;
1124
  ScrapFile: string;
1119
  tmpFontSize: integer;
1125
  tmpFontSize: integer;
1120
  opts: TSynEditorOptions;
1126
  opts: TSynEditorOptions;
1121
resourcestring
1127
resourcestring
1122
  SFileAlreadyOpen = 'File "%s" is alrady open!';
1128
  SFileAlreadyOpen = 'File "%s" is alrady open!';
1123
begin
1129
begin
1124
  if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
1130
  if FormShowRanOnce then exit; // If the theme is changed from normal to dark, OnShow will be called another time
1125
  FormShowRanOnce := true;
1131
  FormShowRanOnce := true;
1126
 
1132
 
1127
  ScrapFile := GetScrapFile;
1133
  ScrapFile := GetScrapFile;
1128
  if ScrapFile = '' then
1134
  if ScrapFile = '' then
1129
  begin
1135
  begin
1130
    Application.Terminate; // Close;
1136
    Application.Terminate; // Close;
1131
    exit;
1137
    exit;
1132
  end;
1138
  end;
1133
 
1139
 
1134
  opts := SynEdit1.Options;
1140
  opts := SynEdit1.Options;
1135
  if TFastPHPConfig.SpecialChars then
1141
  if TFastPHPConfig.SpecialChars then
1136
  begin
1142
  begin
1137
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
1143
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOn.Picture);
1138
    Include(opts, eoShowSpecialChars);
1144
    Include(opts, eoShowSpecialChars);
1139
  end
1145
  end
1140
  else
1146
  else
1141
  begin
1147
  begin
1142
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
1148
    BtnSpecialChars.Picture.Assign(BtnSpecialCharsOff.Picture);
1143
    Exclude(opts, eoShowSpecialChars);
1149
    Exclude(opts, eoShowSpecialChars);
1144
  end;
1150
  end;
1145
  SynEdit1.Options := opts;
1151
  SynEdit1.Options := opts;
1146
 
1152
 
1147
  if FileExists(ScrapFile) then
1153
  if FileExists(ScrapFile) then
1148
  begin
1154
  begin
1149
    if hMutex = 0 then
1155
    if hMutex = 0 then
1150
    begin
1156
    begin
1151
      hMutex := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(ScrapFile))));
1157
      hMutex := CreateMutex(nil, True, PChar('FastPHP'+md5(UpperCase(ScrapFile))));
1152
      if GetLastError = ERROR_ALREADY_EXISTS then
1158
      if GetLastError = ERROR_ALREADY_EXISTS then
1153
      begin
1159
      begin
1154
        // TODO: It would be great if the window of that FastPHP instance would switched to foreground
1160
        // TODO: It would be great if the window of that FastPHP instance would switched to foreground
1155
        ShowMessageFmt(SFileAlreadyOpen, [ScrapFile]);
1161
        ShowMessageFmt(SFileAlreadyOpen, [ScrapFile]);
1156
        Close;
1162
        Close;
1157
      end;
1163
      end;
1158
 
1164
 
1159
      SynEdit1.Lines.LoadFromFile(ScrapFile);
1165
      SynEdit1.Lines.LoadFromFile(ScrapFile);
1160
    end;
1166
    end;
1161
  end
1167
  end
1162
  else
1168
  else
1163
    SynEdit1.Lines.Clear;
1169
    SynEdit1.Lines.Clear;
1164
 
1170
 
1165
  PageControl1.ActivePage := PlaintextTabSheet;
1171
  PageControl1.ActivePage := PlaintextTabSheet;
1166
 
1172
 
1167
  PageControl2.ActivePage := CodeTabsheet;
1173
  PageControl2.ActivePage := CodeTabsheet;
1168
  HelpTabsheet.TabVisible := false;
1174
  HelpTabsheet.TabVisible := false;
1169
 
1175
 
1170
  tmpFontSize := TFastPHPConfig.FontSize;
1176
  tmpFontSize := TFastPHPConfig.FontSize;
1171
  if tmpFontSize <> -1 then SynEdit1.Font.Size := tmpFontSize;
1177
  if tmpFontSize <> -1 then SynEdit1.Font.Size := tmpFontSize;
1172
  SynEdit1.SetFocus;
1178
  SynEdit1.SetFocus;
1173
 
1179
 
1174
  DoubleBuffered := true;
1180
  DoubleBuffered := true;
1175
  StartCodeExplorer;
1181
  StartCodeExplorer;
1176
 
1182
 
1177
  DragAcceptFiles(Handle, True);
1183
  DragAcceptFiles(Handle, True);
1178
 
1184
 
1179
  StartupTimer.Enabled := true;
1185
  StartupTimer.Enabled := true;
1180
end;
1186
end;
1181
 
1187
 
1182
procedure TForm1.SaveToFile(filename: string);
1188
procedure TForm1.SaveToFile(filename: string);
1183
var
1189
var
1184
  ss: TStringStream;
1190
  ss: TStringStream;
1185
  ms: TMemoryStream;
1191
  ms: TMemoryStream;
1186
  fs: TFileStream;
1192
  fs: TFileStream;
1187
  eolStyle: string;
1193
  eolStyle: string;
1188
  str: string;
1194
  str: string;
1189
begin
1195
begin
1190
  FileModTimer.Enabled := false;
1196
  FileModTimer.Enabled := false;
1191
 
1197
 
1192
  ms := TMemoryStream.Create;
1198
  ms := TMemoryStream.Create;
1193
  ss := TStringStream.Create('');
1199
  ss := TStringStream.Create('');
1194
  fs := TFileStream.Create(filename, fmCreate);
1200
  fs := TFileStream.Create(filename, fmCreate);
1195
  try
1201
  try
1196
    // Save everything in a memory stream and then to a string
1202
    // Save everything in a memory stream and then to a string
1197
    // in comparison to "str := SynEdit1.Lines.Text;",
1203
    // in comparison to "str := SynEdit1.Lines.Text;",
1198
    // This approach should preserve LF / CRLF line endings
1204
    // This approach should preserve LF / CRLF line endings
1199
    SynEdit1.Lines.SaveToStream(ms);
1205
    SynEdit1.Lines.SaveToStream(ms);
1200
    ms.Position := 0;
1206
    ms.Position := 0;
1201
    ss.CopyFrom(ms, ms.Size);
1207
    ss.CopyFrom(ms, ms.Size);
1202
    ss.Position := 0;
1208
    ss.Position := 0;
1203
    str := ss.ReadString(ss.Size);
1209
    str := ss.ReadString(ss.Size);
1204
    ss.Size := 0; // clear string-stream, because we need it later again
1210
    ss.Size := 0; // clear string-stream, because we need it later again
1205
 
1211
 
1206
    // Detect current line-endings
1212
    // Detect current line-endings
1207
    if Copy(str, 1, 2) = '#!' then
1213
    if Copy(str, 1, 2) = '#!' then
1208
    begin
1214
    begin
1209
      // Shebang. Use ONLY Linux LF
1215
      // Shebang. Use ONLY Linux LF
1210
      str := StringReplace(str, #13#10, #10, [rfReplaceAll]);
1216
      str := StringReplace(str, #13#10, #10, [rfReplaceAll]);
1211
      eolStyle := #10 // Linux LF
1217
      eolStyle := #10 // Linux LF
1212
    end
1218
    end
1213
    else
1219
    else
1214
    begin
1220
    begin
1215
      if Pos(#13#10, str) > 0 then
1221
      if Pos(#13#10, str) > 0 then
1216
        eolStyle := #13#10 // Windows CRLF
1222
        eolStyle := #13#10 // Windows CRLF
1217
      else if Pos(#10, str) > 0 then
1223
      else if Pos(#10, str) > 0 then
1218
        eolStyle := #10 // Linux LF
1224
        eolStyle := #10 // Linux LF
1219
      else
1225
      else
1220
      begin
1226
      begin
1221
        if DefaultTextLineBreakStyle = tlbsLF then
1227
        if DefaultTextLineBreakStyle = tlbsLF then
1222
          eolStyle := #10 // Linux LF
1228
          eolStyle := #10 // Linux LF
1223
        else if DefaultTextLineBreakStyle = tlbsCRLF then
1229
        else if DefaultTextLineBreakStyle = tlbsCRLF then
1224
          eolStyle := #13#10 // Windows CRLF
1230
          eolStyle := #13#10 // Windows CRLF
1225
        //else if DefaultTextLineBreakStyle = tlbsCR then
1231
        //else if DefaultTextLineBreakStyle = tlbsCR then
1226
        //  eolStyle := #13 // Old Mac CR
1232
        //  eolStyle := #13 // Old Mac CR
1227
        else
1233
        else
1228
          eolStyle := #13#10; // (Should not happen)
1234
          eolStyle := #13#10; // (Should not happen)
1229
      end;
1235
      end;
1230
    end;
1236
    end;
1231
 
1237
 
1232
    // Unitfy line-endings
1238
    // Unitfy line-endings
1233
    str := StringReplace(str, #13#10, eolStyle, [rfReplaceAll]);
1239
    str := StringReplace(str, #13#10, eolStyle, [rfReplaceAll]);
1234
    str := StringReplace(str, #10, eolStyle, [rfReplaceAll]);
1240
    str := StringReplace(str, #10, eolStyle, [rfReplaceAll]);
1235
    str := StringReplace(str, #13, '', [rfReplaceAll]);
1241
    str := StringReplace(str, #13, '', [rfReplaceAll]);
1236
 
1242
 
1237
    // Replace all trailing linebreaks by a single line break
1243
    // Replace all trailing linebreaks by a single line break
1238
    // Note: Removing all line breaks is not good, since Linux's "nano" will
1244
    // Note: Removing all line breaks is not good, since Linux's "nano" will
1239
    //       re-add a linebreak at the end of the file
1245
    //       re-add a linebreak at the end of the file
1240
    str := TrimRight(str) + eolStyle;
1246
    str := TrimRight(str) + eolStyle;
1241
 
1247
 
1242
    // Old versions of Delphi/SynEdit write an UTF-8 BOM, which makes problems
1248
    // Old versions of Delphi/SynEdit write an UTF-8 BOM, which makes problems
1243
    // e.g. with AJAX handlers (because AJAX reponses must not have a BOM).
1249
    // e.g. with AJAX handlers (because AJAX reponses must not have a BOM).
1244
    // So we try to avoid that.
1250
    // So we try to avoid that.
1245
    // Note that the output is still UTF-8 encoded if the input file was UTF-8 encoded
1251
    // Note that the output is still UTF-8 encoded if the input file was UTF-8 encoded
1246
    if Copy(str,1,3) = #$EF#$BB#$BF then Delete(str, 1, 3);
1252
    if Copy(str,1,3) = #$EF#$BB#$BF then Delete(str, 1, 3);
1247
 
1253
 
1248
    // Now save to the file
1254
    // Now save to the file
1249
    ss.WriteString(str);
1255
    ss.WriteString(str);
1250
    ss.Position := 0;
1256
    ss.Position := 0;
1251
    fs.CopyFrom(ss, ss.Size-ss.Position);
1257
    fs.CopyFrom(ss, ss.Size-ss.Position);
1252
  finally
1258
  finally
1253
    FreeAndNil(ms);
1259
    FreeAndNil(ms);
1254
    FreeAndNil(ss);
1260
    FreeAndNil(ss);
1255
    FreeAndNil(fs);
1261
    FreeAndNil(fs);
1256
  end;
1262
  end;
1257
 
1263
 
1258
  FileModLast := FileAge(GetScrapFile);
1264
  FileModLast := FileAge(GetScrapFile);
1259
  FileModTimer.Enabled := True;
1265
  FileModTimer.Enabled := True;
1260
end;
1266
end;
1261
 
1267
 
1262
procedure TForm1.StartCodeExplorer;
1268
procedure TForm1.StartCodeExplorer;
1263
begin
1269
begin
1264
  codeExplorer := TRunCodeExplorer.Create(true);
1270
  codeExplorer := TRunCodeExplorer.Create(true);
1265
  codeExplorer.InputRequestCallback := InputRequestCallback;
1271
  codeExplorer.InputRequestCallback := InputRequestCallback;
1266
  codeExplorer.OutputNotifyCallback := OutputNotifyCallback;
1272
  codeExplorer.OutputNotifyCallback := OutputNotifyCallback;
1267
  codeExplorer.PhpExe := GetPHPExe;
1273
  codeExplorer.PhpExe := GetPHPExe;
1268
  codeExplorer.PhpFile := IncludeTrailingPathDelimiter(ExtractFileDir(Application.ExeName)) + 'codeexplorer.php'; // GetScrapFile;
1274
  codeExplorer.PhpFile := IncludeTrailingPathDelimiter(ExtractFileDir(Application.ExeName)) + 'codeexplorer.php'; // GetScrapFile;
1269
  codeExplorer.WorkDir := ExtractFileDir(Application.ExeName);
1275
  codeExplorer.WorkDir := ExtractFileDir(Application.ExeName);
1270
  codeExplorer.Resume;
1276
  codeExplorer.Resume;
1271
end;
1277
end;
1272
 
1278
 
1273
procedure TForm1.StartUpTimerTimer(Sender: TObject);
1279
procedure TForm1.StartUpTimerTimer(Sender: TObject);
1274
begin
1280
begin
1275
  StartupTimer.Enabled := false;
1281
  StartupTimer.Enabled := false;
1276
 
1282
 
1277
  // We need this timer because we cannot change the Theme during OnShow,
1283
  // We need this timer because we cannot change the Theme during OnShow,
1278
  // because the Delphi VCL Theme is buggy!
1284
  // because the Delphi VCL Theme is buggy!
1279
 
1285
 
1280
  if TFastPHPConfig.DarkTheme then
1286
  if TFastPHPConfig.DarkTheme then
1281
  begin
1287
  begin
1282
    BtnLight.Picture.Assign(BtnLightOff.Picture);
1288
    BtnLight.Picture.Assign(BtnLightOff.Picture);
1283
    Theme_Dark;
1289
    Theme_Dark;
1284
  end
1290
  end
1285
  else
1291
  else
1286
  begin
1292
  begin
1287
    BtnLight.Picture.Assign(BtnLightOn.Picture);
1293
    BtnLight.Picture.Assign(BtnLightOn.Picture);
1288
    Theme_Light;
1294
    Theme_Light;
1289
  end;
1295
  end;
1290
end;
1296
end;
1291
 
1297
 
1292
function TForm1.GetScrapFile: string;
1298
function TForm1.GetScrapFile: string;
1293
var
1299
var
1294
  tmpPath: string;
1300
  tmpPath: string;
1295
resourcestring
1301
resourcestring
1296
  SFileDoesNotExistsCreate = 'File %s does not exist. Create it?';
1302
  SFileDoesNotExistsCreate = 'File %s does not exist. Create it?';
1297
  SPathDoesNotExistTryAgain = 'Path does not exist! Please try again.';
1303
  SPathDoesNotExistTryAgain = 'Path does not exist! Please try again.';
1298
begin
1304
begin
1299
  if FSaveAsFilename <> '' then
1305
  if FSaveAsFilename <> '' then
1300
  begin
1306
  begin
1301
    result := FSaveAsFilename;
1307
    result := FSaveAsFilename;
1302
    exit;
1308
    exit;
1303
  end;
1309
  end;
1304
 
1310
 
1305
  if FScrapFile <> '' then
1311
  if FScrapFile <> '' then
1306
  begin
1312
  begin
1307
    result := FScrapFile;
1313
    result := FScrapFile;
1308
    exit;
1314
    exit;
1309
  end;
1315
  end;
1310
 
1316
 
1311
  if ParamStr(1) <> '' then
1317
  if ParamStr(1) <> '' then
1312
  begin
1318
  begin
1313
    // Program was started with a filename
1319
    // Program was started with a filename
1314
 
1320
 
1315
    result := ParamStr(1);
1321
    result := ParamStr(1);
1316
 
1322
 
1317
    if not FileExists(result) then
1323
    if not FileExists(result) then
1318
    begin
1324
    begin
1319
      case MessageDlg(Format(SFileDoesNotExistsCreate, [result]), mtConfirmation, mbYesNoCancel, 0) of
1325
      case MessageDlg(Format(SFileDoesNotExistsCreate, [result]), mtConfirmation, mbYesNoCancel, 0) of
1320
        mrYes:
1326
        mrYes:
1321
          try
1327
          try
1322
            SaveToFile(result);
1328
            SaveToFile(result);
1323
          except
1329
          except
1324
            on E: Exception do
1330
            on E: Exception do
1325
            begin
1331
            begin
1326
              MessageDlg(E.Message, mtError, [mbOk], 0);
1332
              MessageDlg(E.Message, mtError, [mbOk], 0);
1327
              Application.Terminate;
1333
              Application.Terminate;
1328
              result := '';
1334
              result := '';
1329
              exit;
1335
              exit;
1330
            end;
1336
            end;
1331
          end;
1337
          end;
1332
        mrNo:
1338
        mrNo:
1333
          begin
1339
          begin
1334
            Application.Terminate;
1340
            Application.Terminate;
1335
            result := '';
1341
            result := '';
1336
            exit;
1342
            exit;
1337
          end;
1343
          end;
1338
        mrCancel:
1344
        mrCancel:
1339
          begin
1345
          begin
1340
            Application.Terminate;
1346
            Application.Terminate;
1341
            result := '';
1347
            result := '';
1342
            exit;
1348
            exit;
1343
          end;
1349
          end;
1344
      end;
1350
      end;
1345
    end;
1351
    end;
1346
  end
1352
  end
1347
  else
1353
  else
1348
  begin
1354
  begin
1349
    // Program is started without filename -> use scrap file
1355
    // Program is started without filename -> use scrap file
1350
 
1356
 
1351
    result := TFastPHPConfig.ScrapFile;
1357
    result := TFastPHPConfig.ScrapFile;
1352
 
1358
 
1353
    if not FileExists(result) then
1359
    if not FileExists(result) then
1354
    begin
1360
    begin
1355
      repeat
1361
      repeat
1356
        {$REGION 'Determinate opendialog initial directory'}
1362
        {$REGION 'Determinate opendialog initial directory'}
1357
        if result <> '' then
1363
        if result <> '' then
1358
        begin
1364
        begin
1359
          tmpPath := ExtractFilePath(result);
1365
          tmpPath := ExtractFilePath(result);
1360
          if DirectoryExists(tmpPath) then
1366
          if DirectoryExists(tmpPath) then
1361
          begin
1367
          begin
1362
            OpenDialog3.InitialDir := tmpPath;
1368
            OpenDialog3.InitialDir := tmpPath;
1363
            OpenDialog3.FileName := Result;
1369
            OpenDialog3.FileName := Result;
1364
          end
1370
          end
1365
          else
1371
          else
1366
          begin
1372
          begin
1367
            OpenDialog3.InitialDir := GetMyDocumentsFolder;
1373
            OpenDialog3.InitialDir := GetMyDocumentsFolder;
1368
          end;
1374
          end;
1369
        end
1375
        end
1370
        else
1376
        else
1371
        begin
1377
        begin
1372
          OpenDialog3.InitialDir := GetMyDocumentsFolder;
1378
          OpenDialog3.InitialDir := GetMyDocumentsFolder;
1373
        end;
1379
        end;
1374
        {$ENDREGION}
1380
        {$ENDREGION}
1375
 
1381
 
1376
        if not OpenDialog3.Execute then
1382
        if not OpenDialog3.Execute then
1377
        begin
1383
        begin
1378
          Application.Terminate;
1384
          Application.Terminate;
1379
          result := '';
1385
          result := '';
1380
          exit;
1386
          exit;
1381
        end;
1387
        end;
1382
 
1388
 
1383
        if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1389
        if not DirectoryExists(ExtractFilePath(OpenDialog3.FileName)) then
1384
        begin
1390
        begin
1385
          MessageDlg(SPathDoesNotExistTryAgain, mtWarning, [mbOk], 0);
1391
          MessageDlg(SPathDoesNotExistTryAgain, mtWarning, [mbOk], 0);
1386
        end
1392
        end
1387
        else
1393
        else
1388
        begin
1394
        begin
1389
          result := OpenDialog3.FileName;
1395
          result := OpenDialog3.FileName;
1390
        end;
1396
        end;
1391
      until result <> '';
1397
      until result <> '';
1392
 
1398
 
1393
      if not FileExists(result) then
1399
      if not FileExists(result) then
1394
      begin
1400
      begin
1395
        try
1401
        try
1396
          // Try saving the file; check if we have permissions
1402
          // Try saving the file; check if we have permissions
1397
          //SynEdit1.Lines.Clear;
1403
          //SynEdit1.Lines.Clear;
1398
          SaveToFile(result);
1404
          SaveToFile(result);
1399
        except
1405
        except
1400
          on E: Exception do
1406
          on E: Exception do
1401
          begin
1407
          begin
1402
            MessageDlg(E.Message, mtError, [mbOk], 0);
1408
            MessageDlg(E.Message, mtError, [mbOk], 0);
1403
            Application.Terminate;
1409
            Application.Terminate;
1404
            result := '';
1410
            result := '';
1405
            exit;
1411
            exit;
1406
          end;
1412
          end;
1407
        end;
1413
        end;
1408
      end;
1414
      end;
1409
 
1415
 
1410
      TFastPHPConfig.ScrapFile := result;
1416
      TFastPHPConfig.ScrapFile := result;
1411
      FScrapFile := result;
1417
      FScrapFile := result;
1412
    end;
1418
    end;
1413
  end;
1419
  end;
1414
end;
1420
end;
1415
 
1421
 
1416
procedure TForm1.Help;
1422
procedure TForm1.Help;
1417
var
1423
var
1418
  IndexFile, chmFile, w, OriginalWord, url: string;
1424
  IndexFile, chmFile, w, OriginalWord, url: string;
1419
  internalHtmlFile: string;
1425
  internalHtmlFile: string;
1420
resourcestring
1426
resourcestring
1421
  SChmFileNotAValidPHPDocumentation = 'The CHM file is not a valid PHP documentation. Cannot use help.';
1427
  SChmFileNotAValidPHPDocumentation = 'The CHM file is not a valid PHP documentation. Cannot use help.';
1422
  SUnknownErrorCannotUseHelp = 'Unknown error. Cannot use help.';
1428
  SUnknownErrorCannotUseHelp = 'Unknown error. Cannot use help.';
1423
  SNoHelpAvailable = 'No help for "%s" available';
1429
  SNoHelpAvailable = 'No help for "%s" available';
1424
begin
1430
begin
1425
  if not Assigned(ChmIndex) then
1431
  if not Assigned(ChmIndex) then
1426
  begin
1432
  begin
1427
    IndexFile := TFastPHPConfig.HelpIndex;
1433
    IndexFile := TFastPHPConfig.HelpIndex;
1428
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
1434
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
1429
    if FileExists(IndexFile) then
1435
    if FileExists(IndexFile) then
1430
    begin
1436
    begin
1431
      ChmIndex := TMemIniFile.Create(IndexFile);
1437
      ChmIndex := TMemIniFile.Create(IndexFile);
1432
    end;
1438
    end;
1433
  end;
1439
  end;
1434
 
1440
 
1435
  if Assigned(ChmIndex) then
1441
  if Assigned(ChmIndex) then
1436
  begin
1442
  begin
1437
    IndexFile := TFastPHPConfig.HelpIndex;
1443
    IndexFile := TFastPHPConfig.HelpIndex;
1438
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
1444
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
1439
 
1445
 
1440
    chmFile := ChangeFileExt(IndexFile, '.chm');
1446
    chmFile := ChangeFileExt(IndexFile, '.chm');
1441
    if not FileExists(chmFile) then
1447
    if not FileExists(chmFile) then
1442
    begin
1448
    begin
1443
      FreeAndNil(ChmIndex);
1449
      FreeAndNil(ChmIndex);
1444
    end;
1450
    end;
1445
  end;
1451
  end;
1446
 
1452
 
1447
  if not Assigned(ChmIndex) then
1453
  if not Assigned(ChmIndex) then
1448
  begin
1454
  begin
1449
    if not OpenDialog1.Execute then exit;
1455
    if not OpenDialog1.Execute then exit;
1450
 
1456
 
1451
    chmFile := OpenDialog1.FileName;
1457
    chmFile := OpenDialog1.FileName;
1452
    if not FileExists(chmFile) then exit;
1458
    if not FileExists(chmFile) then exit;
1453
 
1459
 
1454
    IndexFile := ChangeFileExt(chmFile, '.ini');
1460
    IndexFile := ChangeFileExt(chmFile, '.ini');
1455
 
1461
 
1456
    if not FileExists(IndexFile) then
1462
    if not FileExists(IndexFile) then
1457
    begin
1463
    begin
1458
      Panel1.Align := alClient;
1464
      Panel1.Align := alClient;
1459
      Panel1.Visible := true;
1465
      Panel1.Visible := true;
1460
      Panel1.BringToFront;
1466
      Panel1.BringToFront;
1461
      Screen.Cursor := crHourGlass;
1467
      Screen.Cursor := crHourGlass;
1462
      Application.ProcessMessages;
1468
      Application.ProcessMessages;
1463
      try
1469
      try
1464
        if not ParseCHM(chmFile) then
1470
        if not ParseCHM(chmFile) then
1465
        begin
1471
        begin
1466
          MessageDlg(SChmFileNotAValidPHPDocumentation, mtError, [mbOk], 0);
1472
          MessageDlg(SChmFileNotAValidPHPDocumentation, mtError, [mbOk], 0);
1467
          exit;
1473
          exit;
1468
        end;
1474
        end;
1469
      finally
1475
      finally
1470
        Screen.Cursor := crDefault;
1476
        Screen.Cursor := crDefault;
1471
        Panel1.Visible := false;
1477
        Panel1.Visible := false;
1472
      end;
1478
      end;
1473
 
1479
 
1474
      if not FileExists(IndexFile) then
1480
      if not FileExists(IndexFile) then
1475
      begin
1481
      begin
1476
        MessageDlg(SUnknownErrorCannotUseHelp, mtError, [mbOk], 0);
1482
        MessageDlg(SUnknownErrorCannotUseHelp, mtError, [mbOk], 0);
1477
        exit;
1483
        exit;
1478
      end;
1484
      end;
1479
    end;
1485
    end;
1480
 
1486
 
1481
    TFastPHPConfig.HelpIndex := IndexFile;
1487
    TFastPHPConfig.HelpIndex := IndexFile;
1482
 
1488
 
1483
    ChmIndex := TMemIniFile.Create(IndexFile);
1489
    ChmIndex := TMemIniFile.Create(IndexFile);
1484
  end;
1490
  end;
1485
 
1491
 
1486
  w := GetWordUnderCaret(SynEdit1);
1492
  w := GetWordUnderCaret(SynEdit1);
1487
  if w = '' then exit;
1493
  if w = '' then exit;
1488
  {$IFDEF UNICODE}
1494
  {$IFDEF UNICODE}
1489
  if CharInSet(w[1], ['0'..'9']) then exit;
1495
  if CharInSet(w[1], ['0'..'9']) then exit;
1490
  {$ELSE}
1496
  {$ELSE}
1491
  if w[1] in ['0'..'9'] then exit;
1497
  if w[1] in ['0'..'9'] then exit;
1492
  {$ENDIF}
1498
  {$ENDIF}
1493
 
1499
 
1494
  Originalword := w;
1500
  Originalword := w;
1495
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
1501
//  w := StringReplace(w, '_', '-', [rfReplaceAll]);
1496
  w := LowerCase(w);
1502
  w := LowerCase(w);
1497
  CurSearchTerm := w;
1503
  CurSearchTerm := w;
1498
 
1504
 
1499
  internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, ''); // do not translate
1505
  internalHtmlFile := ChmIndex.ReadString('function', CurSearchTerm, ''); // do not translate
1500
  if internalHtmlFile = '' then
1506
  if internalHtmlFile = '' then
1501
    internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, ''); // do not translate
1507
    internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, ''); // do not translate
1502
  if internalHtmlFile = '' then
1508
  if internalHtmlFile = '' then
1503
  begin
1509
  begin
1504
    HelpTabsheet.TabVisible := false;
1510
    HelpTabsheet.TabVisible := false;
1505
    HlpPrevPageIndex := -1;
1511
    HlpPrevPageIndex := -1;
1506
    ShowMessageFmt(SNoHelpAvailable, [Originalword]);
1512
    ShowMessageFmt(SNoHelpAvailable, [Originalword]);
1507
    Exit;
1513
    Exit;
1508
  end;
1514
  end;
1509
 
1515
 
1510
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1516
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
1511
 
1517
 
1512
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
1518
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
1513
  HelpTabsheet.TabVisible := true;
1519
  HelpTabsheet.TabVisible := true;
1514
  PageControl2.ActivePage := HelpTabsheet;
1520
  PageControl2.ActivePage := HelpTabsheet;
1515
  WebBrowser2.Navigate(url);
1521
  WebBrowser2.Navigate(url);
1516
  WebBrowser2.Wait;
1522
  WebBrowser2.Wait;
1517
end;
1523
end;
1518
 
1524
 
1519
procedure TForm1.GotoLineNo(LineNo:integer);
1525
procedure TForm1.GotoLineNo(LineNo:integer);
1520
var
1526
var
1521
  line: string;
1527
  line: string;
1522
  i: integer;
1528
  i: integer;
1523
begin
1529
begin
1524
  SynEdit1.GotoLineAndCenter(LineNo);
1530
  SynEdit1.GotoLineAndCenter(LineNo);
1525
 
1531
 
1526
  // Skip indent
1532
  // Skip indent
1527
  line := SynEdit1.Lines[SynEdit1.CaretY];
1533
  line := SynEdit1.Lines[SynEdit1.CaretY];
1528
  for i := 1 to Length(line) do
1534
  for i := 1 to Length(line) do
1529
  begin
1535
  begin
1530
    {$IFDEF UNICODE}
1536
    {$IFDEF UNICODE}
1531
    if not CharInSet(line[i], [' ', #9]) then
1537
    if not CharInSet(line[i], [' ', #9]) then
1532
    {$ELSE}
1538
    {$ELSE}
1533
    if not (line[i] in [' ', #9]) then
1539
    if not (line[i] in [' ', #9]) then
1534
    {$ENDIF}
1540
    {$ENDIF}
1535
    begin
1541
    begin
1536
      SynEdit1.CaretX := i-1;
1542
      SynEdit1.CaretX := i-1;
1537
      break;
1543
      break;
1538
    end;
1544
    end;
1539
  end;
1545
  end;
1540
 
1546
 
1541
  PageControl2.ActivePage := CodeTabsheet;
1547
  PageControl2.ActivePage := CodeTabsheet;
1542
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
1548
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
1543
end;
1549
end;
1544
 
1550
 
1545
procedure TForm1.PageControl2Changing(Sender: TObject;
1551
procedure TForm1.PageControl2Changing(Sender: TObject;
1546
  var AllowChange: Boolean);
1552
  var AllowChange: Boolean);
1547
begin
1553
begin
1548
  if PageControl2.ActivePage = HelpTabsheet then
1554
  if PageControl2.ActivePage = HelpTabsheet then
1549
    HlpPrevPageIndex := -1
1555
    HlpPrevPageIndex := -1
1550
  else
1556
  else
1551
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
1557
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
1552
 
1558
 
1553
  AllowChange := true;
1559
  AllowChange := true;
1554
end;
1560
end;
1555
 
1561
 
1556
procedure TForm1.Memo2DblClick(Sender: TObject);
1562
procedure TForm1.Memo2DblClick(Sender: TObject);
1557
var
1563
var
1558
  line: string;
1564
  line: string;
1559
 
1565
 
1560
  procedure _process(toFind: string);
1566
  procedure _process(toFind: string);
1561
  var
1567
  var
1562
    p, lineno: integer;
1568
    p, lineno: integer;
1563
  begin
1569
  begin
1564
    if FileSystemCaseSensitive then
1570
    if FileSystemCaseSensitive then
1565
      p := Pos(toFind, line)
1571
      p := Pos(toFind, line)
1566
    else
1572
    else
1567
      p := Pos(LowerCase(toFind), LowerCase(line));
1573
      p := Pos(LowerCase(toFind), LowerCase(line));
1568
    if p <> 0 then
1574
    if p <> 0 then
1569
    begin
1575
    begin
1570
      line := copy(line, p+length(toFind), 99);
1576
      line := copy(line, p+length(toFind), 99);
1571
      if not TryStrToInt(line, lineno) then exit;
1577
      if not TryStrToInt(line, lineno) then exit;
1572
      GotoLineNo(lineno);
1578
      GotoLineNo(lineno);
1573
    end;
1579
    end;
1574
  end;
1580
  end;
1575
 
1581
 
1576
begin
1582
begin
1577
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
1583
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
1578
 
1584
 
1579
  {$REGION 'Possibility 1: filename.php:lineno'}
1585
  {$REGION 'Possibility 1: filename.php:lineno'}
1580
  _process(ExtractFileName(GetScrapFile) + ':');
1586
  _process(ExtractFileName(GetScrapFile) + ':');
1581
  {$ENDREGION}
1587
  {$ENDREGION}
1582
 
1588
 
1583
  {$REGION 'Possibility 2: on line xx'}
1589
  {$REGION 'Possibility 2: on line xx'}
1584
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1590
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1585
  {$ENDREGION}
1591
  {$ENDREGION}
1586
end;
1592
end;
1587
 
1593
 
1588
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1594
procedure TForm1.Memo2KeyDown(Sender: TObject; var Key: Word;
1589
  Shift: TShiftState);
1595
  Shift: TShiftState);
1590
begin
1596
begin
1591
  if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
1597
  if ((ssCtrl in Shift) and (Key = 65)) then TMemo(Sender).SelectAll;
1592
end;
1598
end;
1593
 
1599
 
1594
function TForm1.MarkUpLineReference(cont: string): string;
1600
function TForm1.MarkUpLineReference(cont: string): string;
1595
 
1601
 
1596
  procedure _process(toFind: string);
1602
  procedure _process(toFind: string);
1597
  var
1603
  var
1598
    p, a, b: integer;
1604
    p, a, b: integer;
1599
    num: integer;
1605
    num: integer;
1600
    insert_a, insert_b: string;
1606
    insert_a, insert_b: string;
1601
  begin
1607
  begin
1602
    if FileSystemCaseSensitive then
1608
    if FileSystemCaseSensitive then
1603
      p := Pos(toFind, cont)
1609
      p := Pos(toFind, cont)
1604
    else
1610
    else
1605
      p := Pos(LowerCase(toFind), LowerCase(cont));
1611
      p := Pos(LowerCase(toFind), LowerCase(cont));
1606
    while p >= 1 do
1612
    while p >= 1 do
1607
    begin
1613
    begin
1608
      a := p;
1614
      a := p;
1609
      b := p + length(toFind);
1615
      b := p + length(toFind);
1610
      num := 0;
1616
      num := 0;
1611
      {$IFDEF UNICODE}
1617
      {$IFDEF UNICODE}
1612
      while CharInSet(cont[b], ['0'..'9']) do
1618
      while CharInSet(cont[b], ['0'..'9']) do
1613
      {$ELSE}
1619
      {$ELSE}
1614
      while cont[b] in ['0'..'9'] do
1620
      while cont[b] in ['0'..'9'] do
1615
      {$ENDIF}
1621
      {$ENDIF}
1616
      begin
1622
      begin
1617
        num := num*10 + StrToInt(cont[b]);
1623
        num := num*10 + StrToInt(cont[b]);
1618
        inc(b);
1624
        inc(b);
1619
      end;
1625
      end;
1620
 
1626
 
1621
      insert_b := '</a>';
1627
      insert_b := '</a>';
1622
      insert_a := '<a href="' + FASTPHP_GOTO_URI_PREFIX + IntToStr(num) + '">';
1628
      insert_a := '<a href="' + FASTPHP_GOTO_URI_PREFIX + IntToStr(num) + '">';
1623
 
1629
 
1624
      insert(insert_b, cont, b);
1630
      insert(insert_b, cont, b);
1625
      insert(insert_a, cont, a);
1631
      insert(insert_a, cont, a);
1626
 
1632
 
1627
      p := b + Length(insert_a) + Length(insert_b);
1633
      p := b + Length(insert_a) + Length(insert_b);
1628
 
1634
 
1629
      p := PosEx(toFind, cont, p+1);
1635
      p := PosEx(toFind, cont, p+1);
1630
    end;
1636
    end;
1631
  end;
1637
  end;
1632
 
1638
 
1633
begin
1639
begin
1634
  {$REGION 'Possibility 1: filename.php:lineno'}
1640
  {$REGION 'Possibility 1: filename.php:lineno'}
1635
  _process(ExtractFileName(GetScrapFile) + ':');
1641
  _process(ExtractFileName(GetScrapFile) + ':');
1636
  {$ENDREGION}
1642
  {$ENDREGION}
1637
 
1643
 
1638
  {$REGION 'Possibility 2: on line xx'}
1644
  {$REGION 'Possibility 2: on line xx'}
1639
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1645
  _process(ExtractFileName(GetScrapFile) + ' on line '); // do not translate!
1640
  {$ENDREGION}
1646
  {$ENDREGION}
1641
 
1647
 
1642
  result := cont;
1648
  result := cont;
1643
end;
1649
end;
1644
 
1650
 
1645
function TForm1.InputRequestCallback(var data: AnsiString): boolean;
1651
function TForm1.InputRequestCallback(var data: AnsiString): boolean;
1646
begin
1652
begin
1647
  data := UTF8Encode(SynEdit1.Text);
1653
  data := UTF8Encode(SynEdit1.Text);
1648
  result := true;
1654
  result := true;
1649
end;
1655
end;
1650
 
1656
 
1651
function TForm1.IsThemeDark: boolean;
1657
function TForm1.IsThemeDark: boolean;
1652
begin
1658
begin
1653
  result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1659
  result := Assigned(TStyleManager.ActiveStyle) and (TStyleManager.ActiveStyle.Name<>'Windows');
1654
end;
1660
end;
1655
 
1661
 
1656
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
1662
function TForm1.OutputNotifyCallback(const data: AnsiString): boolean;
1657
begin
1663
begin
1658
  result := TreeView1.FillWithFastPHPData(string(data));
1664
  result := TreeView1.FillWithFastPHPData(string(data));
1659
end;
1665
end;
1660
 
1666
 
1661
end.
1667
end.
1662
 
1668