{ *************************************************************************** * * * 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 . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: A dialog for adding and editing code templates } unit CodeTemplatesDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, LCLProc, LResources, Forms, Controls, Graphics, Dialogs, ClipBrd, StdCtrls, Buttons, ExtCtrls, Menus, FileUtil, SynEdit, SynHighlighterPas, SynEditAutoComplete, CodeToolManager, CodeCache, PascalParserTool, IDECommands, TextTools, SrcEditorIntf, MenuIntf, IDEWindowIntf, LazIDEIntf, IDEProcs, InputHistory, LazarusIDEStrConsts, EditorOptions, CodeMacroSelect; type { TCodeTemplateDialog } TCodeTemplateDialog = class(TForm) AddButton: TButton; OkButton: TBitBtn; CancelButton: TBitBtn; InsertMacroButton: TButton; UseMacrosCheckBox: TCheckBox; EditButton: TButton; DeleteButton: TButton; TemplateListBox: TListBox; TemplateSynEdit: TSynEdit; ASynPasSyn: TSynPasSyn; TemplateGroupBox: TGroupBox; FilenameButton: TButton; FilenameEdit: TEdit; FilenameGroupBox: TGroupBox; MainPopupMenu: TPopupMenu; procedure AddButtonClick(Sender: TObject); procedure DeleteButtonClick(Sender: TObject); procedure EditButtonClick(Sender: TObject); procedure FilenameButtonClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure InsertMacroButtonClick(Sender: TObject); procedure OkButtonClick(Sender: TObject); procedure OnCopyMenuItem(Sender: TObject); procedure OnCutMenuItem(Sender: TObject); procedure OnInsertMacroMenuItem(Sender: TObject); procedure OnPasteMenuItem(Sender: TObject); procedure TemplateListBoxSelectionChange(Sender: TObject; User: boolean); private SynAutoComplete: TSynEditAutoComplete; LastTemplate: integer; procedure BuildPopupMenu; procedure DoInsertMacro; public procedure FillCodeTemplateListBox; procedure ShowCurCodeTemplate; procedure SaveCurCodeTemplate; end; { TCodeTemplateEditForm } TCodeTemplateEditForm = class(TForm) TokenLabel: TLabel; TokenEdit: TEdit; CommentLabel: TLabel; CommentEdit: TEdit; OkButton: TButton; CancelButton: TButton; procedure CodeTemplateEditFormResize(Sender: TObject); procedure OkButtonClick(Sender: TObject); public constructor Create(TheOwner: TComponent); override; SynAutoComplete: TSynEditAutoComplete; TemplateIndex: integer; end; { TLazCodeMacros } TLazCodeMacros = class(TIDECodeMacros) private FItems: TFPList; // list of TIDECodeMacro protected function GetItems(Index: integer): TIDECodeMacro; override; public constructor Create; destructor Destroy; override; procedure Clear; property Items[Index: integer]: TIDECodeMacro read GetItems; default; function Count: integer; override; function Add(Macro: TIDECodeMacro): integer; override; function FindByName(const AName: string): TIDECodeMacro; override; function CreateUniqueName(const AName: string): string; override; end; function ShowCodeTemplateDialog: TModalResult; function AddCodeTemplate(ASynAutoComplete: TSynEditAutoComplete; var Token, Comment: string): TModalResult; function EditCodeTemplate(ASynAutoComplete: TSynEditAutoComplete; Index: integer): TModalResult; procedure CreateStandardCodeMacros; // standard code macros function CodeMacroUpper(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroLower(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroPaste(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroProcedureHead(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroProcedureName(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroDate(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroTime(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; function CodeMacroDateTime(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; const CodeTemplatesMenuRootName = 'CodeTemplates'; var CodeTemplateCopyIDEMenuCommand: TIDEMenuCommand; CodeTemplateCutIDEMenuCommand: TIDEMenuCommand; CodeTemplatePasteIDEMenuCommand: TIDEMenuCommand; CodeTemplateInsertMacroIDEMenuCommand: TIDEMenuCommand; procedure RegisterStandardCodeTemplatesMenuItems; implementation function ShowCodeTemplateDialog: TModalResult; var CodeTemplateDialog: TCodeTemplateDialog; begin CodeTemplateDialog:=TCodeTemplateDialog.Create(nil); Result:=CodeTemplateDialog.ShowModal; CodeTemplateDialog.Free; end; function AddCodeTemplate(ASynAutoComplete:TSynEditAutoComplete; var Token,Comment:ansistring):TModalResult; var CodeTemplateEditForm:TCodeTemplateEditForm; begin Result:=mrCancel; CodeTemplateEditForm:=TCodeTemplateEditForm.Create(nil); try CodeTemplateEditForm.SynAutoComplete:=ASynAutoComplete; CodeTemplateEditForm.TemplateIndex:=ASynAutoComplete.Completions.Count; CodeTemplateEditForm.Caption:=lisCodeTemplAddCodeTemplate; CodeTemplateEditForm.OkButton.Caption:=lisCodeTemplAdd; CodeTemplateEditForm.TokenEdit.Text:=Token; CodeTemplateEditForm.CommentEdit.Text:=Comment; Result:=CodeTemplateEditForm.ShowModal; if Result=mrOk then begin Token:=CodeTemplateEditForm.TokenEdit.Text; Comment:=CodeTemplateEditForm.CommentEdit.Text; end; finally CodeTemplateEditForm.Free; end; end; function EditCodeTemplate(ASynAutoComplete:TSynEditAutoComplete; Index:integer):TModalResult; var CodeTemplateEditForm:TCodeTemplateEditForm; begin Result:=mrCancel; if (Index<0) or (Index>=ASynAutoComplete.Completions.Count) then exit; CodeTemplateEditForm:=TCodeTemplateEditForm.Create(nil); try CodeTemplateEditForm.SynAutoComplete:=ASynAutoComplete; CodeTemplateEditForm.TemplateIndex:=Index; CodeTemplateEditForm.Caption:=lisCodeTemplEditCodeTemplate; CodeTemplateEditForm.OkButton.Caption:=lisCodeTemplChange; CodeTemplateEditForm.TokenEdit.Text:=ASynAutoComplete.Completions[Index]; CodeTemplateEditForm.CommentEdit.Text:= ASynAutoComplete.CompletionComments[Index]; Result:=CodeTemplateEditForm.ShowModal; if Result=mrOk then begin ASynAutoComplete.Completions[Index]:= CodeTemplateEditForm.TokenEdit.Text; ASynAutoComplete.CompletionComments[Index]:= CodeTemplateEditForm.CommentEdit.Text; end; finally CodeTemplateEditForm.Free; end; end; function CodeMacroUpper(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin Value:=UpperCase(Parameter); Result:=true; end; function CodeMacroLower(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin Value:=LowerCase(Parameter); Result:=true; end; function CodeMacroPaste(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin Value:=Clipboard.AsText; Result:=true; end; function CodeMacroProcedureHead(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; var Params: TStrings; Param: string; i: Integer; Attributes: TProcHeadAttributes; begin //debugln('CodeMacroProcedureHead A ',Parameter); // parse attributes Params:=SplitString(Parameter,','); if Params<>nil then begin try Attributes:=[]; for i:=0 to Params.Count-1 do begin Param:=Params[i]; if CompareText(Param,'WithStart')=0 then Include(Attributes,phpWithStart) else if CompareText(Param,'WithStart')=0 then Include(Attributes,phpWithStart) else if CompareText(Param,'WithoutClassKeyword')=0 then Include(Attributes,phpWithoutClassKeyword) else if CompareText(Param,'AddClassName')=0 then Include(Attributes,phpAddClassName) else if CompareText(Param,'WithoutClassName')=0 then Include(Attributes,phpWithoutClassName) else if CompareText(Param,'WithoutName')=0 then Include(Attributes,phpWithoutName) else if CompareText(Param,'WithoutParamList')=0 then Include(Attributes,phpWithoutParamList) else if CompareText(Param,'WithVarModifiers')=0 then Include(Attributes,phpWithVarModifiers) else if CompareText(Param,'WithParameterNames')=0 then Include(Attributes,phpWithParameterNames) else if CompareText(Param,'WithoutParamTypes')=0 then Include(Attributes,phpWithoutParamTypes) else if CompareText(Param,'WithDefaultValues')=0 then Include(Attributes,phpWithDefaultValues) else if CompareText(Param,'WithResultType')=0 then Include(Attributes,phpWithResultType) else if CompareText(Param,'WithOfObject')=0 then Include(Attributes,phpWithOfObject) else if CompareText(Param,'WithCallingSpecs')=0 then Include(Attributes,phpWithCallingSpecs) else if CompareText(Param,'WithProcModifiers')=0 then Include(Attributes,phpWithProcModifiers) else if CompareText(Param,'WithComments')=0 then Include(Attributes,phpWithComments) else if CompareText(Param,'InUpperCase')=0 then Include(Attributes,phpInUpperCase) else if CompareText(Param,'CommentsToSpace')=0 then Include(Attributes,phpCommentsToSpace) else if CompareText(Param,'WithoutBrackets')=0 then Include(Attributes,phpWithoutBrackets) else if CompareText(Param,'WithoutSemicolon')=0 then Include(Attributes,phpWithoutSemicolon) else begin Result:=false; ErrorMsg:='Unknown Option: "'+Param+'"'; exit; end; end; finally Params.Free; end; end; //debugln('CodeMacroProcedureHead B '); if not CodeToolBoss.ExtractProcedureHeader( SrcEdit.CodeToolsBuffer as TCodeBuffer, SrcEdit.CursorTextXY.X,SrcEdit.CursorTextXY.Y,Attributes,Value) then begin Result:=false; ErrorMsg:=CodeToolBoss.ErrorMessage; LazarusIDE.DoJumpToCodeToolBossError; exit; end; //debugln('CodeMacroProcedureHead C Value="',Value,'"'); Result:=true; end; function CodeMacroProcedureName(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin Result:=CodeMacroProcedureHead( 'WithoutParamList,WithoutBrackets,WithoutSemicolon', InteractiveValue,SrcEdit,Value,ErrorMsg); debugln('CodeMacroProcedureName ',Value); end; function CodeMacroDate(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin if Parameter<>'' then Value:=FormatDateTime(Parameter,Now) else Value:=DateToStr(Now); Result:=true; end; function CodeMacroTime(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin if Parameter<>'' then Value:=FormatDateTime(Parameter,Now) else Value:=TimeToStr(Now); Result:=true; end; function CodeMacroDateTime(const Parameter: string; InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean; begin if Parameter<>'' then Value:=FormatDateTime(Parameter,Now) else Value:=DateTimeToStr(Now); Result:=true; end; procedure RegisterStandardCodeTemplatesMenuItems; var Path: string; begin CodeTemplatesMenuRoot := RegisterIDEMenuRoot(CodeTemplatesMenuRootName); Path := CodeTemplatesMenuRoot.Name; CodeTemplateCutIDEMenuCommand := RegisterIDEMenuCommand(Path,'Cut','Cut'); CodeTemplateCopyIDEMenuCommand := RegisterIDEMenuCommand(Path,'Copy','Copy'); CodeTemplatePasteIDEMenuCommand := RegisterIDEMenuCommand(Path,'Paste','Paste'); CodeTemplateInsertMacroIDEMenuCommand := RegisterIDEMenuCommand(Path, 'InsertMacro','Insert Macro'); end; procedure CreateStandardCodeMacros; begin IDECodeMacros:=TLazCodeMacros.Create; RegisterCodeMacro('Upper','uppercase string', 'Uppercase string given as parameter', @CodeMacroUpper,nil); RegisterCodeMacro('Lower','lowercase string', 'Lowercase string given as parameter', @CodeMacroLower,nil); RegisterCodeMacro('Paste','paste clipboard', 'Paste text from clipboard', @CodeMacroPaste,nil); RegisterCodeMacro('ProcedureHead','insert procedure head', 'Insert header of current procedure'#13 +#13 +'Optional Parameters (comma separated):'#13 +'WithStart, // proc keyword e.g. ''function'', ''class procedure'''#13 +'WithoutClassKeyword,// without ''class'' proc keyword'#13 +'AddClassName, // extract/add ClassName.'#13 +'WithoutClassName, // skip classname'#13 +'WithoutName, // skip function name'#13 +'WithoutParamList, // skip param list'#13 +'WithVarModifiers, // extract ''var'', ''out'', ''const'''#13 +'WithParameterNames, // extract parameter names'#13 +'WithoutParamTypes, // skip colon, param types and default values'#13 +'WithDefaultValues, // extract default values'#13 +'WithResultType, // extract colon + result type'#13 +'WithOfObject, // extract ''of object'''#13 +'WithCallingSpecs, // extract cdecl; inline;'#13 +'WithProcModifiers, // extract forward; alias; external;'#13 +'WithComments, // extract comments and spaces'#13 +'InUpperCase, // turn to uppercase'#13 +'CommentsToSpace, // replace comments with a single space'#13 +' // (default is to skip unnecessary space,'#13 +' // e.g ''Do ;'' normally becomes ''Do;'''#13 +' // with this option you get ''Do ;'')'#13 +'WithoutBrackets, // skip start- and end-bracket of parameter list'#13 +'WithoutSemicolon, // skip semicolon at end'#13, @CodeMacroProcedureHead,nil); RegisterCodeMacro('ProcedureName','insert procedure name', 'Insert name of current procedure', @CodeMacroProcedureName,nil); RegisterCodeMacro('Date','insert date', 'Insert date. Optional: format string', @CodeMacroDate,nil); RegisterCodeMacro('Time','insert time', 'Insert time. Optional: format string', @CodeMacroTime,nil); RegisterCodeMacro('DateTime','insert date and time', 'Insert date and time. Optional: format string', @CodeMacroDateTime,nil); end; { TCodeTemplateEditForm } constructor TCodeTemplateEditForm.Create(TheOwner:TComponent); begin inherited Create(TheOwner); if LazarusResources.Find(ClassName)=nil then begin Width:=300; Height:=150; Position:=poScreenCenter; OnResize:=@CodeTemplateEditFormResize; TokenLabel:=TLabel.Create(Self); with TokenLabel do begin Name:='TokenLabel'; Parent:=Self; Caption:=lisCodeTemplToken; Left:=12; Top:=6; Width:=Self.ClientWidth-Left-Left; Show; end; TokenEdit:=TEdit.Create(Self); with TokenEdit do begin Name:='TokenEdit'; Parent:=Self; Left:=10; Top:=TokenLabel.Top+TokenLabel.Height+2; Width:=Self.ClientWidth-Left-Left-4; Text:=''; Show; end; CommentLabel:=TLabel.Create(Self); with CommentLabel do begin Name:='CommentLabel'; Parent:=Self; Caption:=lisCodeTemplComment; Left:=12; Top:=TokenEdit.Top+TokenEdit.Height+10; Width:=Self.ClientWidth-Left-Left; Show; end; CommentEdit:=TEdit.Create(Self); with CommentEdit do begin Name:='CommentEdit'; Parent:=Self; Left:=10; Top:=CommentLabel.Top+CommentLabel.Height+2; Width:=Self.ClientWidth-Left-Left-4; Text:=''; Show; end; OkButton:=TButton.Create(Self); with OkButton do begin Name:='OkButton'; Parent:=Self; Caption:=lisLazBuildOk; OnClick:=@OkButtonClick; Left:=50; Top:=Self.ClientHeight-Height-12; Width:=80; Show; end; CancelButton:=TButton.Create(Self); with CancelButton do begin Name:='CancelButton'; Parent:=Self; Caption:=dlgCancel; ModalResult:=mrCancel; Width:=80; Left:=Self.ClientWidth-50-Width; Top:=Self.ClientHeight-Height-12; Show; end; end; CodeTemplateEditFormResize(nil); end; procedure TCodeTemplateEditForm.CodeTemplateEditFormResize(Sender: TObject); begin with TokenLabel do begin Left:=12; Top:=6; Width:=Self.ClientWidth-Left-Left; end; with TokenEdit do begin Left:=10; Top:=TokenLabel.Top+TokenLabel.Height+2; Width:=Self.ClientWidth-Left-Left-4; end; with CommentLabel do begin Left:=12; Top:=TokenEdit.Top+TokenEdit.Height+10; Width:=Self.ClientWidth-Left-Left; end; with CommentEdit do begin Left:=10; Top:=CommentLabel.Top+CommentLabel.Height+2; Width:=Self.ClientWidth-Left-Left-4; end; with OkButton do begin Left:=50; Top:=Self.ClientHeight-Height-12; Width:=80; end; with CancelButton do begin Width:=80; Left:=Self.ClientWidth-50-Width; Top:=Self.ClientHeight-Height-12; end; end; procedure TCodeTemplateEditForm.OkButtonClick(Sender:TObject); var a:integer; AText,ACaption:AnsiString; begin a:=SynAutoComplete.Completions.IndexOf(TokenEdit.Text); if (a<0) or (a=TemplateIndex) then ModalResult:=mrOk else begin AText:=Format(lisCodeTemplATokenAlreadyExists, ['"', TokenEdit.Text, '"']); ACaption:=lisCodeTemplError; // Application.MessageBox(PChar(AText),PChar(ACaption),0); MessageDlg(ACaption,AText,mterror,[mbok],0); end; end; { TCodeTemplateDialog } procedure TCodeTemplateDialog.FormCreate(Sender: TObject); var s: String; ColorScheme: String; begin IDEDialogLayoutList.ApplyLayout(Self,600,450); SynAutoComplete:=TSynEditAutoComplete.Create(Self); LastTemplate:=-1; // init captions Caption:=lisMenuEditCodeTemplates; AddButton.Caption:=lisCodeTemplAdd; EditButton.Caption:=lisCodeToolsDefsEdit; DeleteButton.Caption:=dlgEdDelete; CancelButton.Caption:=dlgCancel; TemplateGroupBox.Caption:=lisCTDTemplates; OkButton.Caption:=lisLazBuildOk; FilenameGroupBox.Caption:=lisToDoLFile; UseMacrosCheckBox.Caption:=lisEnableMacros; InsertMacroButton.Caption:=lisCTInsertMacro; FilenameEdit.Text:=EditorOpts.CodeTemplateFileName; // init synedit ColorScheme:=EditorOpts.ReadColorScheme(ASynPasSyn.GetLanguageName); EditorOpts.AddSpecialHilightAttribsToHighlighter(ASynPasSyn); EditorOpts.ReadHighlighterSettings(ASynPasSyn,ColorScheme); if EditorOpts.UseSyntaxHighlight then TemplateSynEdit.Highlighter:=ASynPasSyn else TemplateSynEdit.Highlighter:=nil; EditorOpts.GetSynEditSettings(TemplateSynEdit); EditorOpts.KeyMap.AssignTo(TemplateSynEdit.KeyStrokes, TSourceEditorWindowInterface); TemplateSynEdit.Gutter.Visible:=false; // init SynAutoComplete with SynAutoComplete do begin s:=EditorOpts.CodeTemplateFileName; if FileExists(s) then try AutoCompleteList.LoadFromFile(s); except DebugLn('NOTE: unable to read code template file ''',s,''''); end; end; // init listbox FillCodeTemplateListBox; with TemplateListBox do if Items.Count>0 then begin ItemIndex:=0; ShowCurCodeTemplate; end; BuildPopupMenu; end; procedure TCodeTemplateDialog.InsertMacroButtonClick(Sender: TObject); begin DoInsertMacro; end; procedure TCodeTemplateDialog.OkButtonClick(Sender: TObject); var Res: TModalResult; begin SaveCurCodeTemplate; EditorOpts.CodeTemplateFileName:=FilenameEdit.Text; //EditorOpts.CodeTemplateIndentToTokenStart:= // (CodeTemplateIndentTypeRadioGroup.ItemIndex=0); EditorOpts.Save; if BuildBorlandDCIFile(SynAutoComplete) then begin Res:=mrOk; repeat try SynAutoComplete.AutoCompleteList.SaveToFile( EditorOpts.CodeTemplateFileName); except res:=MessageDlg(' Unable to write code templates to file ''' +EditorOpts.CodeTemplateFileName+'''! ',mtError ,[mbAbort, mbIgnore, mbRetry],0); if res=mrAbort then exit; end; until Res<>mrRetry; end; ModalResult:=mrOk; end; procedure TCodeTemplateDialog.OnCopyMenuItem(Sender: TObject); begin TemplateSynEdit.CopyToClipboard; end; procedure TCodeTemplateDialog.OnCutMenuItem(Sender: TObject); begin TemplateSynEdit.CutToClipboard; end; procedure TCodeTemplateDialog.OnInsertMacroMenuItem(Sender: TObject); begin DoInsertMacro; end; procedure TCodeTemplateDialog.OnPasteMenuItem(Sender: TObject); begin TemplateSynEdit.PasteFromClipboard; end; procedure TCodeTemplateDialog.AddButtonClick(Sender: TObject); var Token: String; Comment: String; Index: PtrInt; begin SaveCurCodeTemplate; Token:='new'; Comment:='(custom)'; if AddCodeTemplate(SynAutoComplete,Token,Comment)=mrOk then begin SynAutoComplete.AddCompletion(Token, '', Comment); FillCodeTemplateListBox; Index := SynAutoComplete.Completions.IndexOf(Token); if Index >= 0 then Index := TemplateListBox.Items.IndexOfObject(TObject(Pointer(Index))); if Index >= 0 then TemplateListBox.ItemIndex:=Index; ShowCurCodeTemplate; end; end; procedure TCodeTemplateDialog.DeleteButtonClick(Sender: TObject); var a, idx: LongInt; begin idx := TemplateListBox.ItemIndex; if idx < 0 then exit; a := PtrInt(TemplateListBox.Items.Objects[idx]); if a < 0 then exit; if MessageDlg(dlgDelTemplate +'"'+SynAutoComplete.Completions[a]+' - ' +SynAutoComplete.CompletionComments[a]+'"' +'?',mtConfirmation,[mbOk,mbCancel],0)=mrOK then begin SynAutoComplete.DeleteCompletion(a); FillCodeTemplateListBox; if idx < TemplateListBox.Items.Count then begin TemplateListBox.ItemIndex := idx; end; ShowCurCodeTemplate; end; end; procedure TCodeTemplateDialog.EditButtonClick(Sender: TObject); var a, idx: LongInt; begin idx := TemplateListBox.ItemIndex; if idx < 0 then exit; a := PtrInt(TemplateListBox.Items.Objects[idx]); if a < 0 then exit; if EditCodeTemplate(SynAutoComplete, a)=mrOk then begin TemplateListBox.Items[idx]:= SynAutoComplete.Completions[a] +' - "'+SynAutoComplete.CompletionComments[a]+'"'; ShowCurCodeTemplate; end; end; procedure TCodeTemplateDialog.FilenameButtonClick(Sender: TObject); var OpenDialog:TOpenDialog; begin OpenDialog:=TOpenDialog.Create(nil); try InputHistories.ApplyFileDialogSettings(OpenDialog); with OpenDialog do begin Title:=dlgChsCodeTempl; Filter:='DCI file (*.dci)|*.dci|' + dlgAllFiles + '|' + GetAllFilesMask; if Execute then FilenameEdit.Text:=FileName; end; InputHistories.StoreFileDialogSettings(OpenDialog); finally OpenDialog.Free; end; end; procedure TCodeTemplateDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin IDEDialogLayoutList.SaveLayout(Self); end; procedure TCodeTemplateDialog.TemplateListBoxSelectionChange(Sender: TObject; User: boolean); begin SaveCurCodeTemplate; ShowCurCodeTemplate; end; procedure TCodeTemplateDialog.BuildPopupMenu; begin CodeTemplateCopyIDEMenuCommand.OnClick:=@OnCopyMenuItem; CodeTemplateCutIDEMenuCommand.OnClick:=@OnCutMenuItem; CodeTemplatePasteIDEMenuCommand.OnClick:=@OnPasteMenuItem; CodeTemplateInsertMacroIDEMenuCommand.OnClick:=@OnInsertMacroMenuItem; // assign the root TMenuItem to the registered menu root. MainPopupMenu:=TPopupMenu.Create(Self); // This will automatically create all registered items CodeTemplatesMenuRoot.MenuItem := MainPopupMenu.Items; //MainPopupMenu.Items.WriteDebugReport('TMessagesView.Create '); PopupMenu:=MainPopupMenu; end; procedure TCodeTemplateDialog.DoInsertMacro; var Macro: TIDECodeMacro; Parameter: string; begin Macro:=ShowCodeMacroSelectDialog(Parameter); if Macro<>nil then begin TemplateSynEdit.SelText:='$'+Macro.Name+'('+Parameter+')'; end; end; procedure TCodeTemplateDialog.FillCodeTemplateListBox; var a: PtrInt; sl: TStringList; begin sl:=TStringList.Create; try for a:=0 to SynAutoComplete.Completions.Count-1 do begin // Add the index in SynAutoComplete as Object, since both indexes won't // be in sync after sorting sl.AddObject(SynAutoComplete.Completions[a] +' - "'+SynAutoComplete.CompletionComments[a]+'"', TObject(Pointer(a))); end; sl.Sort; TemplateListBox.Items.Assign(sl); finally sl.Free; end; end; procedure TCodeTemplateDialog.ShowCurCodeTemplate; var EnableMacros: boolean; LineCount: integer; procedure AddLine(const s: string); begin if (LineCount=0) and (s=CodeTemplateMacroMagic) then EnableMacros:=true else TemplateSynEdit.Lines.Add(s); inc(LineCount); end; var idx, a, sp, ep: integer; s: string; begin EnableMacros:=false; LineCount := 0; idx := TemplateListBox.ItemIndex; // search template if idx >= 0 then a := PtrInt(TemplateListBox.Items.Objects[idx]) else a := -1; TemplateSynEdit.Lines.BeginUpdate; TemplateSynEdit.Lines.Clear; //debugln('TCodeTemplateDialog.ShowCurCodeTemplate A i=',dbgs(i)); if a >= 0 then begin LastTemplate := -1; s:=SynAutoComplete.CompletionValues[a]; //debugln('TCodeTemplateDialog.ShowCurCodeTemplate s="',s,'"'); sp:=1; ep:=1; while ep<=length(s) do begin if s[ep] in [#10,#13] then begin AddLine(copy(s,sp,ep-sp)); inc(ep); if (ep<=length(s)) and (s[ep] in [#10,#13]) and (s[ep-1]<>s[ep]) then inc(ep); sp:=ep; end else inc(ep); end; if (ep>sp) or ((s<>'') and (s[length(s)] in [#10,#13])) then AddLine(copy(s,sp,ep-sp)); end; LastTemplate := a; TemplateSynEdit.Lines.EndUpdate; TemplateSynEdit.Invalidate; UseMacrosCheckBox.Checked:=EnableMacros; end; procedure TCodeTemplateDialog.SaveCurCodeTemplate; var NewValue: string; l: integer; a: LongInt; begin if LastTemplate<0 then exit; a := LastTemplate; //DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate A i=',dbgs(i)); NewValue:=TemplateSynEdit.Lines.Text; // remove last EOL if NewValue<>'' then begin l:=length(NewValue); if NewValue[l] in [#10,#13] then begin dec(l); if (l>0) and (NewValue[l] in [#10,#13]) and (NewValue[l]<>NewValue[l+1]) then dec(l); SetLength(NewValue,l); end; end; if UseMacrosCheckBox.Checked then NewValue:=CodeTemplateMacroMagic+LineEnding+NewValue; SynAutoComplete.CompletionValues[a]:=NewValue; //DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate NewValue="',NewValue,'" SynAutoComplete.CompletionValues[a]="',SynAutoComplete.CompletionValues[a],'"'); end; { TLazCodeMacros } function TLazCodeMacros.GetItems(Index: integer): TIDECodeMacro; begin Result:=TIDECodeMacro(FItems[Index]); end; constructor TLazCodeMacros.Create; begin FItems:=TFPList.Create; end; destructor TLazCodeMacros.Destroy; begin Clear; FreeAndNil(FItems); inherited Destroy; end; procedure TLazCodeMacros.Clear; var i: Integer; begin for i:=0 to FItems.Count-1 do TObject(FItems[i]).Free; FItems.Clear; end; function TLazCodeMacros.Count: integer; begin Result:=FItems.Count; end; function TLazCodeMacros.Add(Macro: TIDECodeMacro): integer; begin if FindByName(Macro.Name)<>nil then RaiseGDBException('TLazCodeMacros.Add Name already exists'); Result:=FItems.Add(Macro); end; function TLazCodeMacros.FindByName(const AName: string): TIDECodeMacro; var i: LongInt; begin i:=Count-1; while (i>=0) do begin Result:=Items[i]; if (CompareText(Result.Name,AName)=0) then exit; dec(i); end; Result:=nil; end; function TLazCodeMacros.CreateUniqueName(const AName: string): string; begin Result:=AName; if FindByName(Result)=nil then exit; Result:=CreateFirstIdentifier(Result); while FindByName(Result)<>nil do Result:=CreateNextIdentifier(Result); end; initialization {$I codetemplatesdlg.lrs} end.