Subversion Repositories fastphp

Rev

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

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