mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 03:01:28 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			803 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			803 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {***************************************************************************
 | |
|  *                                                                         *
 | |
|  *   This source is free software; you can redistribute it and/or modify   *
 | |
|  *   it under the terms of the GNU General Public License as published by  *
 | |
|  *   the Free Software Foundation; either version 2 of the License, or     *
 | |
|  *   (at your option) any later version.                                   *
 | |
|  *                                                                         *
 | |
|  *   This code is distributed in the hope that it will be useful, but      *
 | |
|  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 | |
|  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 | |
|  *   General Public License for more details.                              *
 | |
|  *                                                                         *
 | |
|  *   A copy of the GNU General Public License is available on the World    *
 | |
|  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
 | |
|  *   obtain it by writing to the Free Software Foundation,                 *
 | |
|  *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
 | |
|  *                                                                         *
 | |
|  ***************************************************************************
 | |
| 
 | |
|   Abstract:
 | |
|     Frame to edit build macros and conditionals of compiler options
 | |
|     (project+packages).
 | |
| 
 | |
| }
 | |
| unit Compiler_BuildMacro_Options;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, AVL_Tree, LCLProc, FileUtil, Controls, Forms, StdCtrls,
 | |
|   Grids, LCLType, Buttons, ExtCtrls, Dialogs, ComCtrls, Menus, AvgLvlTree,
 | |
|   SynEdit, SynHighlighterPas, SynEditKeyCmds,
 | |
|   KeywordFuncLists, CodeToolsCfgScript,
 | |
|   IDEImagesIntf,
 | |
|   IDECommands, ProjectIntf, PackageIntf, IDEOptionsIntf, MacroIntf,
 | |
|   CompilerOptions, EditorOptions,
 | |
|   LazarusIDEStrConsts, CompOptsModes, SourceSynEditor, PackageDefs;
 | |
| 
 | |
| type
 | |
|   TCBMNodeType = (
 | |
|     cbmntNone,
 | |
|     cbmntBuildMacro,
 | |
|     cbmntValue
 | |
|     );
 | |
|   TCBMPrefixType = (
 | |
|     cbmpShort,
 | |
|     cbmpMedium,
 | |
|     cbmpLong
 | |
|     );
 | |
| 
 | |
|   { TCompOptBuildMacrosFrame }
 | |
| 
 | |
|   TCompOptBuildMacrosFrame = class(TAbstractIDEOptionsEditor)
 | |
|     BMAddMacroSpeedButton: TSpeedButton;
 | |
|     BMAddMacroValueSpeedButton: TSpeedButton;
 | |
|     BMDeleteSpeedButton: TSpeedButton;
 | |
|     BuildMacroDescriptionEdit: TEdit;
 | |
|     BuildMacroSelectedGroupBox: TGroupBox;
 | |
|     BuildMacrosTreeView: TTreeView;
 | |
|     BuildMacroDefaultLabel: TLabel;
 | |
|     BuildMacroDescriptionLabel: TLabel;
 | |
|     ConditionalsGroupBox: TGroupBox;
 | |
|     CondStatusbar: TStatusBar;
 | |
|     CondSynEdit: TSynEdit;
 | |
|     MacrosGroupBox: TGroupBox;
 | |
|     MacrosSplitter: TSplitter;
 | |
|     Splitter1: TSplitter;
 | |
|     procedure BMAddMacroSpeedButtonClick(Sender: TObject);
 | |
|     procedure BMAddMacroValueSpeedButtonClick(Sender: TObject);
 | |
|     procedure BMDeleteSpeedButtonClick(Sender: TObject);
 | |
|     procedure BuildMacrosTreeViewEdited(Sender: TObject; Node: TTreeNode;
 | |
|       var S: string);
 | |
|     procedure BuildMacrosTreeViewEditing(Sender: TObject; Node: TTreeNode;
 | |
|       var AllowEdit: Boolean);
 | |
|     procedure BuildMacrosTreeViewSelectionChanged(Sender: TObject);
 | |
|     procedure CondSynEditChange(Sender: TObject);
 | |
