1 {
2 ***************************************************************************
3 * *
4 * This source is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This code is distributed in the hope that it will be useful, but *
10 * WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * General Public License for more details. *
13 * *
14 * A copy of the GNU General Public License is available on the World *
15 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
16 * obtain it by writing to the Free Software Foundation, *
17 * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
18 * *
19 ***************************************************************************
20
21 Author: Mattias Gaertner
22
23 Abstract:
24 A dialog for adding and editing code templates
25
26 }
27 unit CodeTemplatesDlg;
28
29 {$mode objfpc}{$H+}
30
31 interface
32
33 uses
34 Classes, SysUtils, RegExpr,
35 // LCL
36 LCLProc, Forms, Controls, Dialogs, ClipBrd, StdCtrls, ExtCtrls, Menus,
37 ButtonPanel, EditBtn,
38 // LazUtils
39 FileUtil, LazFileUtils, LazLoggerBase, LazStringUtils, LazUTF8,
40 // synedit
41 SynEdit, SynHighlighterPas, SynEditAutoComplete,
42 // codetools
43 CodeToolManager, CodeCache, KeywordFuncLists, BasicCodeTools, PascalParserTool,
44 // IDEIntf
45 SrcEditorIntf, MenuIntf, IDEWindowIntf, LazIDEIntf, IDEHelpIntf, IDEDialogs,
46 // IDE
47 LazarusIDEStrConsts, EditorOptions, CodeMacroSelect, CodeMacroPrompt;
48
49 type
50 TAutoCompleteOption = (
51 acoLineBreak,
52 acoSpace,
53 acoTab,
54 acoWordEnd,
55 acoIgnoreForSelection,
56 acoRemoveChar
57 );
58
59 const
60 AutoCompleteOptionNames: array[TAutoCompleteOption] of shortstring = (
61 'AutoOnLineBreak',
62 'AutoOnSpace',
63 'AutoOnTab',
64 'AutoOnWordEnd',
65 'IgnoreForSelection',
66 'RemoveChar' // do not add the typed character
67 );
68
69 type
70
71 { TCodeTemplateDialog }
72
73 TCodeTemplateDialog = class(TForm)
74 AddButton: TButton;
75 ASynPasSyn: TSynFreePascalSyn;
76 AutoOnOptionsCheckGroup: TCheckGroup;
77 ButtonPanel: TButtonPanel;
78 EditTemplateGroupBox: TGroupBox;
79 FilenameEdit: TFileNameEdit;
80 InsertMacroButton: TButton;
81 KeepSubIndentCheckBox: TCheckBox;
82 OptionsPanel: TPanel;
83 UseMacrosCheckBox: TCheckBox;
84 RenameButton: TButton;
85 DeleteButton: TButton;
86 TemplateListBox: TListBox;
87 TemplateSynEdit: TSynEdit;
88 TemplatesGroupBox: TGroupBox;
89 FilenameGroupBox: TGroupBox;
90 MainPopupMenu: TPopupMenu;
91 procedure AddButtonClick(Sender: TObject);
92 procedure DeleteButtonClick(Sender: TObject);
93 procedure FormShow(Sender: TObject);
94 procedure RenameButtonClick(Sender: TObject);
95 procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
96 procedure FormCreate(Sender: TObject);
97 procedure HelpButtonClick(Sender: TObject);
98 procedure InsertMacroButtonClick(Sender: TObject);
99 procedure OkButtonClick(Sender: TObject);
100 procedure OnCopyMenuItem(Sender: TObject);
101 procedure OnCutMenuItem(Sender: TObject);
102 procedure OnInsertMacroMenuItem(Sender: TObject);
103 procedure OnPasteMenuItem(Sender: TObject);
104 procedure TemplateListBoxSelectionChange(Sender: TObject; {%H-}User: boolean);
105 procedure UseMacrosCheckBoxChange(Sender: TObject);
106 private
107 SynAutoComplete: TSynEditAutoComplete;
108 LastTemplate: integer;
109 procedure BuildPopupMenu;
110 procedure DoInsertMacro;
111 public
112 procedure FillCodeTemplateListBox;
113 procedure ShowCurCodeTemplate;
114 procedure SaveCurCodeTemplate;
115 end;
116
117 { TLazCodeMacros }
118
119 TLazCodeMacros = class(TIDECodeMacros)
120 private
121 FItems: TFPList; // list of TIDECodeMacro
122 protected
GetItemsnull123 function GetItems(Index: integer): TIDECodeMacro; override;
124 public
125 constructor Create;
126 destructor Destroy; override;
127 procedure Clear;
128 property Items[Index: integer]: TIDECodeMacro read GetItems; default;
Countnull129 function Count: integer; override;
Addnull130 function Add(Macro: TIDECodeMacro): integer; override;
FindByNamenull131 function FindByName(const AName: string): TIDECodeMacro; override;
CreateUniqueNamenull132 function CreateUniqueName(const AName: string): string; override;
133 end;
134
ShowCodeTemplateDialognull135 function ShowCodeTemplateDialog: TModalResult;
136
AddCodeTemplatenull137 function AddCodeTemplate(ASynAutoComplete: TSynEditAutoComplete;
138 var AToken, AComment: string): TModalResult;
EditCodeTemplatenull139 function EditCodeTemplate(ASynAutoComplete: TSynEditAutoComplete;
140 AIndex: integer): TModalResult;
141
142 procedure CreateStandardCodeMacros;
143
144 // standard code macros
CodeMacroUppernull145 function CodeMacroUpper(const Parameter: string; {%H-}InteractiveValue: TPersistent;
146 {%H-}SrcEdit: TSourceEditorInterface;
147 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroLowernull148 function CodeMacroLower(const Parameter: string; {%H-}InteractiveValue: TPersistent;
149 {%H-}SrcEdit: TSourceEditorInterface;
150 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroPastenull151 function CodeMacroPaste(const {%H-}Parameter: string; {%H-}InteractiveValue: TPersistent;
152 {%H-}SrcEdit: TSourceEditorInterface;
153 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroProcedureHeadnull154 function CodeMacroProcedureHead(const Parameter: string;
155 {%H-}InteractiveValue: TPersistent;
156 SrcEdit: TSourceEditorInterface;
157 var Value, ErrorMsg: string): boolean;
CodeMacroProcedureNamenull158 function CodeMacroProcedureName(const {%H-}Parameter: string;
159 InteractiveValue: TPersistent;
160 SrcEdit: TSourceEditorInterface;
161 var Value, ErrorMsg: string): boolean;
CodeMacroDatenull162 function CodeMacroDate(const Parameter: string; {%H-}InteractiveValue: TPersistent;
163 {%H-}SrcEdit: TSourceEditorInterface;
164 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroTimenull165 function CodeMacroTime(const Parameter: string; {%H-}InteractiveValue: TPersistent;
166 {%H-}SrcEdit: TSourceEditorInterface;
167 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroDateTimenull168 function CodeMacroDateTime(const Parameter: string; {%H-}InteractiveValue: TPersistent;
169 {%H-}SrcEdit: TSourceEditorInterface;
170 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroAddMissingEndnull171 function CodeMacroAddMissingEnd(const {%H-}Parameter: string;
172 {%H-}InteractiveValue: TPersistent;
173 SrcEdit: TSourceEditorInterface;
174 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroAddSemicolonnull175 function CodeMacroAddSemicolon(const {%H-}Parameter: string;
176 {%H-}InteractiveValue: TPersistent;
177 SrcEdit: TSourceEditorInterface;
178 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroOfAllnull179 function CodeMacroOfAll(const {%H-}Parameter: string; {%H-}InteractiveValue: TPersistent;
180 SrcEdit: TSourceEditorInterface;
181 var Value, ErrorMsg: string): boolean;
CodeMacroPrevWordnull182 function CodeMacroPrevWord(const Parameter: string;
183 {%H-}InteractiveValue: TPersistent;
184 SrcEdit: TSourceEditorInterface;
185 var Value, {%H-}ErrorMsg: string): boolean;
CodeMacroWordAtCursornull186 function CodeMacroWordAtCursor(const {%H-}Parameter: string; {%H-}InteractiveValue: TPersistent;
187 SrcEdit: TSourceEditorInterface;
188 var Value, {%H-}ErrorMsg: string): boolean;
189
190 const
191 CodeTemplatesMenuRootName = 'CodeTemplates';
192
193 var
194 CodeTemplateCopyIDEMenuCommand: TIDEMenuCommand;
195 CodeTemplateCutIDEMenuCommand: TIDEMenuCommand;
196 CodeTemplatePasteIDEMenuCommand: TIDEMenuCommand;
197 CodeTemplateInsertMacroIDEMenuCommand: TIDEMenuCommand;
198
199 procedure RegisterStandardCodeTemplatesMenuItems;
200
201 implementation
202
203 {$R *.lfm}
204
ShowCodeTemplateDialognull205 function ShowCodeTemplateDialog: TModalResult;
206 var
207 CodeTemplateDialog: TCodeTemplateDialog;
208 begin
209 CodeTemplateDialog:=TCodeTemplateDialog.Create(nil);
210 Result:=CodeTemplateDialog.ShowModal;
211 CodeTemplateDialog.Free;
212 end;
213
IsCodeTemplateOknull214 function IsCodeTemplateOk(ASynAutoComplete: TSynEditAutoComplete;
215 const AToken: string; AIndex: integer): boolean;
216 var
217 n: integer;
218 begin
219 n:=ASynAutoComplete.Completions.IndexOf(AToken);
220 if (n<0) or (n=AIndex) then
221 Result:= true
222 else
223 begin
224 Result:= false;
225 IDEMessageDialog(
226 lisCodeTemplError,
227 Format(lisCodeTemplATokenAlreadyExists, [AToken]),
228 mtError, [mbOK]);
229 end;
230 end;
231
AddCodeTemplatenull232 function AddCodeTemplate(ASynAutoComplete: TSynEditAutoComplete;
233 var AToken, AComment: string): TModalResult;
234 var
235 Str: array of string;
236 begin
237 Result:= mrCancel;
238
239 SetLength(Str, 2);
240 Str[0]:= AToken;
241 Str[1]:= AComment;
242
243 if InputQuery(lisCodeTemplAddCodeTemplate,
244 [lisCodeTemplToken, lisCodeTemplComment], Str) then
245 if IsCodeTemplateOk(ASynAutoComplete, Str[0], ASynAutoComplete.Completions.Count) then
246 begin
247 Result:= mrOk;
248 AToken:= Str[0];
249 AComment:= Str[1];
250 end;
251 end;
252
EditCodeTemplatenull253 function EditCodeTemplate(ASynAutoComplete: TSynEditAutoComplete;
254 AIndex: integer): TModalResult;
255 var
256 Str: array of string;
257 begin
258 Result:= mrCancel;
259 if (AIndex<0) or (AIndex>=ASynAutoComplete.Completions.Count) then exit;
260
261 SetLength(Str, 2);
262 Str[0]:= ASynAutoComplete.Completions[AIndex];
263 Str[1]:= ASynAutoComplete.CompletionComments[AIndex];
264
265 if not InputQuery(lisCodeTemplEditCodeTemplate,
266 [lisCodeTemplToken, lisCodeTemplComment], Str) then exit;
267
268 if not IsCodeTemplateOk(ASynAutoComplete, Str[0], AIndex) then exit;
269
270 ASynAutoComplete.Completions[AIndex]:= Str[0];
271 ASynAutoComplete.CompletionComments[AIndex]:= Str[1];
272 Result:= mrOk;
273 end;
274
CodeMacroUppernull275 function CodeMacroUpper(const Parameter: string; InteractiveValue: TPersistent;
276 SrcEdit: TSourceEditorInterface;
277 var Value, ErrorMsg: string): boolean;
278 begin
279 Value:=UpperCase(Parameter);
280 Result:=true;
281 end;
282
CodeMacroLowernull283 function CodeMacroLower(const Parameter: string; InteractiveValue: TPersistent;
284 SrcEdit: TSourceEditorInterface;
285 var Value, ErrorMsg: string): boolean;
286 begin
287 Value:=LowerCase(Parameter);
288 Result:=true;
289 end;
290
CodeMacroPastenull291 function CodeMacroPaste(const Parameter: string; InteractiveValue: TPersistent;
292 SrcEdit: TSourceEditorInterface;
293 var Value, ErrorMsg: string): boolean;
294 begin
295 Value:=Clipboard.AsText;
296 Result:=true;
297 end;
298
CodeMacroProcedureHeadnull299 function CodeMacroProcedureHead(const Parameter: string;
300 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
301 ErrorMsg: string): boolean;
302 var
303 Params: TStrings;
304 Param: string;
305 i: Integer;
306 Attributes: TProcHeadAttributes;
307 CodeBuf: TCodeBuffer;
308 XY: TPoint;
309 p: integer;
310 StartPos: Integer;
311 begin
312 //debugln('CodeMacroProcedureHead A ',Parameter);
313
314 // parse attributes
315 Params:=SplitString(Parameter,',');
316 if Params<>nil then begin
317 try
318 Attributes:=[];
319 for i:=0 to Params.Count-1 do begin
320 Param:=Params[i];
321 if SysUtils.CompareText(Param,'WithStart')=0 then
322 Include(Attributes,phpWithStart)
323 else if SysUtils.CompareText(Param,'WithStart')=0 then
324 Include(Attributes,phpWithStart)
325 else if SysUtils.CompareText(Param,'WithoutClassKeyword')=0 then
326 Include(Attributes,phpWithoutClassKeyword)
327 else if SysUtils.CompareText(Param,'AddClassName')=0 then
328 Include(Attributes,phpAddClassName)
329 else if SysUtils.CompareText(Param,'WithoutClassName')=0 then
330 Include(Attributes,phpWithoutClassName)
331 else if SysUtils.CompareText(Param,'WithoutName')=0 then
332 Include(Attributes,phpWithoutName)
333 else if SysUtils.CompareText(Param,'WithoutParamList')=0 then
334 Include(Attributes,phpWithoutParamList)
335 else if SysUtils.CompareText(Param,'WithVarModifiers')=0 then
336 Include(Attributes,phpWithVarModifiers)
337 else if SysUtils.CompareText(Param,'WithParameterNames')=0 then
338 Include(Attributes,phpWithParameterNames)
339 else if SysUtils.CompareText(Param,'WithoutParamTypes')=0 then
340 Include(Attributes,phpWithoutParamTypes)
341 else if SysUtils.CompareText(Param,'WithDefaultValues')=0 then
342 Include(Attributes,phpWithDefaultValues)
343 else if SysUtils.CompareText(Param,'WithResultType')=0 then
344 Include(Attributes,phpWithResultType)
345 else if SysUtils.CompareText(Param,'WithOfObject')=0 then
346 Include(Attributes,phpWithOfObject)
347 else if SysUtils.CompareText(Param,'WithCallingSpecs')=0 then
348 Include(Attributes,phpWithCallingSpecs)
349 else if SysUtils.CompareText(Param,'WithProcModifiers')=0 then
350 Include(Attributes,phpWithProcModifiers)
351 else if SysUtils.CompareText(Param,'WithComments')=0 then
352 Include(Attributes,phpWithComments)
353 else if SysUtils.CompareText(Param,'InUpperCase')=0 then
354 Include(Attributes,phpInUpperCase)
355 else if SysUtils.CompareText(Param,'CommentsToSpace')=0 then
356 Include(Attributes,phpCommentsToSpace)
357 else if SysUtils.CompareText(Param,'WithoutBrackets')=0 then
358 Include(Attributes,phpWithoutBrackets)
359 else if SysUtils.CompareText(Param,'WithoutSemicolon')=0 then
360 Include(Attributes,phpWithoutSemicolon)
361 else begin
362 Result:=false;
363 ErrorMsg:='Unknown Option: "'+Param+'"';
364 exit;
365 end;
366 end;
367
368 finally
369 Params.Free;
370 end;
371 end;
372
373 //debugln('CodeMacroProcedureHead B ',dbgs(Attributes));
374 CodeBuf:=SrcEdit.CodeToolsBuffer as TCodeBuffer;
375 XY:=SrcEdit.CursorTextXY;
376 CodeBuf.LineColToPosition(XY.Y,XY.X,p);
377 if p>0 then begin
378 StartPos:=GetIdentStartPosition(CodeBuf.Source,p);
379 XY.X := XY.X + StartPos-p;
380 end;
381 if not CodeToolBoss.ExtractProcedureHeader(CodeBuf,XY.X,XY.Y,Attributes,Value)
382 then begin
383 Result:=false;
384 ErrorMsg:=CodeToolBoss.ErrorMessage;
385 LazarusIDE.DoJumpToCodeToolBossError;
386 exit;
387 end;
388 //debugln('CodeMacroProcedureHead C Value="',Value,'"');
389
390 Result:=true;
391 end;
392
CodeMacroProcedureNamenull393 function CodeMacroProcedureName(const Parameter: string;
394 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
395 ErrorMsg: string): boolean;
396 begin
397 Result:=CodeMacroProcedureHead(
398 'WithoutParamList,WithoutBrackets,WithoutSemicolon',
399 InteractiveValue,SrcEdit,Value,ErrorMsg);
400 end;
401
CodeMacroDatenull402 function CodeMacroDate(const Parameter: string; InteractiveValue: TPersistent;
403 SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean;
404 begin
405 if Parameter<>'' then
406 Value:=FormatDateTime(Parameter,Now)
407 else
408 Value:=DateToStr(Now);
409 Result:=true;
410 end;
411
CodeMacroTimenull412 function CodeMacroTime(const Parameter: string; InteractiveValue: TPersistent;
413 SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean;
414 begin
415 if Parameter<>'' then
416 Value:=FormatDateTime(Parameter,Now)
417 else
418 Value:=TimeToStr(Now);
419 Result:=true;
420 end;
421
CodeMacroDateTimenull422 function CodeMacroDateTime(const Parameter: string;
423 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
424 ErrorMsg: string): boolean;
425 begin
426 if Parameter<>'' then
427 Value:=FormatDateTime(Parameter,Now)
428 else
429 Value:=DateTimeToStr(Now);
430 Result:=true;
431 end;
432
CodeMacroAddMissingEndnull433 function CodeMacroAddMissingEnd(const Parameter: string;
434 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
435 ErrorMsg: string): boolean;
436 { checks if at current position a block end should be inserted
437 Examples:
438
439 No block end required:
440 begin|
441 end
442
443 repeat|
444 until
445
446 begin|
447 repeat
448
449 Block end required:
450 begin
451 begin|
452 end;
453 }
454 var
455 Line: String;
456 p: TPoint;
457 CodeXYPos: TCodeXYPosition;
458 begin
459 Result:=true;
460 Value:='';
461 Line:=SrcEdit.CurrentLineText;
462 p:=SrcEdit.CursorTextXY;
463 if p.y<1 then exit;
464 CodeXYPos.X:=p.x;
465 CodeXYPos.Y:=p.y;
466 CodeXYPos.Code:=SrcEdit.CodeToolsBuffer as TCodeBuffer;
467 if CodeXYPos.Code=nil then exit;
468
469 // ToDo
470
471 while (p.y<=SrcEdit.LineCount) do begin
472 Line:=SrcEdit.Lines[p.y-1];
473 while (p.x<=length(Line)) do begin
474 if IsSpaceChar[Line[p.x]] then
475 inc(p.x)
476 else begin
477 if CompareIdentifiers(@Line[p.x],'end')=0 then begin
478 // has already an end
479 exit;
480 end else begin
481 // missing end
482 Value:=LineEnding+'end;'+LineEnding;
483 end;
484 end;
485 end;
486 inc(p.y);
487 p.x:=1;
488 end;
489 end;
490
CodeMacroAddSemicolonnull491 function CodeMacroAddSemicolon(const Parameter: string;
492 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
493 ErrorMsg: string): boolean;
494 var
495 XY: TPoint;
496 Code: TCodeBuffer;
497 p, AtomStart: integer;
498 Src: String;
499 begin
500 Result:=true;
501 Value:='';
502 XY:=SrcEdit.CursorTextXY;
503 if XY.y<1 then exit;
504 Code:=SrcEdit.CodeToolsBuffer as TCodeBuffer;
505 Code.LineColToPosition(XY.y,XY.x,p);
506 Src:=Code.Source;
507 ReadRawNextPascalAtom(Src,p,AtomStart,true,true);
508 if StringCase(copy(Src,AtomStart,p-AtomStart),
509 [ 'else', 'do', ';', ')', ']' ], True, False) >= 0 then
510 exit;
511 Value:=';';
512 end;
513
CodeMacroOfAllnull514 function CodeMacroOfAll(const Parameter: string; InteractiveValue: TPersistent;
515 SrcEdit: TSourceEditorInterface; var Value, ErrorMsg: string): boolean;
516 // completes
517 // case SomeEnum of
518 // <list of enums>
519 // end;
520 var
521 List, Params: TStrings;
522 Code: TCodeBuffer;
523 CaretXY: TPoint;
524 p: integer;
525 i: Integer;
526 Indent, Param: String;
527 WithoutExtraIndent: Boolean;
528 begin
529 WithoutExtraIndent := False;
530 Params:=SplitString(Parameter,',');
531 if Params<>nil then
532 begin
533 try
534 for i:=0 to Params.Count-1 do
535 begin
536 Param:=Params[i];
537 if SysUtils.CompareText(Param,'WithoutExtraIndent')=0 then
538 WithoutExtraIndent := True
539 else begin
540 Result:=false;
541 ErrorMsg:='Unknown Option: "'+Param+'"';
542 exit;
543 end;
544 end;
545 finally
546 Params.Free;
547 end;
548 end;
549
550 List:=TStringList.Create;
551 try
552 CaretXY:=SrcEdit.CursorTextXY;
553 Code:=SrcEdit.CodeToolsBuffer as TCodeBuffer;
554 Code.LineColToPosition(CaretXY.Y,CaretXY.X,p);
555 if p<1 then begin
556 ErrorMsg:='outside of code';
557 exit(false);
558 end;
559 while (p>1) and (IsIdentChar[Code.Source[p-1]]) do
560 begin
561 dec(p);
562 dec(CaretXY.X);
563 end;
564 if not CodeToolBoss.GetValuesOfCaseVariable(
565 SrcEdit.CodeToolsBuffer as TCodeBuffer,
566 CaretXY.X,CaretXY.Y,List) then
567 begin
568 Result:=false;
569 ErrorMsg:=CodeToolBoss.ErrorMessage;
570 if ErrorMsg='' then
571 ErrorMsg:='missing case variable';
572 LazarusIDE.DoJumpToCodeToolBossError;
573 exit;
574 end;
575
576 Indent := StringOfChar(' ',CodeToolBoss.IndentSize);
577
578 if not WithoutExtraIndent then
579 begin
580 Indent := Indent
581 +StringOfChar(#9,EditorOptions.EditorOpts.BlockTabIndent)
582 +StringOfChar(' ',EditorOptions.EditorOpts.BlockIndent);
583 end;
584
585 Value:='';
586 for i:=0 to List.Count-1 do
587 Value:=Value+ Indent + List[i]+': ;'+LineEnding;
588 finally
589 List.Free;
590 end;
591
592 Result:=true;
593 end;
594
CodeMacroPrevWordnull595 function CodeMacroPrevWord(const Parameter: string;
596 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
597 ErrorMsg: string): boolean;
598 { gets word previous to the cursor position in current line
599 Examples:
600
601 line
602 i 0 count-1 forb|
603
604 with code template
605 for $PrevWord(1) := $PrevWord(2) to $PrevWord(3) do // template:$PrevWord(0)
606 begin
607 |
608 end;$PrevWord(-1)
609
610 is expanded to
611 for i := 0 to count-1 do // template:forb
612 begin
613 |
614 end;
615
616 if $PrevWord(2) is empty, then template
617 is expanded to
618 for i := | to do // template:forb
619 begin
620
621 end;
622
623 $PrevWord(0) expands to template itself, i.e. 'forb'
624 $PrevWord(-1) expands to empty string and is used in the end
625 if macro to delete words in the beginning of the line
626 }
627 var
628 Line,s: String;
629 p: TPoint;
630 CodeXYPos: TCodeXYPosition;
631 re : TRegExpr;
632 iParam,lastword,firstword,Position : Integer;
633 st: TStringList;
634 begin
635 iParam:=StrToIntDef(Parameter,-1);
636 Result:=true;
637 Value:='';
638 Line:=SrcEdit.CurrentLineText;
639 p:=SrcEdit.CursorTextXY;
640 if p.y<1 then exit;
641 CodeXYPos.X:=p.x;
642 CodeXYPos.Y:=p.y;
643 CodeXYPos.Code:=SrcEdit.CodeToolsBuffer as TCodeBuffer;
644 if CodeXYPos.Code=nil then exit;
645
646 st:=TStringList.Create;
647 re:=TRegExpr.Create;
648 re.Expression:='[\w\-+*\(\)\[\].^@]+';
649 if(re.Exec(Line))then
650 begin
651 firstword:=re.MatchPos[0];
652 repeat
653 st.Add(re.Match[0]);
654 lastword:=re.MatchPos[0];
655 until (not re.ExecNext);
656 end;
657 if st.Count>1 then
658 st.Move(st.count-1, 0);
659 if(iParam<0)then
660 begin
661 p.X:=SrcEdit.CursorTextXY.x;
662 CodeXYPos.Code.LineColToPosition(CodeXYPos.Y,firstword,Position);
663 CodeXYPos.Code.Delete(Position,lastword-firstword);
664 p.X:=p.X-(lastword-firstword);
665 SrcEdit.CursorTextXY:=p;
666 Value:='';
667 end
668 else
669 begin
670 if(iParam<st.count)then
671 Value:=st[iParam]
672 else
673 Value:='|';
674 end;
675 st.Free;
676 re.Free;
677 end;
678
CodeMacroWordAtCursornull679 function CodeMacroWordAtCursor(const Parameter: string;
680 InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
681 ErrorMsg: string): boolean;
682 var
683 SynEditor: TSynEdit;
684 begin
685 SynEditor:=SrcEdit.EditorControl as TSynEdit;
686 Value:=SynEditor.GetWordAtRowCol(SynEditor.LogicalCaretXY);
687 Result:=true;
688 end;
689
CodeMacroEditParamnull690 function CodeMacroEditParam(const Parameter: string;
691 {%H-}InteractiveValue: TPersistent; {%H-}SrcEdit: TSourceEditorInterface; var Value,
692 {%H-}ErrorMsg: string; TemplateParser: TIDETemplateParser): boolean;
693 var
694 p: TLazTemplateParser;
695 temp: TStringList;
696 i, g: Integer;
697 s: String;
698 begin
699 p := TLazTemplateParser(TemplateParser);
700 Value := Parameter;
701 g := -1;
702 temp := TStringList.Create;
703 try
704 s := Parameter;
705 while length(s) > 0 do begin
706 if s[1] = '"' then begin
707 System.Delete(s, 1, 1);
708 i := pos('"', s);
709 end
710 else
711 i := pos(',', s);
712 if i < 1 then
713 i := length(s) + 1;
714 temp.add(copy(s, 1, i - 1));
715 System.Delete(s, 1, i);
716 end;
717 //temp.CommaText := Parameter;
718 if temp.Count > 0 then begin
719 Value := temp[0];
720 temp.Delete(0);
721
722 i := temp.IndexOfName('Sync');
723 if i < 0 then
724 i := temp.IndexOfName('S');
725 if i >= 0 then
726 i := StrToIntDef(temp.ValueFromIndex[i], -1)
727 else
728 if (temp.IndexOf('Sync') >= 0) or (temp.IndexOf('S') >= 0) then begin
729 i := p.EditCellList.Count - 1;
730 while i >= 0 do begin
731 if TLazSynPluginSyncronizedEditCell(p.EditCellList[i]).CellValue = Value then
732 break;
733 dec(i);
734 end;
735 end;
736
737 dec(i);
738 if (i >= 0) and (i < p.EditCellList.Count) then begin
739 Value := TLazSynPluginSyncronizedEditCell(p.EditCellList[i]).CellValue;
740 g := TLazSynPluginSyncronizedEditCell(p.EditCellList[i]).Group;
741 end;
742 end;
743 finally
744 temp.Free;
745 end;
746 with TLazSynPluginSyncronizedEditCell(p.EditCellList.AddNew) do begin
747 LogStart := Point(p.DestPosX, p.DestPosY);
748 LogEnd := Point(p.DestPosX + length(Value), p.DestPosY);
749 if g < 0 then begin
750 Group := p.EditCellList.Count;
751 FirstInGroup := True;
752 end
753 else
754 Group := g;
755 CellValue := Value;
756 end;
757 Result := True;
758 end;
759
760 procedure RegisterStandardCodeTemplatesMenuItems;
761 var
762 Path: string;
763 begin
764 CodeTemplatesMenuRoot := RegisterIDEMenuRoot(CodeTemplatesMenuRootName);
765 Path := CodeTemplatesMenuRoot.Name;
766 CodeTemplateCutIDEMenuCommand := RegisterIDEMenuCommand(Path, 'Cut', lisCut);
767 CodeTemplateCopyIDEMenuCommand := RegisterIDEMenuCommand(Path, 'Copy', lisCopy);
768 CodeTemplatePasteIDEMenuCommand := RegisterIDEMenuCommand(Path, 'Paste', lisPaste);
769 CodeTemplateInsertMacroIDEMenuCommand := RegisterIDEMenuCommand(Path,
770 'InsertMacro', lisInsertMacro);
771 end;
772
773 procedure CreateStandardCodeMacros;
774 begin
775 IDECodeMacros:=TLazCodeMacros.Create;
776 RegisterCodeMacro('Upper', lisUppercaseString,
777 lisUppercaseStringGivenAsParameter,
778 @CodeMacroUpper,nil);
779 RegisterCodeMacro('Lower', lisLowercaseString,
780 lisLowercaseStringGivenAsParameter,
781 @CodeMacroLower,nil);
782 RegisterCodeMacro('Paste', lisPasteClipboard,
783 lisPasteFromClipboard,
784 @CodeMacroPaste,nil);
785 RegisterCodeMacro('ProcedureHead', lisInsertProcedureHead,
786 lisInsertHeaderOfCurrentProcedure,
787 @CodeMacroProcedureHead,nil);
788 RegisterCodeMacro('ProcedureName', lisInsertProcedureName,
789 lisInsertNameOfCurrentProcedure,
790 @CodeMacroProcedureName,nil);
791 RegisterCodeMacro('Date', lisInsertDate,
792 lisInsertDateOptionalFormatString,
793 @CodeMacroDate,nil);
794 RegisterCodeMacro('Time', lisInsertTime,
795 lisInsertTimeOptionalFormatString,
796 @CodeMacroTime,nil);
797 RegisterCodeMacro('DateTime', lisInsertDateAndTime,
798 lisInsertDateAndTimeOptionalFormatString,
799 @CodeMacroDateTime,nil);
800 RegisterCodeMacro('AddMissingEnd', lisInsertEndIfNeeded,
801 lisCheckIfTheNextTokenInSourceIsAnEndAndIfNotReturnsL,
802 @CodeMacroAddMissingEnd,nil);
803 RegisterCodeMacro('AddSemicolon', lisInsertSemicolonIfNeeded,
804 lisCheckTheNextTokenInSourceAndAddASemicolonIfNeeded,
805 @CodeMacroAddSemicolon,nil);
806 RegisterCodeMacro('OfAll', lisListOfAllCaseValues,
807 lisReturnsListOfAllValuesOfCaseVariableInFrontOfVaria,
808 @CodeMacroOfAll,nil);
809 RegisterCodeMacro('WordAtCursor', lisGetWordAtCurrentCursorPosition,
810 lisGetWordAtCurrentCursorPosition2,
811 @CodeMacroWordAtCursor,nil);
812 RegisterCodeMacro('PrevWord', lisPrecedingWord,
813 lisReturnParameterIndexedWord,
814 @CodeMacroPrevWord,nil);
815 RegisterCodeMacroEx('Param', lisTemplateEditParamCell,
816 Format(lisTemplateEditParamCellHelp, [LineEnding]),
817 @CodeMacroEditParam,nil);
818 end;
819
820
821 { TCodeTemplateDialog }
822
823 procedure TCodeTemplateDialog.FormCreate(Sender: TObject);
824 var
825 ColorScheme: String;
826 begin
827 IDEDialogLayoutList.ApplyLayout(Self,600,450);
828
829 SynAutoComplete:=TSynEditAutoComplete.Create(Self);
830 LastTemplate:=-1;
831
832 // init captions
833 Caption:=dlgEdCodeTempl;
834 AddButton.Caption:=lisAdd;
835 RenameButton.Caption:=lisRename;
836 DeleteButton.Caption:=lisDelete;
837 TemplatesGroupBox.Caption:=lisCTDTemplates;
838
839 ButtonPanel.OKButton.Caption:=lisMenuOk;
840 ButtonPanel.HelpButton.Caption:=lisMenuHelp;
841 ButtonPanel.CancelButton.Caption:=lisCancel;
842
843 FilenameGroupBox.Caption:=lisDebugOptionsFrmModule;
844 UseMacrosCheckBox.Caption:=lisEnableMacros;
845 InsertMacroButton.Caption:=lisInsertMacro;
846 KeepSubIndentCheckBox.Caption:=lisKeepSubIndentation;
847 KeepSubIndentCheckBox.Hint:=lisKeepRelativeIndentationOfMultiLineTemplate;
848 AutoOnOptionsCheckGroup.Caption:=lisCodeTemplAutoCompleteOn;
849 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyOnLineBreak);
850 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyOnSpace);
851 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyOnTab);
852 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyOnWordEnd);
853 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyIgnoreForSelection);
854 AutoOnOptionsCheckGroup.Items.Add(lisAutomaticallyRemoveCharacter);
855
856 FilenameEdit.Text:=EditorOpts.CodeTemplateFileNameRaw;
857 FilenameEdit.InitialDir:=ExtractFilePath(EditorOpts.CodeTemplateFileNameExpand);
858 FilenameEdit.DialogTitle:=dlgChsCodeTempl;
859 FilenameEdit.Filter:=dlgFilterDciFile + '|*.dci|' + dlgFilterAll + '|' + GetAllFilesMask;
860
861 // init synedit
862 ColorScheme:=EditorOpts.ReadColorScheme(ASynPasSyn.GetLanguageName);
863 EditorOpts.ReadHighlighterSettings(ASynPasSyn,ColorScheme);
864 if EditorOpts.UseSyntaxHighlight then
865 TemplateSynEdit.Highlighter:=ASynPasSyn
866 else
867 TemplateSynEdit.Highlighter:=nil;
868 EditorOpts.SetMarkupColors(TemplateSynEdit);
869 EditorOpts.GetSynEditSettings(TemplateSynEdit);
870 EditorOpts.AssignKeyMapTo(TemplateSynEdit);
871 TemplateSynEdit.Gutter.Visible:=false;
872
873 // init SynAutoComplete
874 EditorOpts.LoadCodeTemplates(SynAutoComplete);
875
876 // init listbox
877 FillCodeTemplateListBox;
878 with TemplateListBox do
879 if Items.Count>0 then begin
880 ItemIndex:=0;
881 ShowCurCodeTemplate;
882 end;
883
884 BuildPopupMenu;
885 end;
886
887 procedure TCodeTemplateDialog.HelpButtonClick(Sender: TObject);
888 begin
889 LazarusHelp.ShowHelpForIDEControl(Self);
890 end;
891
892 procedure TCodeTemplateDialog.InsertMacroButtonClick(Sender: TObject);
893 begin
894 DoInsertMacro;
895 end;
896
897 procedure TCodeTemplateDialog.OkButtonClick(Sender: TObject);
898 var
899 Res: TModalResult;
900 begin
901 SaveCurCodeTemplate;
902
903 EditorOpts.CodeTemplateFileNameRaw:=FilenameEdit.Text;
904 //EditorOpts.CodeTemplateIndentToTokenStart:=
905 // (CodeTemplateIndentTypeRadioGroup.ItemIndex=0);
906
907 EditorOpts.Save;
908
909 if BuildBorlandDCIFile(SynAutoComplete) then begin
910 Res:=mrOk;
911 repeat
912 res := EditorOpts.SaveCodeTemplates(SynAutoComplete);
913 if res <> mrOK then begin
914 res:=IDEMessageDialog(lisCCOErrorCaption, 'Unable to write code '
915 +'templates to file '''
916 +EditorOpts.CodeTemplateFileNameExpand+'''! ',mtError
917 ,[mbAbort, mbIgnore, mbRetry]);
918 if res=mrAbort then exit;
919 end;
920 until Res<>mrRetry;
921 end;
922
923 ModalResult:=mrOk;
924 end;
925
926 procedure TCodeTemplateDialog.OnCopyMenuItem(Sender: TObject);
927 begin
928 TemplateSynEdit.CopyToClipboard;
929 end;
930
931 procedure TCodeTemplateDialog.OnCutMenuItem(Sender: TObject);
932 begin
933 TemplateSynEdit.CutToClipboard;
934 end;
935
936 procedure TCodeTemplateDialog.OnInsertMacroMenuItem(Sender: TObject);
937 begin
938 DoInsertMacro;
939 end;
940
941 procedure TCodeTemplateDialog.OnPasteMenuItem(Sender: TObject);
942 begin
943 TemplateSynEdit.PasteFromClipboard;
944 end;
945
946 procedure TCodeTemplateDialog.AddButtonClick(Sender: TObject);
947 var
948 Token: String;
949 Comment: String;
950 Index: PtrInt;
951 begin
952 SaveCurCodeTemplate;
953 Token:='new';
954 Comment:='(custom)';
955 if AddCodeTemplate(SynAutoComplete,Token,Comment)=mrOk then begin
956 SynAutoComplete.AddCompletion(Token, '', Comment);
957 FillCodeTemplateListBox;
958 Index := SynAutoComplete.Completions.IndexOf(Token);
959 if Index >= 0
960 then Index := TemplateListBox.Items.IndexOfObject(TObject({%H-}Pointer(Index)));
961 if Index >= 0
962 then TemplateListBox.ItemIndex:=Index;
963
964 ShowCurCodeTemplate;
965 end;
966 end;
967
968 procedure TCodeTemplateDialog.DeleteButtonClick(Sender: TObject);
969 var
970 a, idx: LongInt;
971 begin
972 idx := TemplateListBox.ItemIndex;
973 if idx < 0 then exit;
974 a := PtrInt(TemplateListBox.Items.Objects[idx]);
975 if a < 0 then exit;
976
977 if IDEMessageDialog(lisConfirm, dlgDelTemplate
978 +'"'+SynAutoComplete.Completions[a]+' - '
979 +SynAutoComplete.CompletionComments[a]+'"'
980 +'?',mtConfirmation,[mbOk,mbCancel])=mrOK
981 then begin
982 SynAutoComplete.DeleteCompletion(a);
983 LastTemplate := -1; // to prevent the saving of the deleted template
984 FillCodeTemplateListBox;
985 if idx < TemplateListBox.Items.Count then begin
986 TemplateListBox.ItemIndex := idx;
987 end;
988 ShowCurCodeTemplate;
989 end;
990
991 TemplateListBox.OnSelectionChange(Self, false); //update btn state
992 end;
993
994 procedure TCodeTemplateDialog.FormShow(Sender: TObject);
995 begin
996 TemplateListBox.OnSelectionChange(Self, true); //update btn states
997 end;
998
999 procedure TCodeTemplateDialog.RenameButtonClick(Sender: TObject);
1000 var
1001 a, idx: LongInt;
1002 begin
1003 idx := TemplateListBox.ItemIndex;
1004 if idx < 0 then exit;
1005 a := PtrInt(TemplateListBox.Items.Objects[idx]);
1006 if a < 0 then exit;
1007
1008 if EditCodeTemplate(SynAutoComplete, a)=mrOk then begin
1009 TemplateListBox.Items[idx]:=
1010 SynAutoComplete.Completions[a]
1011 +' - "'+SynAutoComplete.CompletionComments[a]+'"';
1012 ShowCurCodeTemplate;
1013 end;
1014 end;
1015
1016 procedure TCodeTemplateDialog.FormClose(Sender: TObject;
1017 var CloseAction: TCloseAction);
1018 begin
1019 IDEDialogLayoutList.SaveLayout(Self);
1020 end;
1021
1022 procedure TCodeTemplateDialog.TemplateListBoxSelectionChange(Sender: TObject;
1023 User: boolean);
1024 var
1025 en: boolean;
1026 begin
1027 en := TemplateListBox.ItemIndex>=0;
1028 DeleteButton.Enabled := en;
1029 RenameButton.Enabled := en;
1030 EditTemplateGroupBox.Enabled := en;
1031
1032 SaveCurCodeTemplate;
1033 ShowCurCodeTemplate;
1034 end;
1035
1036 procedure TCodeTemplateDialog.UseMacrosCheckBoxChange(Sender: TObject);
1037 begin
1038 InsertMacroButton.Enabled:=UseMacrosCheckBox.Checked;
1039 end;
1040
1041 procedure TCodeTemplateDialog.BuildPopupMenu;
1042 begin
1043 CodeTemplateCopyIDEMenuCommand.OnClick:=@OnCopyMenuItem;
1044 CodeTemplateCutIDEMenuCommand.OnClick:=@OnCutMenuItem;
1045 CodeTemplatePasteIDEMenuCommand.OnClick:=@OnPasteMenuItem;
1046 CodeTemplateInsertMacroIDEMenuCommand.OnClick:=@OnInsertMacroMenuItem;
1047
1048 // assign the root TMenuItem to the registered menu root.
1049 MainPopupMenu:=TPopupMenu.Create(Self);
1050 // This will automatically create all registered items
1051 CodeTemplatesMenuRoot.MenuItem := MainPopupMenu.Items;
1052 //MainPopupMenu.Items.WriteDebugReport('TMessagesView.Create ');
1053
1054 PopupMenu:=MainPopupMenu;
1055 end;
1056
1057 procedure TCodeTemplateDialog.DoInsertMacro;
1058 var
1059 Macro: TIDECodeMacro;
1060 Parameter: string;
1061 begin
1062 Macro:=ShowCodeMacroSelectDialog(Parameter);
1063 if Macro<>nil then begin
1064 TemplateSynEdit.SelText:='$'+Macro.Name+'('+Parameter+')';
1065 end;
1066 end;
1067
1068 procedure TCodeTemplateDialog.FillCodeTemplateListBox;
1069 var
1070 a: PtrInt;
1071 sl: TStringListUTF8Fast;
1072 begin
1073 sl:=TStringListUTF8Fast.Create;
1074 try
1075 for a:=0 to SynAutoComplete.Completions.Count-1 do begin
1076 // Add the index in SynAutoComplete as Object, since both indexes won't
1077 // be in sync after sorting
1078 sl.AddObject(SynAutoComplete.Completions[a]
1079 +' - "'+SynAutoComplete.CompletionComments[a]+'"', TObject({%H-}Pointer(a)));
1080 end;
1081 sl.Sort;
1082 TemplateListBox.Items.Assign(sl);
1083 finally
1084 sl.Free;
1085 end;
1086 end;
1087
1088 procedure TCodeTemplateDialog.ShowCurCodeTemplate;
1089 var
1090 EnableMacros, KeepSubIndent: boolean;
1091 LineCount: integer;
1092
1093 procedure AddLine(const s: string);
1094 begin
1095 TemplateSynEdit.Lines.Add(s);
1096 inc(LineCount);
1097 end;
1098
1099 var
1100 idx, a, sp, ep: integer;
1101 s: string;
1102 AutoOnCat: array[TAutoCompleteOption] of Boolean;
1103 Attributes: TStrings;
1104 c: TAutoCompleteOption;
1105 begin
1106 EnableMacros:=false;
1107 KeepSubIndent:=false;
1108 for c:=Low(TAutoCompleteOption) to High(TAutoCompleteOption) do
1109 AutoOnCat[c]:=false;
1110
1111 LineCount := 0;
1112 idx := TemplateListBox.ItemIndex;
1113 // search template
1114 if idx >= 0
1115 then a := PtrInt(TemplateListBox.Items.Objects[idx])
1116 else a := -1;
1117
1118 TemplateSynEdit.Lines.BeginUpdate;
1119 TemplateSynEdit.Lines.Clear;
1120
1121 // debugln('TCodeTemplateDialog.ShowCurCodeTemplate A a=',dbgs(a));
1122 if a >= 0
1123 then begin
1124 EditTemplateGroupBox.Caption:=dbgstr(SynAutoComplete.Completions[a])
1125 +' - '+dbgstr(SynAutoComplete.CompletionComments[a]);
1126 Attributes:=SynAutoComplete.CompletionAttributes[a];
1127 EnableMacros:=Attributes.IndexOfName(CodeTemplateEnableMacros)>=0;
1128 KeepSubIndent:=Attributes.IndexOfName(CodeTemplateKeepSubIndent)>=0;
1129 for c:=Low(TAutoCompleteOption) to High(TAutoCompleteOption) do
1130 AutoOnCat[c]:=Attributes.IndexOfName(AutoCompleteOptionNames[c])>=0;
1131 LastTemplate := -1;
1132 s:=SynAutoComplete.CompletionValues[a];
1133 //debugln('TCodeTemplateDialog.ShowCurCodeTemplate s="',s,'"');
1134 sp:=1;
1135 ep:=1;
1136 while ep<=length(s) do begin
1137 if s[ep] in [#10,#13] then begin
1138 AddLine(copy(s,sp,ep-sp));
1139 inc(ep);
1140 if (ep<=length(s)) and (s[ep] in [#10,#13]) and (s[ep-1]<>s[ep]) then
1141 inc(ep);
1142 sp:=ep;
1143 end else inc(ep);
1144 end;
1145 if (ep>sp) or ((s<>'') and (s[length(s)] in [#10,#13])) then
1146 AddLine(copy(s,sp,ep-sp));
1147 end else begin
1148 EditTemplateGroupBox.Caption:=lisNoTemplateSelected;
1149 end;
1150 LastTemplate := a;
1151 TemplateSynEdit.Lines.EndUpdate;
1152 TemplateSynEdit.Invalidate;
1153 UseMacrosCheckBox.Checked:=EnableMacros;
1154 InsertMacroButton.Enabled:=EnableMacros;
1155 KeepSubIndentCheckBox.Checked:=KeepSubIndent;
1156 for c:=Low(TAutoCompleteOption) to High(TAutoCompleteOption) do
1157 AutoOnOptionsCheckGroup.Checked[ord(c)]:=AutoOnCat[c];
1158 end;
1159
1160 procedure TCodeTemplateDialog.SaveCurCodeTemplate;
1161 var
1162 a: LongInt;
1163
1164 procedure SetBooleanAttribute(const AttrName: string; NewValue: boolean);
1165 var
1166 Attributes: TStrings;
1167 l: LongInt;
1168 begin
1169 Attributes:=SynAutoComplete.CompletionAttributes[a];
1170 if NewValue then
1171 Attributes.Values[AttrName]:='true'
1172 else begin
1173 l:=Attributes.IndexOfName(AttrName);
1174 if l>=0 then
1175 Attributes.Delete(l);
1176 end;
1177 end;
1178
1179 var
1180 NewValue: string;
1181 l: integer;
1182 c: TAutoCompleteOption;
1183 begin
1184 if LastTemplate<0 then exit;
1185 a := LastTemplate;
1186 //DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate A a=',dbgs(a));
1187 NewValue:=TemplateSynEdit.Lines.Text;
1188 // remove last EOL
1189 if NewValue<>'' then begin
1190 l:=length(NewValue);
1191 if NewValue[l] in [#10,#13] then begin
1192 dec(l);
1193 if (l>0) and (NewValue[l] in [#10,#13])
1194 and (NewValue[l]<>NewValue[l+1]) then
1195 dec(l);
1196 SetLength(NewValue,l);
1197 end;
1198 end;
1199 SynAutoComplete.CompletionValues[a]:=NewValue;
1200
1201 SetBooleanAttribute(CodeTemplateEnableMacros,UseMacrosCheckBox.Checked);
1202 SetBooleanAttribute(CodeTemplateKeepSubIndent,KeepSubIndentCheckBox.Checked);
1203 for c:=low(TAutoCompleteOption) to High(TAutoCompleteOption) do
1204 SetBooleanAttribute(AutoCompleteOptionNames[c],AutoOnOptionsCheckGroup.Checked[ord(c)]);
1205
1206 //DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate NewValue="',NewValue,'" SynAutoComplete.CompletionValues[a]="',SynAutoComplete.CompletionValues[a],'"');
1207 end;
1208
1209 { TLazCodeMacros }
1210
GetItemsnull1211 function TLazCodeMacros.GetItems(Index: integer): TIDECodeMacro;
1212 begin
1213 Result:=TIDECodeMacro(FItems[Index]);
1214 end;
1215
1216 constructor TLazCodeMacros.Create;
1217 begin
1218 FItems:=TFPList.Create;
1219 end;
1220
1221 destructor TLazCodeMacros.Destroy;
1222 begin
1223 Clear;
1224 FreeAndNil(FItems);
1225 inherited Destroy;
1226 end;
1227
1228 procedure TLazCodeMacros.Clear;
1229 var
1230 i: Integer;
1231 begin
1232 for i:=0 to FItems.Count-1 do TObject(FItems[i]).Free;
1233 FItems.Clear;
1234 end;
1235
Countnull1236 function TLazCodeMacros.Count: integer;
1237 begin
1238 Result:=FItems.Count;
1239 end;
1240
Addnull1241 function TLazCodeMacros.Add(Macro: TIDECodeMacro): integer;
1242 begin
1243 if FindByName(Macro.Name)<>nil then
1244 RaiseGDBException('TLazCodeMacros.Add Name already exists');
1245 Result:=FItems.Add(Macro);
1246 end;
1247
FindByNamenull1248 function TLazCodeMacros.FindByName(const AName: string): TIDECodeMacro;
1249 var
1250 i: LongInt;
1251 begin
1252 i:=Count-1;
1253 while (i>=0) do begin
1254 Result:=Items[i];
1255 if (SysUtils.CompareText(Result.Name,AName)=0) then exit;
1256 dec(i);
1257 end;
1258 Result:=nil;
1259 end;
1260
CreateUniqueNamenull1261 function TLazCodeMacros.CreateUniqueName(const AName: string): string;
1262 begin
1263 Result:=AName;
1264 if FindByName(Result)=nil then exit;
1265 Result:=CreateFirstIdentifier(Result);
1266 while FindByName(Result)<>nil do
1267 Result:=CreateNextIdentifier(Result);
1268 end;
1269
1270 end.
1271