Subversion Repositories fastphp

Rev

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

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