34
34
Classes, SysUtils, LCLProc, Forms, Controls, Graphics, Dialogs,
35
36
SynEditAutoComplete, SynPluginTemplateEdit, SynPluginSyncronizedEditBase, SynEdit,
36
37
MacroIntf, LazIDEIntf, SrcEditorIntf;
92
95
procedure TrimEOTChar(eot: Char);
94
97
property EnableMacros: Boolean read FEnableMacros write FEnableMacros;
98
property KeepSubIndent: Boolean read FKeepSubIndent write FKeepSubIndent;
95
99
property Indent: String read FIndent write FIndent;
100
property SubIndent: integer read FSubIndent write FSubIndent;
96
101
property DestCaret: TPoint read FCaret;
98
103
property EditCellList: TSynPluginSyncronizedEditList read FEditCellList;
204
209
function TLazTemplateParser.SubstituteMacros(var Template: String): boolean;
211
TemplateTabWidth = 8;
213
IndentLevel: Integer;
214
LastLineIndent: Integer;
215
IsLineStart: boolean;
206
217
procedure AppentToDest(S: String);
219
i, LastCopy: Integer;
220
CurLineIndent: LongInt;
225
//debugln(['AppentToDest START S="',dbgstr(S),'" Indent="',dbgstr(Indent),'"']);
212
226
while i <= length(S) do begin
217
231
if (i <= length(S)) and (s[i] in [#10,#13]) and (s[i] <> s[i-1]) then
219
if (FDestTemplate <> '') and (i > i2) and
220
(FDestTemplate[length(FDestTemplate)] in [#10, #13])
222
FDestTemplate := FDestTemplate + FIndent;
223
FDestTemplate := FDestTemplate + copy(s, i2, i - i2);
233
FDestTemplate := FDestTemplate + copy(s, LastCopy, i - LastCopy) + FIndent;
225
235
FDestPosX := 1 + length(FIndent);
230
if (s[i] = '|') and (FCaret.y < 0) then begin
241
if (s[i] in [' ',#9])
242
and (not KeepSubIndent)
243
and ((FDestTemplate<>'') and IsLineStart)
245
// space at start of template line (not first line)
246
FDestTemplate:=FDestTemplate+copy(S,LastCopy,i-LastCopy);
249
while (i<=length(S)) and (S[i] in [' ',#9]) do inc(i);
250
// compare the indentation of the current and the last line of the template
251
CurLineIndent:=GetLineIndentWithTabs(S,SpaceStart,TemplateTabWidth);
252
if CurLineIndent>LastLineIndent then
254
else if (IndentLevel>0) and (CurLineIndent<LastLineIndent) then
256
LastLineIndent:=CurLineIndent;
258
CurLineIndent:=IndentLevel*SubIndent;
259
//debugln(['AppentToDest CurLineIndent=',CurLineIndent,' ',IndentLevel,'*',SubIndent]);
260
FDestTemplate:=FDestTemplate+StringOfChar(' ',CurLineIndent);
262
inc(FDestPosX,CurLineIndent);
263
end else if (s[i] = '|') and (FCaret.y < 0) then
231
266
System.Delete(s, i, 1);
232
267
FCaret.y := FDestPosY;
233
268
FCaret.x := FDestPosX;
242
if (FDestTemplate <> '') and (i > i2) and
278
if (FDestTemplate <> '') and (i > LastCopy) and
243
279
(FDestTemplate[length(FDestTemplate)] in [#10, #13])
245
281
FDestTemplate := FDestTemplate + FIndent;
246
FDestTemplate := FDestTemplate + copy(s, i2, i - i2);
282
FDestTemplate := FDestTemplate + copy(s, LastCopy, i - LastCopy);
247
283
FDestPosition := length(FDestTemplate);
284
//debugln(['AppentToDest END FDestTemplate=',dbgstr(FDestTemplate)]);
371
411
System.Delete(FDestTemplate, length(FDestTemplate), 1);
375
414
function ExecuteCodeTemplate(SrcEdit: TSourceEditorInterface;
376
415
const TemplateName, TemplateValue, TemplateComment,
377
416
EndOfTokenChr: string; Attributes: TStrings;
378
417
IndentToTokenStart: boolean): boolean;
380
AEditor: TCustomSynEdit;
382
421
TokenStartX: LongInt;
392
431
//debugln('ExecuteCodeTemplate ',dbgsName(SrcEdit),' ',dbgsName(SrcEdit.EditorControl));
393
AEditor:=SrcEdit.EditorControl as TCustomSynEdit;
432
AEditor:=SrcEdit.EditorControl as TSynEdit;
394
433
Pattern:=TemplateValue;
396
435
Parser := TLazTemplateParser.Create(Pattern);
397
436
AEditor.BeginUpdate;
438
Parser.SubIndent:=AEditor.BlockIndent;
399
439
p := AEditor.LogicalCaretXY;
400
440
TokenStartX:=p.x;
401
441
if IndentToTokenStart then begin
402
IndentLen := TokenStartX - 1;
442
BaseIndent := TokenStartX - 1;
404
444
// indent the same as the first line
406
446
if (p.y>0) and (p.y<=AEditor.Lines.Count) then begin
407
447
s:=AEditor.Lines[p.y-1];
408
while (IndentLen<p.x)
409
and ((IndentLen>length(s)) or (s[IndentLen] in [#9,' '])) do
448
while (BaseIndent<p.x)
449
and ((BaseIndent>length(s)) or (s[BaseIndent] in [#9,' '])) do
412
IndentLen:=AEditor.LogicalToPhysicalCol(s, p.y - 1, IndentLen);// consider tabs
452
BaseIndent:=AEditor.LogicalToPhysicalCol(s, p.y - 1, BaseIndent);// consider tabs
416
456
Parser.EnableMacros := Attributes.IndexOfName(CodeTemplateEnableMacros)>=0;
417
Parser.Indent := StringOfChar(' ', IndentLen);
457
Parser.KeepSubIndent := Attributes.IndexOfName(CodeTemplateKeepSubIndent)>=0;
458
Parser.Indent := StringOfChar(' ', BaseIndent);
418
459
LazarusIDE.SaveSourceEditorChangesToCodeCache(nil);
419
460
if not Parser.SubstituteCodeMacros(SrcEdit) then exit;
451
490
Parser.TrimEOTChar(EndOfTokenChr[i]);
454
i := AEditor.PluginCount - 1;
493
if Parser.EditCellList.Count > 0 then
494
i := AEditor.PluginCount - 1
455
497
while i >= 0 do begin
456
498
if AEditor.Plugin[i] is TSynPluginTemplateEdit then begin
500
p := AEditor.CaretXY;
457
501
TSynPluginTemplateEdit(AEditor.Plugin[i]).CellParserEnabled := False;
458
502
TSynPluginTemplateEdit(AEditor.Plugin[i]).SetTemplate(Parser.DestTemplate, p);
459
503
TSynPluginTemplateEdit(AEditor.Plugin[i]).AddEditCells(Parser.EditCellList);
464
508
if i < 0 then begin
465
509
// replace the selected text and position the caret
466
AEditor.SelText := Parser.DestTemplate;
467
AEditor.MoveCaretIgnoreEOL(p);
510
AEditor.SetTextBetweenPoints(AEditor.BlockBegin, AEditor.BlockEnd, Parser.DestTemplate, [], scamEnd);
512
AEditor.MoveCaretIgnoreEOL(p);
470
515
AEditor.EndUpdate;