Subversion Repositories fastphp

Rev

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

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