SynEdit, IDE: Refactoring for code template completion. Sort the list after parsing. Issue #40764.

This commit is contained in:
Juha 2024-02-13 11:17:11 +02:00
parent 7044a3b3df
commit a9f0754324
7 changed files with 294 additions and 291 deletions

View File

@ -458,8 +458,7 @@ type
function GetTokenList: string;
function GetTokenValue(Token: string): string;
published
property AutoCompleteList: TStrings read fAutoCompleteList
write SetAutoCompleteList;
property AutoCompleteList: TStrings read fAutoCompleteList write SetAutoCompleteList;
property EndOfTokenChr: string read FEndOfTokenChr write FEndOfTokenChr;
property ShortCut: TShortCut read FShortCut write SetShortCut;
property ExecCommandID: TSynEditorCommand read FExecCommandID write FExecCommandID;

View File

@ -64,6 +64,37 @@ type
TOnExecuteCompletion = procedure(ASynAutoComplete: TCustomSynAutoComplete;
Index: integer) of object;
// Data for a single template item.
{ TCodeTemplate }
TCodeTemplate = class
private // The Key is Stored in a TCodeTemplateList string item.
fValue: string;
fComment: string;
fAttributes: TStringList; // List of attributes.
public
constructor Create;
constructor Create(aTemplate: TCodeTemplate);
constructor Create(aValue, aComment: string);
destructor Destroy; override;
procedure SetBooleanAttribute(aName: string; aValue: Boolean);
procedure SetValueWithoutLastEOL(aValue: string);
property Value: string read fValue write fValue;
property Comment: string read fComment write fComment;
property Attributes: TStringList read fAttributes;
end;
{ TCodeTemplateList }
TCodeTemplateList = class(TStringListUTF8Fast)
private
function GetTemplate(Index: Integer): TCodeTemplate;
procedure SetTemplate(Index: Integer; AValue: TCodeTemplate);
public
property Objects[Index: Integer]: TCodeTemplate read GetTemplate write SetTemplate;
end;
{ TCustomSynAutoComplete }
TCustomSynAutoComplete = class(TLazSynMultiEditPlugin)
@ -71,25 +102,18 @@ type
fOnTokenNotFound: TOnTokenNotFound;
fIndentToTokenStart: boolean;
FOnExecuteCompletion: TOnExecuteCompletion;
fAttributes: TFPList;// list of TStrings
function GetCompletionAttributes(Index: integer): TStrings;
procedure ClearAttributes;
protected
fAutoCompleteList: TStrings;
fCompletions: TStrings;
fCompletionComments: TStrings;
fCompletionValues: TStrings;
fCodeTemplSource: TStrings;
fCodeTemplates: TCodeTemplateList;
fEditor: TCustomSynEdit;
fEditors: TList;
fEOTokenChars: string;
fCaseSensitive: boolean;
fParsed: boolean;
procedure CompletionListChanged(Sender: TObject);
function GetCompletions: TStrings;
function GetCompletionComments: TStrings;
function GetCompletionValues: TStrings;
function GetCodeTemplates: TCodeTemplateList;
procedure ParseCompletionList; virtual;
procedure SetAutoCompleteList(Value: TStrings); virtual;
procedure SetCodeTemplSource(Value: TStrings); virtual;
procedure SynEditCommandHandler(Sender: TObject; AfterProcessing: boolean;
var Handled: boolean; var Command: TSynEditorCommand;
var AChar: TUTF8Char;
@ -99,27 +123,17 @@ type
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure AddCompletion(AToken, AValue, AComment: string;
TheAttributes: TStrings = nil);
procedure DeleteCompletion(Index: integer);
procedure AddCompletion(AToken: string; ATemplate: TCodeTemplate);
procedure AddCompletion(AToken, AValue, AComment: string);
procedure Execute(AEditor: TCustomSynEdit); virtual;
procedure ExecuteCompletion(AToken: string; AEditor: TCustomSynEdit);
virtual;
procedure ExecuteCompletion(AToken: string; AEditor: TCustomSynEdit); virtual;
public
property AutoCompleteList: TStrings read fAutoCompleteList
write SetAutoCompleteList;
property CodeTemplSource: TStrings read fCodeTemplSource write SetCodeTemplSource;
property CaseSensitive: boolean read fCaseSensitive write fCaseSensitive;
property Completions: TStrings read GetCompletions;
property CompletionComments: TStrings read GetCompletionComments;
property CompletionValues: TStrings read GetCompletionValues;
property CodeTemplates: TCodeTemplateList read GetCodeTemplates;
property EndOfTokenChr: string read fEOTokenChars write fEOTokenChars;
property CompletionAttributes[Index: integer]: TStrings
read GetCompletionAttributes;
property OnTokenNotFound: TOnTokenNotFound
read fOnTokenNotFound write fOnTokenNotFound;
property IndentToTokenStart: boolean
read fIndentToTokenStart write fIndentToTokenStart;
property OnTokenNotFound: TOnTokenNotFound read fOnTokenNotFound write fOnTokenNotFound;
property IndentToTokenStart: boolean read fIndentToTokenStart write fIndentToTokenStart;
property OnExecuteCompletion: TOnExecuteCompletion read FOnExecuteCompletion
write FOnExecuteCompletion;
end;
@ -128,7 +142,7 @@ type
TSynEditAutoComplete = class(TCustomSynAutoComplete)
published
property AutoCompleteList;
property CodeTemplSource;
property CaseSensitive;
property Editor;
property EndOfTokenChr;
@ -139,22 +153,100 @@ type
implementation
{ TCodeTemplate }
constructor TCodeTemplate.Create;
begin
inherited Create;
fAttributes := TStringListUTF8Fast.Create;
fAttributes.UseLocale := False;
fAttributes.OwnsObjects := True;
end;
constructor TCodeTemplate.Create(aTemplate: TCodeTemplate);
begin
Create;
fValue := aTemplate.Value;
fComment := aTemplate.Comment;
fAttributes.Assign(aTemplate.Attributes);
end;
constructor TCodeTemplate.Create(aValue, aComment: string);
begin
Create;
fValue := aValue;
fComment := aComment;
end;
destructor TCodeTemplate.Destroy;
begin
fAttributes.Free;
inherited Destroy;
end;
procedure TCodeTemplate.SetBooleanAttribute(aName: string; aValue: Boolean);
var
i: Integer;
begin
if aValue then
fAttributes.Values[aName] := 'true'
else begin
i := fAttributes.IndexOfName(aName);
if i >= 0 then
fAttributes.Delete(i);
end;
end;
procedure TCodeTemplate.SetValueWithoutLastEOL(aValue: string);
var
l: Integer;
begin // Remove last EOL from Value.
if aValue = '' then Exit;
l := Length(aValue);
if aValue[l] in [#10,#13] then begin
Dec(l);
if (l > 0) and (aValue[l] in [#10,#13])
and (aValue[l] <> aValue[l+1]) then
Dec(l);
SetLength(aValue, l);
end;
fValue := aValue;
end;
{ TCodeTemplateList }
function TCodeTemplateList.GetTemplate(Index: Integer): TCodeTemplate;
begin
Result := TCodeTemplate(inherited GetObject(Index));
end;
procedure TCodeTemplateList.SetTemplate(Index: Integer; AValue: TCodeTemplate);
begin
inherited PutObject(Index, AValue);
end;
{ TCustomSynAutoComplete }
procedure TCustomSynAutoComplete.AddCompletion(AToken, AValue, AComment: string;
TheAttributes: TStrings);
procedure TCustomSynAutoComplete.AddCompletion(AToken: string; ATemplate: TCodeTemplate);
var
NewTemplate: TCodeTemplate;
begin
if AToken <> '' then begin
if not fParsed then
ParseCompletionList;
if aToken = '' then Exit;
if not fParsed then
ParseCompletionList;
NewTemplate := TCodeTemplate.Create(ATemplate);
fCodeTemplates.AddObject(aToken, NewTemplate);
end;
fCompletions.Add(AToken);
fCompletionComments.Add(AComment);
fCompletionValues.Add(AValue);
if TheAttributes=nil then
TheAttributes:=TStringList.Create;
fAttributes.Add(TheAttributes);
end;
procedure TCustomSynAutoComplete.AddCompletion(AToken, AValue, AComment: string);
var
NewTemplate: TCodeTemplate;
begin
if aToken = '' then Exit;
if not fParsed then
ParseCompletionList;
NewTemplate := TCodeTemplate.Create(AValue, AComment);
fCodeTemplates.AddObject(aToken, NewTemplate);
end;
procedure TCustomSynAutoComplete.CompletionListChanged(Sender: TObject);
@ -165,48 +257,18 @@ end;
constructor TCustomSynAutoComplete.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fAutoCompleteList := TStringList.Create;
TStringList(fAutoCompleteList).OnChange := @CompletionListChanged;
fCompletions := TStringListUTF8Fast.Create;
fCompletionComments := TStringListUTF8Fast.Create;
fCompletionValues := TStringListUTF8Fast.Create;
fCodeTemplSource := TStringList.Create;
TStringList(fCodeTemplSource).OnChange := @CompletionListChanged;
fCodeTemplates := TCodeTemplateList.Create;
fEditors := TList.Create;
fEOTokenChars := '()[]{}.';
fAttributes:=TFPList.Create;
end;
function TCustomSynAutoComplete.GetCompletionAttributes(Index: integer): TStrings;
begin
Result:=TStrings(fAttributes[Index]);
end;
procedure TCustomSynAutoComplete.ClearAttributes;
var
i: Integer;
begin
for i:=0 to fAttributes.Count-1 do
TObject(fAttributes[i]).Free;
fAttributes.Clear;
end;
procedure TCustomSynAutoComplete.DeleteCompletion(Index: integer);
begin
fCompletions.Delete(Index);
fCompletionComments.Delete(Index);
fCompletionValues.Delete(Index);
TObject(fAttributes[Index]).Free;
fAttributes.Delete(Index);
end;
destructor TCustomSynAutoComplete.Destroy;
begin
fEditors.Free;
fCompletions.Free;
fCompletionComments.Free;
fCompletionValues.Free;
fAutoCompleteList.Free;
ClearAttributes;
fAttributes.Free;
fCodeTemplates.Free;
fCodeTemplSource.Free;
inherited Destroy;
end;
@ -231,7 +293,7 @@ begin
if Assigned(OnTokenNotFound) then
OnTokenNotFound(Self,'',AEditor,i);
if i>=0 then
ExecuteCompletion(FCompletions[i], AEditor);
ExecuteCompletion(fCodeTemplates[i], AEditor);
end;
end;
end;
@ -245,6 +307,7 @@ var
p, p2: TPoint;
NewCaretPos: boolean;
Temp: TStringList;
Template: TCodeTemplate;
begin
if not fParsed then
ParseCompletionList;
@ -255,15 +318,15 @@ begin
OnTokenNotFound(Self,AToken,AEditor,i);
end;
if (Len > 0) and (AEditor <> nil) and not AEditor.ReadOnly
and (fCompletions.Count > 0)
and (fCodeTemplates.Count > 0)
then begin
// find completion for this token - not all chars necessary if unambiguous
i := fCompletions.Count - 1;
i := fCodeTemplates.Count - 1;
IdxMaybe := -1;
NumMaybe := 0;
if fCaseSensitive then begin
while i > -1 do begin
s := fCompletions[i];
s := fCodeTemplates[i];
if s = AToken then
break
else if LazStartsStr(AToken, s) then begin
@ -274,7 +337,7 @@ begin
end;
end else begin
while i > -1 do begin
s := fCompletions[i];
s := fCodeTemplates[i];
if AnsiCompareText(s, AToken) = 0 then
break
else if AnsiCompareText(Copy(s, 1, Len), AToken) = 0 then begin
@ -322,8 +385,9 @@ begin
NewCaretPos := FALSE;
Temp := TStringList.Create;
try
Temp.Text := fCompletionValues[i];
s:=fCompletionValues[i];
Template := fCodeTemplates.Objects[i];
s:=Template.fValue;
Temp.Text := s;
if (s<>'') and (s[length(s)] in [#10,#13]) then
Temp.Add('');
@ -382,62 +446,46 @@ begin
end;
end;
function TCustomSynAutoComplete.GetCompletions: TStrings;
function TCustomSynAutoComplete.GetCodeTemplates: TCodeTemplateList;
begin
if not fParsed then
ParseCompletionList;
Result := fCompletions;
end;
function TCustomSynAutoComplete.GetCompletionComments: TStrings;
begin
if not fParsed then
ParseCompletionList;
Result := fCompletionComments;
end;
function TCustomSynAutoComplete.GetCompletionValues: TStrings;
begin
if not fParsed then
ParseCompletionList;
Result := fCompletionValues;
Result := fCodeTemplates;
end;
procedure TCustomSynAutoComplete.ParseCompletionList;
var
sComplKey, sComment, sComplValue: string;
sKey, sValue, sComment: string;
procedure SaveEntry;
var
CurAttributes: TStrings;
StartI, EndI: Integer;
Template: TCodeTemplate;
begin
fCompletions.Add(sComplKey);
sComplKey := '';
fCompletionComments.Add(sComment);
sComment := '';
CurAttributes:=TStringListUTF8Fast.Create;
Assert(not LazStartsStr(CodeTemplateMacroMagic, sComplValue), 'SaveEntry: Found '+CodeTemplateMacroMagic);
if LazStartsStr(CodeTemplateAttributesStartMagic, sComplValue) then
Template := TCodeTemplate.Create;
Assert(not LazStartsStr(CodeTemplateMacroMagic, sValue), 'SaveEntry: Found '+CodeTemplateMacroMagic);
if LazStartsStr(CodeTemplateAttributesStartMagic, sValue) then
begin
// Start of attributes
StartI := Length(CodeTemplateAttributesStartMagic) + 1;
while (StartI <= Length(sComplValue)) and (sComplValue[StartI] in [#10,#13]) do
while (StartI <= Length(sValue)) and (sValue[StartI] in [#10,#13]) do
Inc(StartI);
EndI := PosEx(CodeTemplateAttributesEndMagic, sComplValue, StartI);
EndI := PosEx(CodeTemplateAttributesEndMagic, sValue, StartI);
if EndI = 0 then
raise Exception.Create('TCustomSynAutoComplete.ParseCompletionList: "'
+ CodeTemplateAttributesEndMagic + '" not found.');
CurAttributes.Text := Copy(sComplValue, StartI, EndI-StartI);
Template.Attributes.Text := Copy(sValue, StartI, EndI-StartI);
// Start of value
StartI := EndI + Length(CodeTemplateAttributesEndMagic);
while (StartI <= Length(sComplValue)) and (sComplValue[StartI] in [#10,#13]) do
while (StartI <= Length(sValue)) and (sValue[StartI] in [#10,#13]) do
Inc(StartI);
sComplValue := Copy(sComplValue, StartI, Length(sComplValue));
Template.Value := Copy(sValue, StartI, Length(sValue));
end;
fCompletionValues.Add(sComplValue);
sComplValue := '';
fAttributes.Add(CurAttributes);
Template.Comment := sComment;
fCodeTemplates.AddObject(sKey, Template);
sKey := '';
sValue := '';
sComment := '';
end;
var
@ -446,29 +494,28 @@ var
S: string;
TemplateStarted: Boolean;
begin
fCompletions.Clear;
fCompletionComments.Clear;
fCompletionValues.Clear;
ClearAttributes;
if fAutoCompleteList.Count > 0 then begin
S := fAutoCompleteList[0];
fCodeTemplates.Clear;
sKey := '';
sValue := '';
sComment := '';
if fCodeTemplSource.Count > 0 then begin
S := fCodeTemplSource[0];
BorlandDCI := (S <> '') and (S[1] = '[');
TemplateStarted:=false;
for i := 0 to fAutoCompleteList.Count - 1 do begin
S := fAutoCompleteList[i];
for i := 0 to fCodeTemplSource.Count - 1 do begin
S := fCodeTemplSource[i];
Len := Length(S);
if BorlandDCI then begin
// the style of the Delphi32.dci file
if (Len > 0) and (S[1] = '[') then begin
// save last entry
if sComplKey <> '' then
if sKey <> '' then
SaveEntry;
// new completion entry
j := 2;
while (j <= Len) and (S[j] > ' ') do
Inc(j);
sComplKey := Copy(S, 2, j - 2);
sKey := Copy(S, 2, j - 2);
// start of comment in DCI file
while (j <= Len) and (S[j] <= ' ') do
Inc(j);
@ -482,36 +529,37 @@ begin
TemplateStarted:=true;
end else begin
if not TemplateStarted then
sComplValue := sComplValue + LineEnding;
sValue := sValue + LineEnding;
TemplateStarted:=false;
sComplValue := sComplValue + S;
sValue := sValue + S;
end;
end else begin
// the original style
if (Len > 0) and (S[1] <> '=') then begin
// save last entry
if sComplKey <> '' then
if sKey <> '' then
SaveEntry;
// new completion entry
sComplKey := S;
sKey := S;
TemplateStarted:=true;
end else if (Len > 0) and (S[1] = '=') then begin
if not TemplateStarted then
sComplValue := sComplValue + LineEnding;
sValue := sValue + LineEnding;
TemplateStarted:=false;
sComplValue := sComplValue + Copy(S, 2, Len);
sValue := sValue + Copy(S, 2, Len);
end;
end;
end;
if sComplKey <> '' then
if sKey <> '' then
SaveEntry;
end;
fCodeTemplates.Sort;
fParsed:=true;
end;
procedure TCustomSynAutoComplete.SetAutoCompleteList(Value: TStrings);
procedure TCustomSynAutoComplete.SetCodeTemplSource(Value: TStrings);
begin
fAutoCompleteList.Assign(Value);
fCodeTemplSource.Assign(Value);
fParsed := FALSE;
end;

View File

@ -108,8 +108,7 @@ type
end;
function ExecuteCodeTemplate(SrcEdit: TSourceEditorInterface;
const TemplateName, TemplateValue, {%H-}TemplateComment,
EndOfTokenChr: string; Attributes: TStrings;
Template: TCodeTemplate; const TemplateName, EndOfTokenChr: string;
IndentToTokenStart: boolean): boolean;
implementation
@ -452,8 +451,7 @@ begin
end;
function ExecuteCodeTemplate(SrcEdit: TSourceEditorInterface;
const TemplateName, TemplateValue, TemplateComment,
EndOfTokenChr: string; Attributes: TStrings;
Template: TCodeTemplate; const TemplateName, EndOfTokenChr: string;
IndentToTokenStart: boolean): boolean;
var
AEditor: TSynEdit;
@ -471,7 +469,7 @@ begin
Result:=false;
//debugln('ExecuteCodeTemplate ',dbgsName(SrcEdit),' ',dbgsName(SrcEdit.EditorControl));
AEditor:=SrcEdit.EditorControl as TSynEdit;
Pattern:=TemplateValue;
Pattern:=Template.Value;
Parser := TLazTemplateParser.Create(Pattern);
AEditor.BeginUpdate;
try
@ -499,8 +497,8 @@ begin
dec(BaseIndent);
end;
Parser.EnableMacros := Attributes.IndexOfName(CodeTemplateEnableMacros)>=0;
Parser.KeepSubIndent := Attributes.IndexOfName(CodeTemplateKeepSubIndent)>=0;
Parser.EnableMacros := Template.Attributes.IndexOfName(CodeTemplateEnableMacros)>=0;
Parser.KeepSubIndent := Template.Attributes.IndexOfName(CodeTemplateKeepSubIndent)>=0;
Parser.Indent := LogBaseIndent;
CodeToolBossOriginalIndent := CodeToolBoss.IndentSize;
if Parser.KeepSubIndent then

View File

@ -230,7 +230,7 @@ begin
// exists
if not ASkipExistCheck then
if ASynAutoComplete.Completions.IndexOf(AToken) >= 0 then
if ASynAutoComplete.CodeTemplates.IndexOf(AToken) >= 0 then
begin
IDEMessageDialog(lisCodeTemplError, lisCodeTemplErrorAlreadyExists, mtError, [mbOK]);
exit(false);
@ -280,19 +280,19 @@ var
Str: array of string;
begin
Result:= mrCancel;
if (AIndex<0) or (AIndex>=ASynAutoComplete.Completions.Count) then exit;
if (AIndex<0) or (AIndex>=ASynAutoComplete.CodeTemplates.Count) then exit;
SetLength(Str{%H-}, 2);
Str[0]:= ASynAutoComplete.Completions[AIndex];
Str[1]:= ASynAutoComplete.CompletionComments[AIndex];
Str[0] := ASynAutoComplete.CodeTemplates[AIndex];
Str[1] := ASynAutoComplete.CodeTemplates.Objects[AIndex].Comment;
if not InputQuery(lisCodeTemplEditCodeTemplate,
[lisCodeTemplToken, lisCodeTemplComment], Str) then exit;
if not IsCodeTemplateOk(ASynAutoComplete, Str[0], true) then exit;
ASynAutoComplete.Completions[AIndex]:= Str[0];
ASynAutoComplete.CompletionComments[AIndex]:= Str[1];
ASynAutoComplete.CodeTemplates[AIndex] := Str[0];
ASynAutoComplete.CodeTemplates.Objects[AIndex].Comment := Str[1];
Result:= mrOk;
end;
@ -983,7 +983,7 @@ begin
if AddCodeTemplate(SynAutoComplete,Token,Comment)=mrOk then begin
SynAutoComplete.AddCompletion(Token, '', Comment);
FillCodeTemplateListBox;
Index := SynAutoComplete.Completions.IndexOf(Token);
Index := SynAutoComplete.CodeTemplates.IndexOf(Token);
if Index >= 0 then
Index := TemplateListBox.Items.IndexOfObject(TObject({%H-}Pointer(Index)));
if Index >= 0 then
@ -1008,11 +1008,11 @@ begin
if a < 0 then exit;
if IDEMessageDialog(lisConfirm, dlgDelTemplate
+'"'+SynAutoComplete.Completions[a]+' - '
+SynAutoComplete.CompletionComments[a]+'"'
+'"'+SynAutoComplete.CodeTemplates[a]+' - '
+SynAutoComplete.CodeTemplates[a]+'"'
+'?',mtConfirmation,[mbOk,mbCancel])=mrOK
then begin
SynAutoComplete.DeleteCompletion(a);
SynAutoComplete.CodeTemplates.Delete(a);
LastTemplate := -1; // to prevent the saving of the deleted template
FillCodeTemplateListBox;
if idx < TemplateListBox.Items.Count then begin
@ -1118,8 +1118,8 @@ begin
if EditCodeTemplate(SynAutoComplete, a)=mrOk then begin
TemplateListBox.Items[idx]:=
SynAutoComplete.Completions[a]
+' - "'+SynAutoComplete.CompletionComments[a]+'"';
SynAutoComplete.CodeTemplates[a]
+' - "'+SynAutoComplete.CodeTemplates[a]+'"';
ShowCurCodeTemplate;
end;
end;
@ -1184,11 +1184,12 @@ var
begin
sl:=TStringListUTF8Fast.Create;
try
for a:=0 to SynAutoComplete.Completions.Count-1 do begin
for a:=0 to SynAutoComplete.CodeTemplates.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({%H-}Pointer(a)));
sl.AddObject(SynAutoComplete.CodeTemplates[a]
+' - "'+SynAutoComplete.CodeTemplates.Objects[a].Comment+'"',
TObject({%H-}Pointer(a)));
end;
sl.Sort;
TemplateListBox.Items.Assign(sl);
@ -1201,7 +1202,7 @@ procedure TCodeTemplateDialog.ShowCurCodeTemplate;
var
EnableMacros, KeepSubIndent: boolean;
LineCount: integer;
Attributes: TStrings;
Template: TCodeTemplate;
idx, a, sp, ep: integer;
s: string;
AutoOnCat: array[TAutoCompleteOption] of Boolean;
@ -1215,7 +1216,7 @@ var
//
function GetBooleanAttribute(const AttrName: string): boolean; inline;
begin
result:=StrToBoolDef(Attributes.Values[AttrName], false);
result:=StrToBoolDef(Template.Attributes.Values[AttrName], false);
end;
//
begin
@ -1237,15 +1238,15 @@ begin
// debugln('TCodeTemplateDialog.ShowCurCodeTemplate A a=',dbgs(a));
if a >= 0
then begin
EditTemplateGroupBox.Caption:=dbgstr(SynAutoComplete.Completions[a])
+' - '+dbgstr(SynAutoComplete.CompletionComments[a]);
Attributes:=SynAutoComplete.CompletionAttributes[a];
Template:=SynAutoComplete.CodeTemplates.Objects[a];
EditTemplateGroupBox.Caption:=dbgstr(SynAutoComplete.CodeTemplates[a])
+' - '+dbgstr(Template.Comment);
EnableMacros:=GetBooleanAttribute(CodeTemplateEnableMacros);
KeepSubIndent:=GetBooleanAttribute(CodeTemplateKeepSubIndent);
for c:=Low(TAutoCompleteOption) to High(TAutoCompleteOption) do
AutoOnCat[c]:=GetBooleanAttribute(AutoCompleteOptionNames[c]);
LastTemplate := -1;
s:=SynAutoComplete.CompletionValues[a];
s:=Template.Value;
//debugln('TCodeTemplateDialog.ShowCurCodeTemplate s="',s,'"');
sp:=1;
ep:=1;
@ -1276,51 +1277,17 @@ end;
procedure TCodeTemplateDialog.SaveCurCodeTemplate;
var
a: LongInt;
procedure SetBooleanAttribute(const AttrName: string; NewValue: boolean);
var
Attributes: TStrings;
l: LongInt;
begin
Attributes:=SynAutoComplete.CompletionAttributes[a];
if NewValue then
Attributes.Values[AttrName]:='true'
else begin
l:=Attributes.IndexOfName(AttrName);
if l>=0 then
Attributes.Delete(l);
end;
end;
var
NewValue: string;
l: integer;
Templ: TCodeTemplate;
c: TAutoCompleteOption;
begin
if LastTemplate<0 then exit;
a := LastTemplate;
//DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate A a=',dbgs(a));
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;
SynAutoComplete.CompletionValues[a]:=NewValue;
SetBooleanAttribute(CodeTemplateEnableMacros,UseMacrosCheckBox.Checked);
SetBooleanAttribute(CodeTemplateKeepSubIndent,KeepSubIndentCheckBox.Checked);
Templ:=SynAutoComplete.CodeTemplates.Objects[LastTemplate];
Templ.SetValueWithoutLastEOL(TemplateSynEdit.Lines.Text);
Templ.SetBooleanAttribute(CodeTemplateEnableMacros, UseMacrosCheckBox.Checked);
Templ.SetBooleanAttribute(CodeTemplateKeepSubIndent, KeepSubIndentCheckBox.Checked);
for c:=low(TAutoCompleteOption) to High(TAutoCompleteOption) do
SetBooleanAttribute(AutoCompleteOptionNames[c],AutoOnOptionsCheckGroup.Checked[ord(c)]);
//DebugLn('TCodeTemplateDialog.SaveCurCodeTemplate NewValue="',NewValue,'" SynAutoComplete.CompletionValues[a]="',SynAutoComplete.CompletionValues[a],'"');
Templ.SetBooleanAttribute(AutoCompleteOptionNames[c],
AutoOnOptionsCheckGroup.Checked[ord(c)]);
end;
{ TLazCodeMacros }

View File

@ -2496,36 +2496,34 @@ const
DciFileVersionName = '!FileVersion';
DciVersionName = '!Version';
function BuildBorlandDCIFile(
ACustomSynAutoComplete: TCustomSynAutoComplete): Boolean;
function BuildBorlandDCIFile(ACustomSynAutoComplete: TCustomSynAutoComplete): Boolean;
// returns if something has changed
var
sl: TStringList;
i, sp, ep, v: Integer;
Token, Comment, Value: String;
Attributes: TStrings;
Token, Value: String;
Template: TCodeTemplate;
begin
Result := False;
sl := TStringList.Create;
try
for i := 0 to ACustomSynAutoComplete.Completions.Count - 1 do
for i := 0 to ACustomSynAutoComplete.CodeTemplates.Count - 1 do
begin
Token := ACustomSynAutoComplete.Completions[i];
Comment := ACustomSynAutoComplete.CompletionComments[i];
Value := ACustomSynAutoComplete.CompletionValues[i];
sl.Add('[' + Token + ' | ' + Comment + ']');
Attributes:=ACustomSynAutoComplete.CompletionAttributes[i];
Token := ACustomSynAutoComplete.CodeTemplates[i];
Template := ACustomSynAutoComplete.CodeTemplates.Objects[i];
Value := Template.Value;
sl.Add('[' + Token + ' | ' + Template.Comment + ']');
// Store DciFileVersion as attribute to first macro
v := Attributes.IndexOfName(DciFileVersionName);
v := Template.Attributes.IndexOfName(DciFileVersionName);
if v >= 0 then
Attributes.Delete(v);
Template.Attributes.Delete(v);
if i = 0 then
Attributes.Values[DciFileVersionName] := IntToStr(DciFileVersion);
Template.Attributes.Values[DciFileVersionName] := IntToStr(DciFileVersion);
if (Attributes<>nil) and (Attributes.Count>0) then begin
if Template.Attributes.Count>0 then begin
sl.Add(CodeTemplateAttributesStartMagic);
sl.AddStrings(Attributes);
sl.AddStrings(Template.Attributes);
sl.Add(CodeTemplateAttributesEndMagic);
end;
sp := 1;
@ -2545,10 +2543,10 @@ begin
if (ep > sp) or ((Value <> '') and (Value[length(Value)] in [#10, #13])) then
sl.Add(copy(Value, sp, ep - sp));
end;
if ACustomSynAutoComplete.AutoCompleteList.Equals(sl) = False then
if not ACustomSynAutoComplete.CodeTemplSource.Equals(sl) then
begin
Result := True;
ACustomSynAutoComplete.AutoCompleteList := sl;
ACustomSynAutoComplete.CodeTemplSource := sl;
end;
finally
sl.Free;
@ -5786,14 +5784,14 @@ var
s: String;
FileVersion, i, j, v: Integer;
NewAutoComplete: TSynEditAutoComplete;
Attr, ExAtr: TStrings;
Added: Boolean;
Template: TCodeTemplate;
begin
s := CodeTemplateFileNameExpand;
Result := mrAbort;
if FileExistsUTF8(s) then begin
try
AnAutoComplete.AutoCompleteList.LoadFromFile(s);
AnAutoComplete.CodeTemplSource.LoadFromFile(s);
Result := mrOK;
except
Result := mrAbort;
@ -5801,35 +5799,30 @@ begin
if Result = mrAbort then
exit;
FileVersion := AnAutoComplete.Completions.Count;
FileVersion := AnAutoComplete.CodeTemplates.Count;
if (FileVersion > 0) then begin
ExAtr := AnAutoComplete.CompletionAttributes[0];
FileVersion := ExAtr.IndexOfName(DciFileVersionName);
Template := AnAutoComplete.CodeTemplates.Objects[0];
FileVersion := Template.Attributes.IndexOfName(DciFileVersionName);
if (FileVersion >= 0) then
FileVersion := StrToIntDef(ExAtr.ValueFromIndex[FileVersion], 0);
FileVersion := StrToIntDef(Template.Attributes.ValueFromIndex[FileVersion], 0);
end;
if FileVersion < DciFileVersion then begin
// Merge new entries
NewAutoComplete := TSynEditAutoComplete.Create(nil);
NewAutoComplete.AutoCompleteList.Text := ResourceDCIAsText;
NewAutoComplete.CodeTemplSource.Text := ResourceDCIAsText;
Added := False;
for i := 0 to NewAutoComplete.Completions.Count - 1 do begin
ExAtr := NewAutoComplete.CompletionAttributes[i];
j := ExAtr.IndexOfName(DciVersionName);
for i := 0 to NewAutoComplete.CodeTemplates.Count - 1 do begin
Template := NewAutoComplete.CodeTemplates.Objects[0];
j := Template.Attributes.IndexOfName(DciVersionName);
if j < 0 then
continue;
v := StrToIntDef(ExAtr.ValueFromIndex[j], 0);
v := StrToIntDef(Template.Attributes.ValueFromIndex[j], 0);
if v <= FileVersion then
continue;
if AnAutoComplete.Completions.IndexOf(NewAutoComplete.Completions[i]) >= 0 then
if AnAutoComplete.CodeTemplates.IndexOf(NewAutoComplete.CodeTemplates[i]) >= 0 then
continue;
Attr := TStringListUTF8Fast.Create;
Attr.Assign(ExAtr); // will be owned by AnAutoComplete;
AnAutoComplete.AddCompletion(
NewAutoComplete.Completions[i],
NewAutoComplete.CompletionValues[i],
NewAutoComplete.CompletionComments[i],
Attr);
AnAutoComplete.AddCompletion(NewAutoComplete.CodeTemplates[i],
NewAutoComplete.CodeTemplates.Objects[0]);
Added := True;
end;
NewAutoComplete.Free;
@ -5839,7 +5832,7 @@ begin
end;
end
else begin
AnAutoComplete.AutoCompleteList.Text := ResourceDCIAsText;
AnAutoComplete.CodeTemplSource.Text := ResourceDCIAsText;
end;
end;
@ -5847,7 +5840,7 @@ function TEditorOptions.SaveCodeTemplates(AnAutoComplete: TSynEditAutoComplete
): TModalResult;
begin
try
AnAutoComplete.AutoCompleteList.SaveToFile(CodeTemplateFileNameExpand);
AnAutoComplete.CodeTemplSource.SaveToFile(CodeTemplateFileNameExpand);
Result := mrOK;
except
Result := mrAbort;

View File

@ -7250,15 +7250,15 @@ var
begin
if not CodeToolsOpts.IdentComplIncludeCodeTemplates then
Exit;
for I := 0 to SourceEditorManager.CodeTemplateModul.Completions.Count-1 do
begin
New := TCodeTemplateIdentifierListItem.Create(CodeTemplateCompatibility, False, CodeTemplateHistoryIndex,
PChar(SourceEditorManager.CodeTemplateModul.Completions[I]),
CodeTemplateLevel, nil, nil, ctnCodeTemplate);
New.Comment := SourceEditorManager.CodeTemplateModul.CompletionComments[I];
CodeToolBoss.IdentifierList.Add(New);
end;
with SourceEditorManager.CodeTemplateModul do
for I := 0 to CodeTemplates.Count-1 do
begin
New := TCodeTemplateIdentifierListItem.Create(CodeTemplateCompatibility,
False, CodeTemplateHistoryIndex, PChar(CodeTemplates[I]),
CodeTemplateLevel, nil, nil, ctnCodeTemplate);
New.Comment := CodeTemplates.Objects[I].Comment;
CodeToolBoss.IdentifierList.Add(New);
end;
end;
procedure TMainIDE.DoCompile;

View File

@ -2488,15 +2488,16 @@ Begin
ctTemplateCompletion:
begin
ccSelection:='';
for I := 0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
NewStr := Manager.CodeTemplateModul.Completions[I];
if NewStr<>'' then begin
NewStr:=#3'B'+NewStr+#3'b';
while length(NewStr)<10+4 do NewStr:=NewStr+' ';
NewStr:=NewStr+' '+Manager.CodeTemplateModul.CompletionComments[I];
SL.Add(NewStr);
with Manager.CodeTemplateModul do
for I := 0 to CodeTemplates.Count-1 do begin
NewStr := CodeTemplates[I];
if NewStr<>'' then begin
NewStr:=#3'B'+NewStr+#3'b';
while length(NewStr)<10+4 do NewStr:=NewStr+' ';
NewStr:=NewStr+' '+CodeTemplates.Objects[I].Comment;
SL.Add(NewStr);
end;
end;
end;
end;
end;
@ -5086,6 +5087,7 @@ var
SrcToken: String;
IdChars: TSynIdentChars;
WordToken: String;
Template: TCodeTemplate;
begin
Result:=false;
Line:=GetLineText;
@ -5098,28 +5100,28 @@ begin
x2 := Min(x2, p.x);
WordToken := copy(Line, x1, x2-x1);
IdChars := FEditor.IdentChars;
for i:=0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
AToken:=Manager.CodeTemplateModul.Completions[i];
if AToken='' then continue;
if AToken[1] in IdChars then
SrcToken:=WordToken
else
SrcToken:=copy(Line,length(Line)-length(AToken)+1,length(AToken));
//DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
if (AnsiCompareText(AToken,SrcToken)=0)
and (Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)>=0)
and ( (not FEditor.SelAvail) or
(Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(
AutoCompleteOptionNames[acoIgnoreForSelection]) < 0) )
then begin
Result:=true;
with Manager.CodeTemplateModul do
for i:=0 to CodeTemplates.Count-1 do begin
AToken:=CodeTemplates[i];
Template:=CodeTemplates.Objects[i];
if AToken='' then continue;
if AToken[1] in IdChars then
SrcToken:=WordToken
else
SrcToken:=copy(Line,length(Line)-length(AToken)+1,length(AToken));
//DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
Manager.CodeTemplateModul.ExecuteCompletion(AToken,FEditor);
AddChar:=not Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(
AutoCompleteOptionNames[acoRemoveChar])>=0;
exit;
if (AnsiCompareText(AToken,SrcToken)=0)
and (Template.Attributes.IndexOfName(CatName)>=0)
and ( (not FEditor.SelAvail) or
(Template.Attributes.IndexOfName(AutoCompleteOptionNames[acoIgnoreForSelection])<0) )
then begin
Result:=true;
//DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
ExecuteCompletion(AToken,FEditor);
AddChar:=not Template.Attributes.IndexOfName(AutoCompleteOptionNames[acoRemoveChar])>=0;
exit;
end;
end;
end;
if EditorOpts.AutoBlockCompletion
and (FEditor.Highlighter is TSynPasSyn) then
@ -11649,22 +11651,18 @@ procedure TSourceEditorManager.CodeTemplateExecuteCompletion(
ASynAutoComplete: TCustomSynAutoComplete; Index: integer);
var
SrcEdit: TSourceEditorInterface;
Template: TCodeTemplate;
TemplateName: string;
TemplateValue: string;
TemplateComment: string;
TemplateAttr: TStrings;
begin
SrcEdit:=FindSourceEditorWithEditorComponent(ASynAutoComplete.Editor);
if SrcEdit=nil then
SrcEdit := ActiveEditor;
//debugln('TSourceNotebook.OnCodeTemplateExecuteCompletion A ',dbgsName(SrcEdit),' ',dbgsName(ASynAutoComplete.Editor));
TemplateName:=ASynAutoComplete.Completions[Index];
TemplateValue:=ASynAutoComplete.CompletionValues[Index];
TemplateComment:=ASynAutoComplete.CompletionComments[Index];
TemplateAttr:=ASynAutoComplete.CompletionAttributes[Index];
ExecuteCodeTemplate(SrcEdit,TemplateName,TemplateValue,TemplateComment,
ASynAutoComplete.EndOfTokenChr,TemplateAttr,
TemplateName:=ASynAutoComplete.CodeTemplates[Index];
Template:=ASynAutoComplete.CodeTemplates.Objects[Index];
ExecuteCodeTemplate(SrcEdit,Template,TemplateName,
ASynAutoComplete.EndOfTokenChr,
ASynAutoComplete.IndentToTokenStart);
end;