1 {***************************************************************************
2  *                                                                         *
3  *   This source is free software; you can redistribute it and/or modify   *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  *   This code is distributed in the hope that it will be useful, but      *
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
11  *   General Public License for more details.                              *
12  *                                                                         *
13  *   A copy of the GNU General Public License is available on the World    *
14  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
15  *   obtain it by writing to the Free Software Foundation,                 *
16  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
17  *                                                                         *
18  ***************************************************************************
19 
20   Abstract:
21     Frame to edit custom options and conditionals of compiler options
22     (project+packages).
23 }
24 unit Compiler_Other_Options;
25 
26 {$mode objfpc}{$H+}
27 
28 interface
29 
30 uses
31   Classes, SysUtils, math, Laz_AVL_Tree,
32   // LCL
33   Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Buttons, LCLType,
34   // LazUtils
35   LazUTF8, LazLoggerBase,
36   // Codetools
37   CodeToolsCfgScript, KeywordFuncLists,
38   // IdeIntf
39   IDEOptionsIntf, IDEOptEditorIntf, CompOptsIntf, IDECommands,
40   // SynEdit
41   SynEdit, SynEditKeyCmds, SynCompletion,
42   // IDE
43   LazarusIDEStrConsts, CompilerOptions, Compiler, AllCompilerOptions, DefinesGui,
44   EditorOptions, PackageDefs, SourceSynEditor;
45 
46 type
47 
48   { TCompilerOtherOptionsFrame }
49 
50   TCompilerOtherOptionsFrame = class(TAbstractIDEOptionsEditor)
51     btnDefines: TBitBtn;
52     btnAllOptions: TBitBtn;
53     btnFcUTF8: TBitBtn;
54     grpCustomOptions: TGroupBox;
55     grpConditionals: TGroupBox;
56     CondStatusbar: TStatusBar;
57     CondSynEdit: TSynEdit;
58     CustomSplitter: TSplitter;
59     memoCustomOptions: TMemo;
60     procedure btnAllOptionsClick(Sender: TObject);
61     procedure btnDefinesClick(Sender: TObject);
62     procedure btnFcUTF8Click(Sender: TObject);
63     procedure CondSynEditChange(Sender: TObject);
64     procedure CondSynEditKeyPress(Sender: TObject; var {%H-}Key: char);
65     procedure CondSynEditProcessUserCommand(Sender: TObject;
66       var Command: TSynEditorCommand; var {%H-}AChar: TUTF8Char; {%H-}Data: pointer);
67     procedure CondSynEditStatusChange(Sender: TObject; {%H-}Changes: TSynStatusChanges);
68     procedure memoCustomOptionsChange(Sender: TObject);
69   private
70     FCompOptions: TBaseCompilerOptions;
71     FIdleConnected: Boolean;
72     FIsPackage: boolean;
73     FLocalOtherDefines: TStrings;
74     FCompletionHistory: TStrings;
75     FCompletionValues: TStrings;
76     FDefaultVariables: TCTCfgScriptVariables;
77     FHighlighter: TIDESynFreePasSyn;
78     FStatusMessage: string;
79     fEngine: TIDECfgScriptEngine;
80     fSynCompletion: TSynCompletion;
81     FOptionsReader: TCompilerOptReader;
82     FOptionsThread: TCompilerOptThread;
83     FUseComments: boolean;
84     procedure SetIdleConnected(AValue: Boolean);
85     procedure SetStatusMessage(const AValue: string);
86     procedure StartCompletion;
87     procedure UpdateCompletionValues;
GetCondCursorWordnull88     function GetCondCursorWord: string;
89     procedure UpdateMessages;
90     procedure UpdateStatusBar;
91     procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean);
92     procedure OnSynCompletionCancel(Sender: TObject);
93     procedure OnSynCompletionExecute(Sender: TObject);
94     procedure OnSynCompletionKeyCompletePrefix(Sender: TObject);
95     procedure OnSynCompletionKeyDelete(Sender: TObject);
96     procedure OnSynCompletionKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
97     procedure OnSynCompletionKeyNextChar(Sender: TObject);
98     procedure OnSynCompletionKeyPrevChar(Sender: TObject);
99     procedure OnSynCompletionSearchPosition(var Position: integer);
100     procedure OnSynCompletionUTF8KeyPress(Sender: TObject; var {%H-}UTF8Key: TUTF8Char);
101     procedure OnSynCompletionValidate(Sender: TObject; {%H-}KeyChar: TUTF8Char;
102       {%H-}Shift: TShiftState);
103   protected
104     procedure SetVisible(Value: Boolean); override;
105   public
106     constructor Create(TheOwner: TComponent); override;
107     destructor Destroy; override;
Checknull108     function Check: Boolean; override;
GetTitlenull109     function GetTitle: string; override;
110     procedure Setup({%H-}ADialog: TAbstractOptionsEditorDialog); override;
111     procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
112     procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
SupportedOptionsClassnull113     class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
NoUtf8RtlSupportYetnull114     function NoUtf8RtlSupportYet: Boolean;
115     property StatusMessage: string read FStatusMessage write SetStatusMessage;
116     property DefaultVariables: TCTCfgScriptVariables read FDefaultVariables;
117     property CompletionValues: TStrings read FCompletionValues;
118     property CompletionHistory: TStrings read FCompletionHistory;
119     property IdleConnected: Boolean read FIdleConnected write SetIdleConnected;
120     property OptionsReader: TCompilerOptReader read FOptionsReader;
121   end;
122 
123 implementation
124 
125 {$R *.lfm}
126 
127 const
128   FcUTF8 = '-FcUTF8';
129 
130 { TCompilerOtherOptionsFrame }
131 
132 procedure TCompilerOtherOptionsFrame.btnAllOptionsClick(Sender: TObject);
133 var
134   AllOpts: TfrmAllCompilerOptions;
135 begin
136   try
137     FOptionsReader.FromCustomOptions(memoCustomOptions.Lines);
138     AllOpts := TfrmAllCompilerOptions.Create(Nil);
139     try
140       AllOpts.OptionsReader := FOptionsReader;
141       AllOpts.OptionsThread := FOptionsThread;
142       AllOpts.cbUseComments.Checked := FUseComments;
143       if AllOpts.ShowModal = mrOK then
144       begin
145         // Synchronize with custom options memo
146         FUseComments := AllOpts.cbUseComments.Checked;
147         AllOpts.ToCustomOptions(memoCustomOptions.Lines);
148         memoCustomOptions.Invalidate;
149       end;
150     finally
151       AllOpts.Free;
152     end;
153   except
154     on E: Exception do
155       ShowMessage('Error parsing custom options: '+E.Message);
156   end;
157 end;
158 
159 procedure TCompilerOtherOptionsFrame.btnDefinesClick(Sender: TObject);
160 var
161   EditForm: TDefinesGuiForm;
162 begin
163   EditForm := TDefinesGuiForm.Create(Nil);
164   try
165   try
166     EditForm.OptionsReader := FOptionsReader;
167     EditForm.OptionsThread := FOptionsThread;
168     EditForm.CustomOptions := memoCustomOptions.Lines;
169     EditForm.DefinesCheckList.Items.Assign(FLocalOtherDefines);
170     EditForm.UseComments := FUseComments;
171     if EditForm.ShowModal = mrOK then
172     begin
173       FLocalOtherDefines.Assign(EditForm.DefinesCheckList.Items);
174       // Synchronize with custom options memo
175       EditForm.ToCustomOptions(memoCustomOptions.Lines);
176       memoCustomOptions.Invalidate;
177     end;
178   except
179     on E: Exception do
180       ShowMessage('Error parsing custom options: '+E.Message);
181   end;
182   finally
183     EditForm.Free;
184   end;
185 end;
186 
187 procedure TCompilerOtherOptionsFrame.btnFcUTF8Click(Sender: TObject);
188 begin
189   if NoUtf8RtlSupportYet then
190     memoCustomOptions.Lines.Add(FcUTF8);
191 end;
192 
NoUtf8RtlSupportYetnull193 function TCompilerOtherOptionsFrame.NoUtf8RtlSupportYet: Boolean;
194 begin
195   Result := Pos(FcUTF8, memoCustomOptions.Text) = 0;
196 end;
197 
198 // Events dealing with conditionals SynEdit :
199 
200 procedure TCompilerOtherOptionsFrame.memoCustomOptionsChange(Sender: TObject);
201 begin
202   btnFcUTF8.Enabled := NoUtf8RtlSupportYet;
203 end;
204 
205 procedure TCompilerOtherOptionsFrame.CondSynEditChange(Sender: TObject);
206 begin
207   UpdateStatusBar;
208   IdleConnected := True;
209 end;
210 
211 procedure TCompilerOtherOptionsFrame.CondSynEditKeyPress(Sender: TObject; var Key: char);
212 begin
213   //debugln(['TCompilerOtherOptionsFrame.CondSynEditKeyPress ',ord(Key)]);
214 end;
215 
216 procedure TCompilerOtherOptionsFrame.CondSynEditProcessUserCommand(Sender: TObject;
217   var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
218 begin
219   if (Command=ecWordCompletion) or (Command=ecIdentCompletion) then
220     StartCompletion;
221 end;
222 
223 procedure TCompilerOtherOptionsFrame.CondSynEditStatusChange(Sender: TObject;
224   Changes: TSynStatusChanges);
225 begin
226   if fSynCompletion.TheForm.Visible then
227   begin
228     //debugln(['TCompilerOtherOptionsFrame.CondSynEditStatusChange ']);
229     fSynCompletion.CurrentString := GetCondCursorWord;
230   end;
231   UpdateStatusBar;
232 end;
233 
234 procedure TCompilerOtherOptionsFrame.OnSynCompletionCancel(Sender: TObject);
235 begin
236   {$IFDEF VerboseCOCondSynCompletion}
237   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionCancel ',fSynCompletion.TheForm.Visible]);
238   {$ENDIF}
239   if fSynCompletion.TheForm.Visible then
240     fSynCompletion.Deactivate;
241   fSynCompletion.RemoveEditor(CondSynEdit);
242   //fSynCompletion.Editor:=nil;
243 end;
244 
245 procedure TCompilerOtherOptionsFrame.OnSynCompletionExecute(Sender: TObject);
246 begin
247   {$IFDEF VerboseCOCondSynCompletion}
248   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionExecute ']);
249   {$ENDIF}
250 end;
251 
252 procedure TCompilerOtherOptionsFrame.OnSynCompletionKeyCompletePrefix(
253   Sender: TObject);
254 begin
255   {$IFDEF VerboseCOCondSynCompletion}
256   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionKeyCompletePrefix ToDo']);
257   {$ENDIF}
258 end;
259 
260 procedure TCompilerOtherOptionsFrame.OnSynCompletionKeyDelete(Sender: TObject);
261 begin
262   {$IFDEF VerboseCOCondSynCompletion}
263   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionKeyDelete']);
264   {$ENDIF}
265 end;
266 
267 procedure TCompilerOtherOptionsFrame.OnSynCompletionKeyDown(Sender: TObject;
268   var Key: Word; Shift: TShiftState);
269 begin
270   {$IFDEF VerboseCOCondSynCompletion}
271   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionKeyDown ']);
272   {$ENDIF}
273   if Key=VK_BACK then
274   begin
275     Key:=VK_UNKNOWN;
276     if fSynCompletion.CurrentString<>'' then
277       CondSynEdit.CommandProcessor(ecDeleteLastChar,#0,nil);
278   end;
279 end;
280 
281 procedure TCompilerOtherOptionsFrame.OnSynCompletionKeyNextChar(Sender: TObject);
282 var
283   XY: TPoint;
284   StartX: integer;
285   EndX: integer;
286   Line: string;
287 begin
288   {$IFDEF VerboseCOCondSynCompletion}
289   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionKeyNextChar ']);
290   {$ENDIF}
291   XY:=CondSynEdit.LogicalCaretXY;
292   if XY.Y>CondSynEdit.Lines.Count then exit;
293   CondSynEdit.GetWordBoundsAtRowCol(XY,StartX,EndX);
294   if EndX<=XY.X then exit;
295   Line := CondSynEdit.Lines[XY.Y - 1];
296   inc(XY.X,UTF8CodepointSize(@Line[XY.X-1]));
297   CondSynEdit.LogicalCaretXY:=XY;
298 end;
299 
300 procedure TCompilerOtherOptionsFrame.OnSynCompletionKeyPrevChar(Sender: TObject);
301 var
302   XY: TPoint;
303   StartX: integer;
304   EndX: integer;
305   Line: string;
306 begin
307   {$IFDEF VerboseCOCondSynCompletion}
308   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionKeyPrevChar ']);
309   {$ENDIF}
310   XY:=CondSynEdit.LogicalCaretXY;
311   if XY.Y>CondSynEdit.Lines.Count then exit;
312   CondSynEdit.GetWordBoundsAtRowCol(XY,StartX,EndX);
313   if StartX>=XY.X then exit;
314   Line := CondSynEdit.Lines[XY.Y - 1];
315   XY.X:=UTF8FindNearestCharStart(PChar(Line),length(Line),XY.X-2)+1;
316   CondSynEdit.LogicalCaretXY:=XY;
317 end;
318 
319 procedure TCompilerOtherOptionsFrame.OnSynCompletionSearchPosition(var Position: integer);
320 var
321   sl: TStringList;
322   Prefix: String;
323   s: string;
324   i: Integer;
325 begin
326   {$IFDEF VerboseCOCondSynCompletion}
327   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionSearchPosition "',fSynCompletion.CurrentString,'"']);
328   {$ENDIF}
329   Prefix:=fSynCompletion.CurrentString;
330   sl:=TStringList.Create;
331   try
332     Position:=-1;
333     for i:=0 to CompletionValues.Count-1 do
334     begin
335       s:=CompletionValues[i];
336       if SysUtils.CompareText(Prefix,copy(s,1,length(Prefix)))<>0 then continue;
337       if (Position<0) or (length(Prefix)=length(s)) then
338         Position:=sl.Count;
339       sl.AddObject(s,TObject({%H-}Pointer(i)));
340     end;
341     fSynCompletion.ItemList.Assign(sl);
342   finally
343     sl.Free;
344   end;
345 end;
346 
347 procedure TCompilerOtherOptionsFrame.OnSynCompletionUTF8KeyPress(Sender: TObject;
348   var UTF8Key: TUTF8Char);
349 begin
350   {$IFDEF VerboseCOCondSynCompletion}
351   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionUTF8KeyPress ']);
352   {$ENDIF}
353 end;
354 
355 procedure TCompilerOtherOptionsFrame.OnSynCompletionValidate(Sender: TObject;
356   KeyChar: TUTF8Char; Shift: TShiftState);
357 var
358   i: LongInt;
359   s: string;
360   p: LongInt;
361   TxtXY: TPoint;
362   TxtStartX: integer;
363   TxtEndX: integer;
364 begin
365   {$IFDEF VerboseCOCondSynCompletion}
366   debugln(['TCompilerOtherOptionsFrame.OnSynCompletionValidate ']);
367   {$ENDIF}
368   i:=fSynCompletion.Position;
369   if (i>=0) and (i<fSynCompletion.ItemList.Count) then begin
370     i:=PtrUInt(fSynCompletion.ItemList.Objects[i]);
371     if (i>=0) and (i<CompletionValues.Count) then begin
372       s:=CompletionValues[i];
373       p:=System.Pos(#9,s);
374       if p>0 then s:=copy(s,1,p-1);
375       TxtXY:=CondSynEdit.LogicalCaretXY;
376       CondSynEdit.GetWordBoundsAtRowCol(TxtXY,TxtStartX,TxtEndX);
377       CondSynEdit.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TCompilerOtherOptionsFrame.OnSynCompletionValidate'){$ENDIF};
378       try
379         CondSynEdit.BlockBegin:=Point(TxtStartX,TxtXY.Y);
380         CondSynEdit.BlockEnd:=Point(TxtEndX,TxtXY.Y);
381         CondSynEdit.SelText:=s;
382       finally
383         CondSynEdit.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TCompilerOtherOptionsFrame.OnSynCompletionValidate'){$ENDIF};
384       end;
385       FCompletionHistory.Insert(0,s);
386       if FCompletionHistory.Count>100 then
387         FCompletionHistory.Delete(FCompletionHistory.Count-1);
388     end;
389   end;
390 
391   fSynCompletion.Deactivate;
392 end;
393 
394 procedure TCompilerOtherOptionsFrame.SetVisible(Value: Boolean);
395 begin
396   inherited SetVisible(Value);
397   // Read all compiler options when the page is shown for the first time.
398   if Value then begin
399     if Assigned(fOptionsThread) then
400     begin
401       fOptionsThread.EndParsing;       // Make sure the thread has finished running.
402       if FOptionsReader.UpdateTargetParam then begin
403         FOptionsReader.Clear;
404         fOptionsThread.StartParsing;   // Read new options.
405       end;
406     end
407     else begin
408       fOptionsThread := TCompilerOptThread.Create(FOptionsReader);
409       fOptionsThread.StartParsing;
410     end;
411   end;
412 end;
413 
414 procedure TCompilerOtherOptionsFrame.SetStatusMessage(const AValue: string);
415 begin
416   if FStatusMessage=AValue then exit;
417   FStatusMessage:=AValue;
418   CondStatusbar.Panels[2].Text := FStatusMessage;
419 end;
420 
421 procedure TCompilerOtherOptionsFrame.SetIdleConnected(AValue: Boolean);
422 begin
423   if csDestroying in ComponentState then
424     AValue:=false;
425   if FIdleConnected=AValue then exit;
426   FIdleConnected:=AValue;
427   if FIdleConnected then
428     Application.AddOnIdleHandler(@OnIdle)
429   else
430     Application.RemoveOnIdleHandler(@OnIdle);
431 end;
432 
433 procedure TCompilerOtherOptionsFrame.StartCompletion;
434 
EditorRowColumnToCompletionXYnull435   function EditorRowColumnToCompletionXY(ScreenRowCol: TPoint;
436     AboveRow: boolean): TPoint;
437   begin
438     if not AboveRow then
439       inc(ScreenRowCol.Y,1);
440     Result:=CondSynEdit.RowColumnToPixels(ScreenRowCol);
441     Result:=CondSynEdit.ClientToScreen(Result);
442     if fSynCompletion.TheForm.Parent<>nil then
443       Result:=fSynCompletion.TheForm.Parent.ScreenToClient(Result);
444   end;
445 
446 var
447   LogStartX: integer;
448   LogEndX: integer;
449   LogXY: TPoint;
450   ScreenXY: TPoint;
451   XY: TPoint;
452   Line: String;
453 begin
454   {$IFDEF VerboseCOCondSynCompletion}
455   debugln(['TCompOptBuildMacrosFrame.StartCompletion START']);
456   {$ENDIF}
457   UpdateCompletionValues;
458   fSynCompletion.ItemList.Assign(CompletionValues);
459 
460   // get row and column of word start at cursor
461   LogXY:=CondSynEdit.LogicalCaretXY;
462   CondSynEdit.GetWordBoundsAtRowCol(LogXY,LogStartX,LogEndX);
463   LogEndX:=Min(LogEndX,LogXY.X);
464   // convert text row,column to screen row,column
465   ScreenXY:=CondSynEdit.PhysicalToLogicalPos(Point(LogStartX,LogXY.Y));
466   // convert screen row,column to coordinates for the completion form
467   XY:=EditorRowColumnToCompletionXY(ScreenXY,false);
468 
469   if XY.Y+fSynCompletion.TheForm.Height>fSynCompletion.TheForm.Parent.ClientHeight
470   then begin
471     // place completion above text
472     XY:=EditorRowColumnToCompletionXY(ScreenXY,true);
473     dec(XY.Y,fSynCompletion.TheForm.Height);
474   end;
475 
476   // show completion box
477   //fSynCompletion.AddEditor(CondSynEdit);
478   fSynCompletion.Editor:=CondSynEdit;
479   Line:=CondSynEdit.LineText;
480   fSynCompletion.Execute(copy(Line,LogStartX,LogEndX-LogStartX),XY.X,XY.Y);
481   debugln(['TCompilerOtherOptionsFrame.StartCompletion XY=',dbgs(XY),' fSynCompletion.TheForm.BoundsRect=',dbgs(fSynCompletion.TheForm.BoundsRect)]);
482 end;
483 
484 procedure TCompilerOtherOptionsFrame.UpdateCompletionValues;
485 
HasWordnull486   function HasWord(const aName: string): Boolean;
487   var
488     i: Integer;
489     s: string;
490     p: LongInt;
491   begin
492     for i:=0 to CompletionValues.Count-1 do begin
493       s:=CompletionValues[i];
494       p:=System.Pos(#9,s);
495       if p>0 then
496         s:=copy(s,1,p-1);
497       if SysUtils.CompareText(s,aName)=0 then exit(true);
498     end;
499     Result:=false;
500   end;
501 
502   procedure AddKeyword(aName: string);
503   begin
504     CompletionValues.Add(aName);
505   end;
506 
507   procedure AddWord(aName: string);
508   begin
509     aName:=dbgstr(aName);
510     if aName='' then exit;
511     if HasWord(aName) then exit;
512     CompletionValues.Add(aName);
513   end;
514 
515   procedure AddVar(aName, aValue: string);
516   var
517     s: String;
518   begin
519     aName:=dbgstr(aName);
520     if aName='' then exit;
521     if HasWord(aName) then exit;
522     s:=dbgstr(aValue);
523     if length(s)>50 then s:=copy(s,1,50)+'...';
524     s:=aName+#9+aValue;
525     CompletionValues.Add(s);
526   end;
527 
528 var
529   Node: TAVLTreeNode;
530   V: PCTCfgScriptVariable;
531   s: String;
532   p: PChar;
533   AtomStart: PChar;
534   pcov: TParsedCompilerOptString;
535   pcouv: TParsedCompilerOptString;
536   i: Integer;
537   j: Integer;
538   Macro: TLazBuildMacro;
539 begin
540   CompletionValues.Clear;
541 
542   // add default variables with values
543   Node:=DefaultVariables.Tree.FindLowest;
544   while Node<>nil do begin
545     V:=PCTCfgScriptVariable(Node.Data);
546     AddVar(V^.Name,GetCTCSVariableAsString(V));
547     Node:=DefaultVariables.Tree.FindSuccessor(Node);
548   end;
549 
550   // add keywords and operands
551   AddKeyword('if');
552   AddKeyword('then');
553   AddKeyword('else');
554   AddKeyword('begin');
555   AddKeyword('end');
556   AddKeyword('not');
557   AddKeyword('and');
558   AddKeyword('or');
559   AddKeyword('xor');
560   AddKeyword('undefine');
561   AddKeyword('defined');
562   AddKeyword('undefined');
563   AddKeyword('integer');
564   AddKeyword('int64');
565   AddKeyword('string');
566   AddKeyword('true');
567   AddKeyword('false');
568 
569   // add IDE functions
570   AddWord('GetIDEValue(''OS'')');
571   AddWord('GetIDEValue(''CPU'')');
572   AddWord('GetIDEValue(''SrcOS'')');
573   AddWord('GetIDEValue(''SrcOS2'')');
574   AddWord('GetIDEValue(''LCLWidgetType'')');
575   AddWord('GetEnv(''USER'')');
576   AddWord('GetEnv(''HOME'')');
577   if FCompOptions is TPkgCompilerOptions then
578     AddWord('GetProjValue(''FPC_FULLVERSION'')');
579 
580   // add result variables
581   for pcov:=low(ParsedCompilerOptsVars) to high(ParsedCompilerOptsVars) do
582     AddWord(ParsedCompilerOptsVars[pcov]);
583   if FIsPackage then
584     for pcouv:=low(ParsedCompilerOptsUsageVars) to high(ParsedCompilerOptsUsageVars) do
585       AddWord(ParsedCompilerOptsUsageVars[pcouv]);
586 
587   // add build macros and values
588   if FCompOptions.BuildMacros<>nil then begin
589     for i:=0 to FCompOptions.BuildMacros.Count-1 do
590     begin
591       Macro:=FCompOptions.BuildMacros[i];
592       AddWord(Macro.Identifier);
593       for j:=0 to Macro.Values.Count-1 do
594         AddWord(Macro.Values[j]);
595     end;
596   end;
597 
598   // add words in text
599   s:=CondSynEdit.Lines.Text;
600   if s<>'' then begin
601     p:=PChar(s);
602     repeat
603       AtomStart:=p;
604       while (AtomStart^<>#0) and not IsIdentStartChar[AtomStart^] do
605         inc(AtomStart);
606       if (AtomStart^=#0) then break;
607       p:=AtomStart;
608       while IsIdentChar[p^] do inc(p);
609       AddWord(copy(s,AtomStart-PChar(s)+1,p-AtomStart));
610     until false;
611   end;
612 
613   // sort alphabetically
614   TStringList(FCompletionValues).Sort;
615 
616   // push recently used words upwards
617   for i:=CompletionHistory.Count-1 downto 0 do begin
618     j:=CompletionValues.IndexOf(CompletionHistory[i]);
619     if j>0 then
620       CompletionValues.Move(j,0);
621   end;
622 
623   // set index
624   for i:=0 to CompletionValues.Count-1 do
625     CompletionValues.Objects[i]:=TObject({%H-}Pointer(i));
626 
627   //debugln(['TCompOptBuildMacrosFrame.UpdateCompletionValues ',CompletionValues.Text]);
628 end;
629 
TCompilerOtherOptionsFrame.GetCondCursorWordnull630 function TCompilerOtherOptionsFrame.GetCondCursorWord: string;
631 var
632   XY: TPoint;
633   StartX: integer;
634   EndX: integer;
635   Line: string;
636 begin
637   XY := CondSynEdit.LogicalCaretXY;
638   if (XY.Y>=1) and (XY.Y<=CondSynEdit.Lines.Count) then
639   begin
640     CondSynEdit.GetWordBoundsAtRowCol(XY,StartX,EndX);
641     //debugln(['TCompOptBuildMacrosFrame.GetCondCursorWord ',StartX,' ',EndX,' ',XY.X]);
642     EndX := Min(EndX,XY.X);
643     Line := CondSynEdit.Lines[XY.Y - 1];
644     Result := Copy(Line, StartX, EndX - StartX);
645   end else
646     Result := '';
647   //debugln(['TCompOptBuildMacrosFrame.GetCondCursorWord "',Result,'"']);
648 end;
649 
650 procedure TCompilerOtherOptionsFrame.UpdateMessages;
651 begin
652   fEngine.Variables.Assign(DefaultVariables);
653   fEngine.Execute(CondSynEdit.Lines.Text,1);
654   if fEngine.ErrorCount>0 then begin
655     StatusMessage:=fEngine.GetErrorStr(0);
656   end else begin
657     StatusMessage:='';
658   end;
659 end;
660 
661 procedure TCompilerOtherOptionsFrame.UpdateStatusBar;
662 var
663   PanelCharMode: String;
664   PanelXY: String;
665 begin
666   PanelXY := Format(' %6d:%4d',[CondSynEdit.CaretY,CondSynEdit.CaretX]);
667   if CondSynEdit.InsertMode then
668     PanelCharMode := uepIns
669   else
670     PanelCharMode := uepOvr;
671 
672   CondStatusbar.Panels[0].Text := PanelXY;
673   CondStatusbar.Panels[1].Text := PanelCharMode;
674 end;
675 
676 procedure TCompilerOtherOptionsFrame.OnIdle(Sender: TObject; var Done: Boolean);
677 begin
678   IdleConnected := False;
679   UpdateMessages;
680 end;
681 
682 constructor TCompilerOtherOptionsFrame.Create(TheOwner: TComponent);
683 begin
684   inherited Create(TheOwner);
685   FLocalOtherDefines:=TStringList.Create;
686   FCompletionValues:=TStringList.Create;
687   FCompletionHistory:=TStringList.Create;
688   fDefaultVariables:=TCTCfgScriptVariables.Create;
689   fEngine:=TIDECfgScriptEngine.Create;
690 
691   CondSynEdit.OnStatusChange:=@CondSynEditStatusChange;
692 
693   fSynCompletion:=TSynCompletion.Create(Self);
694   fSynCompletion.ShowSizeDrag:=true;
695   fSynCompletion.TheForm.Parent:=Self;
696   fSynCompletion.OnExecute:=@OnSynCompletionExecute;
697   fSynCompletion.OnCancel:=@OnSynCompletionCancel;
698   fSynCompletion.OnValidate:=@OnSynCompletionValidate;
699   fSynCompletion.OnSearchPosition:=@OnSynCompletionSearchPosition;
700   fSynCompletion.OnKeyCompletePrefix:=@OnSynCompletionKeyCompletePrefix;
701   fSynCompletion.OnUTF8KeyPress:=@OnSynCompletionUTF8KeyPress;
702   fSynCompletion.OnKeyNextChar:=@OnSynCompletionKeyNextChar;
703   fSynCompletion.OnKeyPrevChar:=@OnSynCompletionKeyPrevChar;
704   fSynCompletion.OnKeyDelete:=@OnSynCompletionKeyDelete;
705   fSynCompletion.OnKeyDown:=@OnSynCompletionKeyDown;
706 
707   FOptionsReader := TCompilerOptReader.Create;
708 end;
709 
710 destructor TCompilerOtherOptionsFrame.Destroy;
711 begin
712   IdleConnected:=false;
713   FreeAndNil(fOptionsThread);
714   FreeAndNil(FOptionsReader);
715   FreeAndNil(fEngine);
716   FreeAndNil(fDefaultVariables);
717   FreeAndNil(FCompletionHistory);
718   FreeAndNil(FCompletionValues);
719   FreeAndNil(FLocalOtherDefines);
720   inherited Destroy;
721 end;
722 
Checknull723 function TCompilerOtherOptionsFrame.Check: Boolean;
724 begin
725   Result := True;
726 end;
727 
TCompilerOtherOptionsFrame.GetTitlenull728 function TCompilerOtherOptionsFrame.GetTitle: string;
729 begin
730   Result := lisCustomOptions3;
731 end;
732 
733 procedure TCompilerOtherOptionsFrame.Setup(ADialog: TAbstractOptionsEditorDialog);
734 begin
735   grpCustomOptions.Caption := lisCustomOptions2;
736   memoCustomOptions.Hint := lisCustomOptHint;
737   grpConditionals.Caption := lisConditionals;
738   btnAllOptions.Caption := lisDlgAllOptions;
739   btnDefines.Caption := lisDlgDefines;
740   btnFcUTF8.Caption := lisAddFcUTF8;
741   btnFcUTF8.Hint := lisAddFcUTF8Hint;
742 end;
743 
744 procedure TCompilerOtherOptionsFrame.ReadSettings(AOptions: TAbstractIDEOptions);
745 var
746   Vars: TCTCfgScriptVariables;
747 begin
748   FCompOptions := AOptions as TBaseCompilerOptions;
749   FIsPackage := FCompOptions is TPkgCompilerOptions;
750   //debugln(['TCompilerOtherOptionsFrame.ReadSettings ',dbgs(Pointer(FCompOptions)),' ',FCompOptions=Project1.CompilerOptions]);
751 
752   CondSynEdit.Lines.Text := FCompOptions.Conditionals;
753   if FHighlighter=nil then
754   begin
755     FHighlighter := TPreviewPasSyn.Create(Self);
756     CondSynEdit.Highlighter:=FHighlighter;
757   end;
758   EditorOpts.ReadHighlighterSettings(FHighlighter, '');
759   EditorOpts.GetSynEditSettings(CondSynEdit);
760 
761   Vars := GetBuildMacroValues(FCompOptions,false);
762   if Vars<>nil then
763     DefaultVariables.Assign(Vars)
764   else
765     DefaultVariables.Clear;
766 
767   // Custom Options
768   memoCustomOptions.Text := FCompOptions.CustomOptions;
769   memoCustomOptions.OnChange(Nil);
770   FUseComments := FCompOptions.UseCommentsInCustomOptions;
771   FLocalOtherDefines.Assign(FCompOptions.OtherDefines);
772 
773   UpdateStatusBar;
774 end;
775 
776 procedure TCompilerOtherOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions);
777 var
778   CurOptions: TBaseCompilerOptions;
779 begin
780   //debugln(['TCompilerOtherOptionsFrame.WriteSettings ',DbgSName(AOptions)]);
781   CurOptions := AOptions as TBaseCompilerOptions;
782   CurOptions.Conditionals := CondSynEdit.Lines.Text;
783   CurOptions.CustomOptions := memoCustomOptions.Text;
784   CurOptions.UseCommentsInCustomOptions := FUseComments;
785   if not CurOptions.OtherDefines.Equals(FLocalOtherDefines) then
786   begin
787     CurOptions.OtherDefines.Assign(FLocalOtherDefines);
788     CurOptions.IncreaseChangeStamp;
789   end;
790 end;
791 
TCompilerOtherOptionsFrame.SupportedOptionsClassnull792 class function TCompilerOtherOptionsFrame.SupportedOptionsClass: TAbstractIDEOptionsClass;
793 begin
794   Result := TBaseCompilerOptions;
795 end;
796 
797 initialization
798   RegisterIDEOptionsEditor(GroupCompiler, TCompilerOtherOptionsFrame,
799     CompilerOptionsOther);
800   RegisterIDEOptionsEditor(GroupPkgCompiler, TCompilerOtherOptionsFrame,
801     CompilerOptionsOther);
802 
803 end.
804 
805