|     procedure CondSynEditProcessCommand(Sender: TObject;
 | |
|       var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
 | |
|     procedure CondSynEditProcessUserCommand(Sender: TObject;
 | |
|       var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
 | |
|     procedure CondSynEditStatusChange(Sender: TObject;
 | |
|       Changes: TSynStatusChanges);
 | |
|     procedure OnIdle(Sender: TObject; var Done: Boolean);
 | |
|   private
 | |
|     FCompletionValues: TStrings;
 | |
|     FDefaultVariables: TCTCfgScriptVariables;
 | |
|     FHighlighter: TIDESynFreePasSyn;
 | |
|     FBuildMacros: TIDEBuildMacros;
 | |
|     FIdleConnected: Boolean;
 | |
|     FIsPackage: boolean;
 | |
|     FStatusMessage: string;
 | |
|     fVarImgID: LongInt;
 | |
|     fValueImgID: LongInt;
 | |
|     fDefValueImgID: LongInt;
 | |
|     fEngine: TCTConfigScriptEngine;
 | |
|     procedure SaveItemProperties;
 | |
|     procedure SetBuildMacros(const AValue: TIDEBuildMacros);
 | |
|     procedure RebuildTreeView;
 | |
|     procedure SetIdleConnected(const AValue: Boolean);
 | |
|     procedure SetStatusMessage(const AValue: string);
 | |
|     function TreeViewAddBuildMacro(aBuildMacro: TLazBuildMacro): TTreeNode;
 | |
|     procedure TreeViewAddValue(ValuesTVNode: TTreeNode; aValue: string);
 | |
|     function GetNodeInfo(Node: TTreeNode; out BuildMacro: TLazBuildMacro): TCBMNodeType;
 | |
|     function GetSelectedNode(out aBuildMacro: TLazBuildMacro;
 | |
|                              out NodeType: TCBMNodeType): TTreeNode;
 | |
|     function GetBuildMacroTVNode(aBuildMacro: TLazBuildMacro): TTreeNode;
 | |
|     function GetMacroNamePrefix(PrefixType: TCBMPrefixType): string;
 | |
|     procedure UpdateItemPropertyControls;
 | |
|     procedure UpdateMessages;
 | |
|     procedure UpdateStatusBar;
 | |
|     procedure StartCompletion;
 | |
|     procedure UpdateCompletionValues;
 | |
|   public
 | |
|     constructor Create(TheOwner: TComponent); override;
 | |
|     destructor Destroy; override;
 | |
|     function GetTitle: String; override;
 | |
|     procedure Setup(ADialog: TAbstractOptionsEditorDialog); override;
 | |
|     class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
 | |
|     procedure ReadSettings(AOptions: TAbstractIDEOptions); override;
 | |
|     procedure WriteSettings(AOptions: TAbstractIDEOptions); override;
 | |
|     property BuildMacros: TIDEBuildMacros read FBuildMacros write SetBuildMacros; // local copy
 | |
|     procedure LoadFromOptions(Options: TBaseCompilerOptions);
 | |
|     procedure SaveToOptions(Options: TBaseCompilerOptions);
 | |
|     property IdleConnected: Boolean read FIdleConnected write SetIdleConnected;
 | |
|     property StatusMessage: string read FStatusMessage write SetStatusMessage;
 | |
|     property DefaultVariables: TCTCfgScriptVariables read FDefaultVariables;
 | |
|     property CompletionValues: TStrings read FCompletionValues;
 | |
|     property IsPackage: boolean read FIsPackage;
 | |
|   end;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| {$R *.lfm}
 | |
| 
 | |
| { TCompOptBuildMacrosFrame }
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.OnIdle(Sender: TObject; var Done: Boolean);
 | |
| begin
 | |
|   IdleConnected:=false;
 | |
|   UpdateMessages;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.CondSynEditChange(Sender: TObject);
 | |
| begin
 | |
|   UpdateStatusBar;
 | |
|   IdleConnected:=true;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.CondSynEditProcessCommand(Sender: TObject;
 | |
|   var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
 | |
| begin
 | |
| 
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.CondSynEditProcessUserCommand(
 | |
|   Sender: TObject; var Command: TSynEditorCommand; var AChar: TUTF8Char;
 | |
|   Data: pointer);
 | |
| begin
 | |
|   if (Command=ecWordCompletion) or (Command=ecIdentCompletion) then
 | |
|     StartCompletion;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.CondSynEditStatusChange(Sender: TObject;
 | |
|   Changes: TSynStatusChanges);
 | |
| begin
 | |
|   UpdateStatusBar;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BuildMacrosTreeViewEditing(Sender: TObject;
 | |
|   Node: TTreeNode; var AllowEdit: Boolean);
 | |
| var
 | |
|   BuildProperty: TLazBuildMacro;
 | |
|   NodeType: TCBMNodeType;
 | |
| begin
 | |
|   NodeType:=GetNodeInfo(Node,BuildProperty);
 | |
|   AllowEdit:=NodeType in [cbmntBuildMacro,cbmntValue];
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BuildMacrosTreeViewSelectionChanged(
 | |
|   Sender: TObject);
 | |
| begin
 | |
|   UpdateItemPropertyControls;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BuildMacrosTreeViewEdited(Sender: TObject;
 | |
|   Node: TTreeNode; var S: string);
 | |
| var
 | |
|   BuildMacro: TLazBuildMacro;
 | |
|   NodeType: TCBMNodeType;
 | |
|   ConflictBuildProperty: TIDEBuildMacro;
 | |
|   Index: LongInt;
 | |
|   Prefix: String;
 | |
|   BetterName: String;
 | |
|   DlgResult: TModalResult;
 | |
|   Vars: TCTCfgScriptVariables;
 | |
|   ok: Boolean;
 | |
| begin
 | |
|   NodeType:=GetNodeInfo(Node,BuildMacro);
 | |
|   case NodeType of
 | |
| 
 | |
|   cbmntBuildMacro:
 | |
|     if S<>BuildMacro.Identifier then begin
 | |
|       // rename build macro
 | |
|       ok:=false;
 | |
|       try
 | |
|         // check syntax
 | |
|         if (S='') or (not IsValidIdent(S)) then begin
 | |
|           MessageDlg(lisCCOErrorCaption,
 | |
|             Format(lisInvalidBuildMacroTheBuildMacroMustBeAPascalIdentifie, ['"',
 | |
|               S, '"']),
 | |
|             mtError,[mbCancel],0);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         // check for prefix
 | |
|         Prefix:=GetMacroNamePrefix(cbmpShort);
 | |
|         if (Prefix<>'') and (SysUtils.CompareText(Prefix,copy(S,1,length(Prefix)))<>0)
 | |
|         then  begin
 | |
|           BetterName:=GetMacroNamePrefix(cbmpMedium)+S;
 | |
|           DlgResult:=QuestionDlg('Warning',
 | |
|             'The build macro "'+S+'" does not begin with "'+Prefix+'".',
 | |
|             mtWarning,[mrCancel,mrYes,'Rename to '+BetterName,mrIgnore],0);
 | |
|           if DlgResult=mrIgnore then begin
 | |
|           end else if DlgResult=mrYes then
 | |
|             S:=BetterName
 | |
|           else begin
 | |
|             exit;
 | |
|           end;
 | |
|         end;
 | |
| 
 | |
|         // check for keyword
 | |
|         if WordIsKeyWord.DoItCaseInsensitive(S) then begin
 | |
|           MessageDlg(lisCCOErrorCaption,
 | |
|             Format(lisInvalidBuildMacroTheNameIsAKeyword, [S]),
 | |
|             mtError,[mbCancel],0);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         // check for conflicts with built-in macros
 | |
|         if IDEMacros.IsMacro(s) then begin
 | |
|           MessageDlg(lisCCOErrorCaption,
 | |
|             Format(lisThereIsAlreadyAnIDEMacroWithTheName, [S]),
 | |
|             mtError,[mbCancel],0);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         // check for duplicates
 | |
|         ConflictBuildProperty:=BuildMacros.VarWithIdentifier(S);
 | |
|         if ((ConflictBuildProperty<>nil) and (ConflictBuildProperty<>BuildMacro))
 | |
|         or (SysUtils.CompareText('TargetOS',S)=0)
 | |
|         or (SysUtils.CompareText('SrcOS',S)=0)
 | |
|         or (SysUtils.CompareText('SrcOS2',S)=0)
 | |
|         or (SysUtils.CompareText('TargetCPU',S)=0)
 | |
|         or (SysUtils.CompareText('LCLWidgetType',S)=0)
 | |
|         then begin
 | |
|           MessageDlg(lisCCOErrorCaption,
 | |
|             Format(lisThereIsAlreadyABuildMacroWithTheName, ['"', S, '"']),
 | |
|             mtError,[mbCancel],0);
 | |
|           exit;
 | |
|         end;
 | |
| 
 | |
|         // check for duplicates with used packages
 | |
|         if (BuildMacros<>nil) and (BuildMacros.Owner is TBaseCompilerOptions) then
 | |
|         begin
 | |
|           Vars:=GetBuildMacroValues(TBaseCompilerOptions(BuildMacros.Owner),false);
 | |
|           if (Vars<>nil) and Vars.IsDefined(PChar(S)) then begin
 | |
|             DlgResult:=MessageDlg('Warning',
 | |
|               Format(lisThereIsAlreadyABuildMacroWithTheName, ['"', S, '"']),
 | |
|               mtWarning,[mbCancel,mbIgnore],0);
 | |
|             if DlgResult<>mrIgnore then
 | |
|               exit;
 | |
|           end;
 | |
|         end;
 | |
| 
 | |
|         ok:=true;
 | |
|       finally
 | |
|         if not ok then
 | |
|           S:=BuildMacro.Identifier;
 | |
|       end;
 | |
| 
 | |
|       // rename build macro
 | |
|       BuildMacro.Identifier:=S;
 | |
|     end;
 | |
| 
 | |
|   cbmntValue:
 | |
|     begin
 | |
|       Index:=Node.Index;
 | |
|       Index:=BuildMacro.Values.IndexOf(S);
 | |
|       if (Index>=0) and (Index<>Node.Index) then begin
 | |
|         MessageDlg(lisCCOErrorCaption,
 | |
|           Format(lisDuplicateFoundOfValue, ['"', S, '"']),
 | |
|           mtError,[mbCancel],0);
 | |
|         S:=BuildMacro.Values[Node.Index];
 | |
|         exit;
 | |
|       end;
 | |
|       BuildMacro.Values[Node.Index]:=S;
 | |
|     end;
 | |
| 
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BMAddMacroSpeedButtonClick(Sender: TObject);
 | |
| var
 | |
|   NewIdentifier: String;
 | |
|   NewBuildMacro: TLazBuildMacro;
 | |
|   i: Integer;
 | |
|   TVNode: TTreeNode;
 | |
| begin
 | |
|   i:=1;
 | |
|   repeat
 | |
|     NewIdentifier:=GetMacroNamePrefix(cbmpLong)+IntToStr(BuildMacros.Count+1);
 | |
|     if BuildMacros.IndexOfIdentifier(NewIdentifier)<0 then break;
 | |
|     inc(i);
 | |
|   until false;
 | |
|   NewBuildMacro:=BuildMacros.Add(NewIdentifier);
 | |
|   // add to TreeView
 | |
|   BuildMacrosTreeView.BeginUpdate;
 | |
|   TVNode:=TreeViewAddBuildMacro(NewBuildMacro);
 | |
|   BuildMacrosTreeView.Selected:=TVNode;
 | |
|   BuildMacrosTreeView.EndUpdate;
 | |
|   UpdateItemPropertyControls;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BMAddMacroValueSpeedButtonClick(
 | |
|   Sender: TObject);
 | |
| var
 | |
|   BuildMacro: TLazBuildMacro;
 | |
|   NodeType: TCBMNodeType;
 | |
|   i: Integer;
 | |
|   NewValueStr: String;
 | |
|   ValuesTVNode: TTreeNode;
 | |
| begin
 | |
|   GetSelectedNode(BuildMacro,NodeType);
 | |
|   if BuildMacro=nil then exit;
 | |
|   i:=1;
 | |
|   repeat
 | |
|     NewValueStr:=Format(lisValue2, [IntToStr(i)]);
 | |
|     if BuildMacro.Values.IndexOf(NewValueStr)<0 then break;
 | |
|     inc(i);
 | |
|   until false;
 | |
|   BuildMacro.Values.Add(NewValueStr);
 | |
|   BuildMacrosTreeView.BeginUpdate;
 | |
|   ValuesTVNode:=GetBuildMacroTVNode(BuildMacro);
 | |
|   TreeViewAddValue(ValuesTVNode,NewValueStr);
 | |
|   ValuesTVNode.Expand(true);
 | |
|   BuildMacrosTreeView.EndUpdate;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.BMDeleteSpeedButtonClick(Sender: TObject);
 | |
| var
 | |
|   aBuildMacro: TIDEBuildMacro;
 | |
|   SelTVNode: TTreeNode;
 | |
|   NodeType: TCBMNodeType;
 | |
|   i: LongInt;
 | |
|   aValue: String;
 | |
| begin
 | |
|   SelTVNode:=GetSelectedNode(TLazBuildMacro(aBuildMacro),NodeType);
 | |
|   if aBuildMacro=nil then exit;
 | |
|   if NodeType=cbmntValue then
 | |
|   begin
 | |
|     aValue:=SelTVNode.Text;
 | |
|     if MessageDlg(lisConfirmDelete,
 | |
|       Format(lisDeleteValue, ['"', aValue, '"']),
 | |
|       mtConfirmation,[mbYes,mbCancel],0)<>mrYes
 | |
|     then exit;
 | |
|     i:=aBuildMacro.Values.IndexOf(aValue);
 | |
|     if i>=0 then aBuildMacro.Values.Delete(i);
 | |
|   end else begin
 | |
|     if MessageDlg(lisConfirmDelete,
 | |
|       Format(lisDeleteBuildMacro, ['"', aBuildMacro.Identifier, '"']),
 | |
|       mtConfirmation,[mbYes,mbCancel],0)<>mrYes
 | |
|     then exit;
 | |
|     i:=BuildMacros.IndexOfIdentifier(aBuildMacro.Identifier);
 | |
|     BuildMacros.Delete(i);
 | |
|   end;
 | |
|   BuildMacrosTreeView.BeginUpdate;
 | |
|   SelTVNode.Delete;
 | |
|   BuildMacrosTreeView.EndUpdate;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.SetBuildMacros(
 | |
|   const AValue: TIDEBuildMacros);
 | |
| begin
 | |
|   if FBuildMacros=AValue then exit;
 | |
|   BuildMacros.Assign(AValue);
 | |
|   RebuildTreeView;
 | |
|   UpdateItemPropertyControls;
 | |
|   IdleConnected:=true;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.RebuildTreeView;
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   BuildMacrosTreeView.BeginUpdate;
 | |
|   BuildMacrosTreeView.Items.Clear;
 | |
|   if BuildMacros<>nil then begin
 | |
|     // first level: build macros
 | |
|     for i:=0 to BuildMacros.Count-1 do
 | |
|       TreeViewAddBuildMacro(BuildMacros.Items[i]);
 | |
|   end;
 | |
|   BuildMacrosTreeView.EndUpdate;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.SetIdleConnected(const AValue: Boolean);
 | |
| begin
 | |
|   if FIdleConnected=AValue then exit;
 | |
|   FIdleConnected:=AValue;
 | |
|   if FIdleConnected then
 | |
|     Application.AddOnIdleHandler(@OnIdle)
 | |
|   else
 | |
|     Application.RemoveOnIdleHandler(@OnIdle);
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.SetStatusMessage(const AValue: string);
 | |
| begin
 | |
|   if FStatusMessage=AValue then exit;
 | |
|   FStatusMessage:=AValue;
 | |
|   CondStatusbar.Panels[2].Text := FStatusMessage;
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.TreeViewAddBuildMacro(
 | |
|   aBuildMacro: TLazBuildMacro): TTreeNode;
 | |
| var
 | |
|   Values: TStrings;
 | |
|   i: Integer;
 | |
| begin
 | |
|   // create node for the build macro
 | |
|   Result:=BuildMacrosTreeView.Items.AddObject(nil,aBuildMacro.Identifier,aBuildMacro);
 | |
|   Result.ImageIndex:=fVarImgID;
 | |
|   Result.SelectedIndex:=Result.ImageIndex;
 | |
|   // second level
 | |
|   begin
 | |
|     // a node for each value
 | |
|     Values:=aBuildMacro.Values;
 | |
|     for i:=0 to Values.Count-1 do
 | |
|       TreeViewAddValue(Result,Values[i]);
 | |
|   end;
 | |
|   //DebugLn(['TCompOptBuildMacrosFrame.TreeViewAddBuildMacro ',TVNode.Text]);
 | |
|   Result.Expand(true);
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.TreeViewAddValue(ValuesTVNode: TTreeNode;
 | |
|   aValue: string);
 | |
| var
 | |
|   ValueTVNode: TTreeNode;
 | |
| begin
 | |
|   ValueTVNode:=BuildMacrosTreeView.Items.AddChild(ValuesTVNode,aValue);
 | |
|   ValueTVNode.ImageIndex:=fValueImgID;
 | |
|   ValueTVNode.SelectedIndex:=ValueTVNode.ImageIndex;
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.GetNodeInfo(Node: TTreeNode; out
 | |
|   BuildMacro: TLazBuildMacro): TCBMNodeType;
 | |
| 
 | |
|   function GetNodeType(CurNode: TTreeNode): TCBMNodeType;
 | |
|   var
 | |
|     ParentType: TCBMNodeType;
 | |
|   begin
 | |
|     if CurNode=nil then
 | |
|       Result:=cbmntNone
 | |
|     else if TObject(CurNode.Data) is TLazBuildMacro then begin
 | |
|       BuildMacro:=TLazBuildMacro(CurNode.Data);
 | |
|       Result:=cbmntBuildMacro;
 | |
|     end else begin
 | |
|       ParentType:=GetNodeType(CurNode.Parent);
 | |
|       case ParentType of
 | |
|       cbmntBuildMacro:
 | |
|         Result:=cbmntValue;
 | |
|       end;
 | |
|     end;
 | |
|   end;
 | |
| 
 | |
| begin
 | |
|   BuildMacro:=nil;
 | |
|   Result:=GetNodeType(Node);
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.GetSelectedNode(out
 | |
|   aBuildMacro: TLazBuildMacro; out NodeType: TCBMNodeType): TTreeNode;
 | |
| begin
 | |
|   Result:=BuildMacrosTreeView.Selected;
 | |
|   NodeType:=GetNodeInfo(Result,aBuildMacro);
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.GetBuildMacroTVNode(aBuildMacro: TLazBuildMacro
 | |
|   ): TTreeNode;
 | |
| begin
 | |
|   Result:=BuildMacrosTreeView.Items.GetFirstNode;
 | |
|   while (Result<>nil) and (TObject(Result.Data)<>aBuildMacro) do
 | |
|     Result:=Result.GetNextSibling;
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.GetMacroNamePrefix(PrefixType: TCBMPrefixType
 | |
|   ): string;
 | |
| begin
 | |
|   if PrefixType=cbmpShort then
 | |
|     Result:=''
 | |
|   else
 | |
|     Result:='BuildMacro';
 | |
|   if (BuildMacros=nil) or (BuildMacros.Owner=nil) then exit;
 | |
|   if BuildMacros.Owner is TPkgCompilerOptions then
 | |
|   begin
 | |
|     Result:=TPkgCompilerOptions(BuildMacros.Owner).LazPackage.Name;
 | |
|     if ord(PrefixType)>=ord(cbmpMedium) then
 | |
|       Result:=Result+'_';
 | |
|     if PrefixType=cbmpLong then
 | |
|       Result:=Result+'macro';
 | |
|   end;
 | |
| 
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.UpdateItemPropertyControls;
 | |
| var
 | |
|   aBuildMacro: TLazBuildMacro;
 | |
|   NodeType: TCBMNodeType;
 | |
| begin
 | |
|   GetSelectedNode(aBuildMacro,NodeType);
 | |
|   if aBuildMacro<>nil then begin
 | |
|     BuildMacroSelectedGroupBox.Caption:='Macro '+aBuildMacro.Identifier;
 | |
|     BuildMacroSelectedGroupBox.Enabled:=true;
 | |
|     BuildMacroDescriptionEdit.Enabled:=true;
 | |
|     BuildMacroDescriptionEdit.Text:=aBuildMacro.Description;
 | |
|     BMAddMacroValueSpeedButton.Hint:='Add value to macro '+aBuildMacro.Identifier;
 | |
|     BMDeleteSpeedButton.Hint:='Delete macro '+aBuildMacro.Identifier;
 | |
|   end else begin
 | |
|     BuildMacroSelectedGroupBox.Caption:='No macro selected';
 | |
|     BuildMacroSelectedGroupBox.Enabled:=false;
 | |
|     BuildMacroDescriptionEdit.Enabled:=false;
 | |
|     BuildMacroDescriptionEdit.Text:='';
 | |
|     BMAddMacroValueSpeedButton.Hint:='';
 | |
|     BMDeleteSpeedButton.Hint:='';
 | |
|   end;
 | |
|   BMAddMacroSpeedButton.Hint:='Add new macro';
 | |
|   BMAddMacroValueSpeedButton.Enabled:=NodeType in [cbmntBuildMacro,cbmntValue];
 | |
|   BMDeleteSpeedButton.Enabled:=NodeType in [cbmntBuildMacro,cbmntValue];
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.UpdateMessages;
 | |
| begin
 | |
|   fEngine.Variables.Assign(DefaultVariables);
 | |
|   fEngine.Execute(CondSynEdit.Lines.Text,1);
 | |
|   if fEngine.ErrorCount>0 then begin
 | |
|     StatusMessage:=fEngine.GetErrorStr(0);
 | |
|   end else begin
 | |
|     StatusMessage:='No errors';
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.UpdateStatusBar;
 | |
| var
 | |
|   PanelCharMode: String;
 | |
|   PanelXY: String;
 | |
| begin
 | |
|   PanelXY := Format(' %6d:%4d',[CondSynEdit.CaretY,CondSynEdit.CaretX]);
 | |
|   if CondSynEdit.InsertMode then
 | |
|     PanelCharMode := uepIns
 | |
|   else
 | |
|     PanelCharMode := uepOvr;
 | |
| 
 | |
|   CondStatusbar.Panels[0].Text := PanelXY;
 | |
|   CondStatusbar.Panels[1].Text := PanelCharMode;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.StartCompletion;
 | |
| begin
 | |
|   UpdateCompletionValues;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.UpdateCompletionValues;
 | |
| 
 | |
|   function HasWord(const aName: string): Boolean;
 | |
|   var
 | |
|     i: Integer;
 | |
|     s: string;
 | |
|     p: LongInt;
 | |
|   begin
 | |
|     for i:=0 to CompletionValues.Count-1 do begin
 | |
|       s:=CompletionValues[i];
 | |
|       p:=System.Pos(#9,s);
 | |
|       if p>0 then
 | |
|         s:=copy(s,1,p-1);
 | |
|       if SysUtils.CompareText(s,aName)=0 then exit(true);
 | |
|     end;
 | |
|     Result:=false;
 | |
|   end;
 | |
| 
 | |
|   procedure AddVar(aName, aValue: string);
 | |
|   var
 | |
|     s: String;
 | |
|   begin
 | |
|     s:=dbgstr(aValue);
 | |
|     if length(s)>50 then s:=copy(s,1,50)+'...';
 | |
|     s:=aName+#9+aValue;
 | |
|     CompletionValues.Add(s);
 | |
|   end;
 | |
| 
 | |
|   procedure AddKeyword(aName: string);
 | |
|   begin
 | |
|     CompletionValues.Add(aName);
 | |
|   end;
 | |
| 
 | |
|   procedure AddWord(aName: string);
 | |
|   begin
 | |
|     aName:=dbgstr(aName);
 | |
|     if aName='' then exit;
 | |
|     if HasWord(aName) then exit;
 | |
|     CompletionValues.Add(aName);
 | |
|   end;
 | |
| 
 | |
| var
 | |
|   Node: TAVLTreeNode;
 | |
|   V: PCTCfgScriptVariable;
 | |
|   s: String;
 | |
|   p: PChar;
 | |
|   AtomStart: PChar;
 | |
|   Macro: TLazBuildMacro;
 | |
|   pcov: TParsedCompilerOptString;
 | |
|   pcouv: TParsedCompilerOptString;
 | |
|   i: Integer;
 | |
|   j: Integer;
 | |
| begin
 | |
|   CompletionValues.Clear;
 | |
| 
 | |
|   // add default variables with values
 | |
|   Node:=DefaultVariables.Tree.FindLowest;
 | |
|   while Node<>nil do begin
 | |
|     V:=PCTCfgScriptVariable(Node.Data);
 | |
|     AddVar(V^.Name,GetCTCSVariableAsString(V));
 | |
|     Node:=DefaultVariables.Tree.FindSuccessor(Node);
 | |
|   end;
 | |
| 
 | |
|   // add keywords and operands
 | |
|   AddKeyword('if');
 | |
|   AddKeyword('then');
 | |
|   AddKeyword('else');
 | |
|   AddKeyword('begin');
 | |
|   AddKeyword('end');
 | |
|   AddKeyword('not');
 | |
|   AddKeyword('and');
 | |
|   AddKeyword('or');
 | |
|   AddKeyword('xor');
 | |
|   AddKeyword('undefine');
 | |
|   AddKeyword('defined');
 | |
|   AddKeyword('undefined');
 | |
|   AddKeyword('integer');
 | |
|   AddKeyword('int64');
 | |
|   AddKeyword('string');
 | |
|   AddKeyword('true');
 | |
|   AddKeyword('false');
 | |
| 
 | |
|   // add result variables
 | |
|   for pcov:=low(ParsedCompilerOptsVars) to high(ParsedCompilerOptsVars) do
 | |
|     AddWord(ParsedCompilerOptsVars[pcov]);
 | |
|   if FIsPackage then
 | |
|     for pcouv:=low(ParsedCompilerOptsUsageVars) to high(ParsedCompilerOptsUsageVars) do
 | |
|       AddWord(ParsedCompilerOptsUsageVars[pcouv]);
 | |
| 
 | |
|   // add build macros and values
 | |
|   if BuildMacros<>nil then begin
 | |
|     for i:=0 to BuildMacros.Count-1 do
 | |
|     begin
 | |
|       Macro:=BuildMacros[i];
 | |
|       AddWord(Macro.Identifier);
 | |
|       for j:=0 to Macro.Values.Count-1 do
 | |
|         AddWord(Macro.Values[j]);
 | |
|     end;
 | |
|   end;
 | |
| 
 | |
|   // add words in text
 | |
|   s:=CondSynEdit.Lines.Text;
 | |
|   if s<>'' then begin
 | |
|     p:=PChar(s);
 | |
|     repeat
 | |
|       AtomStart:=p;
 | |
|       while (AtomStart^<>#0) and not IsIdentStartChar[AtomStart^] do
 | |
|         inc(AtomStart);
 | |
|       if (AtomStart^=#0) then break;
 | |
|       p:=AtomStart;
 | |
|       while IsIdentChar[p^] do inc(p);
 | |
|       AddWord(copy(s,AtomStart-PChar(s)+1,p-AtomStart));
 | |
|     until false;
 | |
|   end;
 | |
| 
 | |
|   debugln(['TCompOptBuildMacrosFrame.UpdateCompletionValues ',CompletionValues.Text]);
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.SaveItemProperties;
 | |
| var
 | |
|   BuildMacro: TLazBuildMacro;
 | |
|   NodeType: TCBMNodeType;
 | |
| begin
 | |
|   GetSelectedNode(BuildMacro,NodeType);
 | |
|   if BuildMacro=nil then exit;
 | |
|   BuildMacro.Description:=BuildMacroDescriptionEdit.Text;
 | |
| end;
 | |
| 
 | |
| constructor TCompOptBuildMacrosFrame.Create(TheOwner: TComponent);
 | |
| begin
 | |
|   inherited Create(TheOwner);
 | |
| 
 | |
|   FCompletionValues:=TStringList.Create;
 | |
|   fDefaultVariables:=TCTCfgScriptVariables.Create;
 | |
|   FBuildMacros:=TIDEBuildMacros.Create(nil);
 | |
|   fEngine:=TCTConfigScriptEngine.Create;
 | |
| 
 | |
|   MacrosGroupBox.Caption:='Build macros:';
 | |
|   BuildMacrosTreeView.Images := IDEImages.Images_24;
 | |
|   fVarImgID:=IDEImages.LoadImage(24,'da_define');
 | |
|   fValueImgID:=IDEImages.LoadImage(24,'da_define');
 | |
|   fDefValueImgID:=IDEImages.LoadImage(24,'da_define');
 | |
| 
 | |
|   BuildMacroDefaultLabel.Caption:='Hint: A default value can be defined in the conditionals.';
 | |
|   BuildMacroDescriptionLabel.Caption:='Description:';
 | |
| 
 | |
|   ConditionalsGroupBox.Caption:='Conditionals:';
 | |
| 
 | |
|   CondSynEdit.OnStatusChange:=@CondSynEditStatusChange;
 | |
| 
 | |
|   BMAddMacroSpeedButton.LoadGlyphFromLazarusResource('laz_add');
 | |
|   BMAddMacroValueSpeedButton.LoadGlyphFromLazarusResource('laz_add');
 | |
|   BMDeleteSpeedButton.LoadGlyphFromLazarusResource('laz_delete');
 | |
| end;
 | |
| 
 | |
| destructor TCompOptBuildMacrosFrame.Destroy;
 | |
| begin
 | |
|   FreeAndNil(FCompletionValues);
 | |
|   FreeAndNil(fDefaultVariables);
 | |
|   FreeAndNil(fEngine);
 | |
|   FreeAndNil(FBuildMacros);
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| function TCompOptBuildMacrosFrame.GetTitle: String;
 | |
| begin
 | |
|   Result:='Build macros';
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.ReadSettings(AOptions: TAbstractIDEOptions);
 | |
| begin
 | |
|   if AOptions is TBaseCompilerOptions then
 | |
|     LoadFromOptions(TBaseCompilerOptions(AOptions));
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.Setup(ADialog: TAbstractOptionsEditorDialog
 | |
|   );
 | |
| begin
 | |
| end;
 | |
| 
 | |
| class function TCompOptBuildMacrosFrame.SupportedOptionsClass: TAbstractIDEOptionsClass;
 | |
| begin
 | |
|   Result := TBaseCompilerOptions;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.WriteSettings(AOptions: TAbstractIDEOptions
 | |
|   );
 | |
| begin
 | |
|   if AOptions is TBaseCompilerOptions then
 | |
|     SaveToOptions(TBaseCompilerOptions(AOptions));
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.LoadFromOptions(Options: TBaseCompilerOptions
 | |
|   );
 | |
| var
 | |
|   Vars: TCTCfgScriptVariables;
 | |
| begin
 | |
|   FIsPackage:=Options is TPkgCompilerOptions;
 | |
| 
 | |
|   BuildMacros:=Options.BuildMacros as TIDEBuildMacros;
 | |
|   Vars:=GetBuildMacroValues(Options,false);
 | |
|   if Vars<>nil then
 | |
|     DefaultVariables.Assign(Vars);
 | |
| 
 | |
|   CondSynEdit.Lines.Text:=Options.Conditionals;
 | |
|   EditorOpts.GetSynEditSettings(CondSynEdit);
 | |
|   if FHighlighter=nil then
 | |
|   begin
 | |
|     FHighlighter := TPreviewPasSyn.Create(Self);
 | |
|     CondSynEdit.Highlighter:=FHighlighter;
 | |
|   end;
 | |
|   EditorOpts.ReadHighlighterSettings(FHighlighter, '');
 | |
|   UpdateStatusBar;
 | |
| end;
 | |
| 
 | |
| procedure TCompOptBuildMacrosFrame.SaveToOptions(Options: TBaseCompilerOptions
 | |
|   );
 | |
| begin
 | |
|   SaveItemProperties;
 | |
|   (Options.BuildMacros as TIDEBuildMacros).Assign(BuildMacros);
 | |
|   Options.Conditionals:=CondSynEdit.Lines.Text;
 | |
| end;
 | |
| 
 | |
| {$IFDEF EnableBuildModes}
 | |
| initialization
 | |
|   RegisterIDEOptionsEditor(GroupCompiler, TCompOptBuildMacrosFrame,
 | |
|     CompilerOptionsConditional);
 | |
| {$ENDIF}
 | |
| 
 | |
| end.
 | |
| 
 | 
