SynEdit: Optimize parsing CompletionList. Use faster string comparison.

git-svn-id: trunk@64626 -
This commit is contained in:
juha 2021-02-20 13:14:27 +00:00
parent b82ead0cfa
commit a523ee94b3

View File

@ -44,8 +44,8 @@ unit SynEditAutoComplete;
interface interface
uses uses
Classes, StrUtils, Classes, SysUtils, StrUtils,
LCLIntf, LCLType, LCLProc, Controls, SysUtils, Menus, LCLIntf, LCLType, Controls, LCLProc,
LazStringUtils, LazUTF8, LazStringUtils, LazUTF8,
SynEdit, SynEditKeyCmds, SynEditPlugins; SynEdit, SynEditKeyCmds, SynEditPlugins;
@ -167,16 +167,15 @@ begin
inherited Create(AOwner); inherited Create(AOwner);
fAutoCompleteList := TStringList.Create; fAutoCompleteList := TStringList.Create;
TStringList(fAutoCompleteList).OnChange := @CompletionListChanged; TStringList(fAutoCompleteList).OnChange := @CompletionListChanged;
fCompletions := TStringList.Create; fCompletions := TStringListUTF8Fast.Create;
fCompletionComments := TStringList.Create; fCompletionComments := TStringListUTF8Fast.Create;
fCompletionValues := TStringList.Create; fCompletionValues := TStringListUTF8Fast.Create;
fEditors := TList.Create; fEditors := TList.Create;
fEOTokenChars := '()[]{}.'; fEOTokenChars := '()[]{}.';
fAttributes:=TFPList.Create; fAttributes:=TFPList.Create;
end; end;
function TCustomSynAutoComplete.GetCompletionAttributes(Index: integer function TCustomSynAutoComplete.GetCompletionAttributes(Index: integer): TStrings;
): TStrings;
begin begin
Result:=TStrings(fAttributes[Index]); Result:=TStrings(fAttributes[Index]);
end; end;
@ -405,74 +404,47 @@ begin
end; end;
procedure TCustomSynAutoComplete.ParseCompletionList; procedure TCustomSynAutoComplete.ParseCompletionList;
procedure RemoveFirstLine(var Pattern: string);
var
i: Integer;
begin
// remove first line (i.e. macro enabled flag)
i:=1;
while (i<=length(Pattern)) and (not (Pattern[i] in [#10,#13])) do inc(i);
if (i<length(Pattern)) and (Pattern[i+1] in [#10,#13])
and (Pattern[i+1]<>Pattern[i]) then
inc(i);
delete(Pattern,1,i);
end;
var var
BorlandDCI: boolean; sComplKey, sComment, sComplValue: string;
i, j, Len: integer;
s, sCompl, sComment, sComplValue: string;
TemplateStarted: Boolean;
procedure SaveEntry; procedure SaveEntry;
var var
CurAttributes: TStrings; CurAttributes: TStrings;
Lines: TStringList; StartI, EndI: Integer;
LastLineHasEnding: boolean;
l: Integer;
begin begin
fCompletions.Add(sCompl); fCompletions.Add(sComplKey);
sCompl := ''; sComplKey := '';
fCompletionComments.Add(sComment); fCompletionComments.Add(sComment);
sComment := ''; sComment := '';
CurAttributes:=TStringList.Create; CurAttributes:=TStringListUTF8Fast.Create;
if copy(sComplValue,1,length(CodeTemplateMacroMagic))=CodeTemplateMacroMagic Assert(not StartsStr(CodeTemplateMacroMagic, sComplValue), 'SaveEntry: Found '+CodeTemplateMacroMagic);
then begin if StartsStr(CodeTemplateAttributesStartMagic, sComplValue) then
RemoveFirstLine(sComplValue);
CurAttributes.Values[CodeTemplateEnableMacros]:='true';
end else if copy(sComplValue,1,length(CodeTemplateAttributesStartMagic))
=CodeTemplateAttributesStartMagic
then begin
Lines:=TStringList.Create;
Lines.Text:=sComplValue;
LastLineHasEnding:=(sComplValue<>'') and (sComplValue[length(sComplValue)] in [#10,#13]);
Lines.Delete(0);
while (Lines.Count>0) and (Lines[0]<>CodeTemplateAttributesEndMagic) do
begin begin
CurAttributes.Add(Lines[0]); // Start of attributes
Lines.Delete(0); StartI := Length(CodeTemplateAttributesStartMagic) + 1;
end; while (StartI <= Length(sComplValue)) and (sComplValue[StartI] in [#10,#13]) do
if Lines.Count>0 then Inc(StartI);
Lines.Delete(0); EndI := Pos(CodeTemplateAttributesEndMagic, sComplValue, StartI);
sComplValue:=Lines.Text; if EndI = 0 then
if not LastLineHasEnding then begin raise Exception.Create('TCustomSynAutoComplete.ParseCompletionList: "'
l:=length(sComplValue); + CodeTemplateAttributesEndMagic + '" not found.');
if (l>0) and (sComplValue[l] in [#10,#13]) then begin CurAttributes.Text := Copy(sComplValue, StartI, EndI-StartI);
dec(l); // Start of value
if (l>0) and (sComplValue[l] in [#10,#13]) StartI := EndI + Length(CodeTemplateAttributesEndMagic);
and (sComplValue[l]<>sComplValue[l+1]) then while (StartI <= Length(sComplValue)) and (sComplValue[StartI] in [#10,#13]) do
dec(l); Inc(StartI);
sComplValue:=copy(sComplValue,1,l); sComplValue := Copy(sComplValue, StartI, Length(sComplValue));
end;
end;
Lines.Free;
end; end;
fCompletionValues.Add(sComplValue); fCompletionValues.Add(sComplValue);
sComplValue := ''; sComplValue := '';
fAttributes.Add(CurAttributes); fAttributes.Add(CurAttributes);
end; end;
var
BorlandDCI: boolean;
i, j, Len: integer;
S: string;
TemplateStarted: Boolean;
begin begin
fCompletions.Clear; fCompletions.Clear;
fCompletionComments.Clear; fCompletionComments.Clear;
@ -480,62 +452,60 @@ begin
ClearAttributes; ClearAttributes;
if fAutoCompleteList.Count > 0 then begin if fAutoCompleteList.Count > 0 then begin
s := fAutoCompleteList[0]; S := fAutoCompleteList[0];
BorlandDCI := (s <> '') and (s[1] = '['); DebugLn(['TCustomSynAutoComplete.ParseCompletionList: ', S]);
BorlandDCI := (S <> '') and (S[1] = '[');
sCompl := ''; Assert((sComplKey='') and (sComment='') and (sComplValue=''), 'ParseCompletionList: strings not empty.');
sComment := '';
sComplValue := '';
TemplateStarted:=false; TemplateStarted:=false;
for i := 0 to fAutoCompleteList.Count - 1 do begin for i := 0 to fAutoCompleteList.Count - 1 do begin
s := fAutoCompleteList[i]; S := fAutoCompleteList[i];
Len := Length(s); Len := Length(S);
if BorlandDCI then begin if BorlandDCI then begin
// the style of the Delphi32.dci file // the style of the Delphi32.dci file
if (Len > 0) and (s[1] = '[') then begin if (Len > 0) and (S[1] = '[') then begin
// save last entry // save last entry
if sCompl <> '' then if sComplKey <> '' then
SaveEntry; SaveEntry;
// new completion entry // new completion entry
j := 2; j := 2;
while (j <= Len) and (s[j] > ' ') do while (j <= Len) and (S[j] > ' ') do
Inc(j); Inc(j);
sCompl := Copy(s, 2, j - 2); sComplKey := Copy(S, 2, j - 2);
// start of comment in DCI file // start of comment in DCI file
while (j <= Len) and (s[j] <= ' ') do while (j <= Len) and (S[j] <= ' ') do
Inc(j); Inc(j);
if (j <= Len) and (s[j] = '|') then if (j <= Len) and (S[j] = '|') then
Inc(j); Inc(j);
while (j <= Len) and (s[j] <= ' ') do while (j <= Len) and (S[j] <= ' ') do
Inc(j); Inc(j);
sComment := Copy(s, j, Len); sComment := Copy(S, j, Len);
if sComment[Length(sComment)] = ']' then if sComment[Length(sComment)] = ']' then
SetLength(sComment, Length(sComment) - 1); SetLength(sComment, Length(sComment) - 1);
TemplateStarted:=true; TemplateStarted:=true;
end else begin end else begin
if not TemplateStarted then if not TemplateStarted then
sComplValue := sComplValue + #13#10; sComplValue := sComplValue + LineEnding;
TemplateStarted:=false; TemplateStarted:=false;
sComplValue := sComplValue + s; sComplValue := sComplValue + S;
end; end;
end else begin end else begin
// the original style // the original style
if (Len > 0) and (s[1] <> '=') then begin if (Len > 0) and (S[1] <> '=') then begin
// save last entry // save last entry
if sCompl <> '' then if sComplKey <> '' then
SaveEntry; SaveEntry;
// new completion entry // new completion entry
sCompl := s; sComplKey := S;
TemplateStarted:=true; TemplateStarted:=true;
end else if (Len > 0) and (s[1] = '=') then begin end else if (Len > 0) and (S[1] = '=') then begin
if not TemplateStarted then if not TemplateStarted then
sComplValue := sComplValue + #13#10; sComplValue := sComplValue + LineEnding;
TemplateStarted:=false; TemplateStarted:=false;
sComplValue := sComplValue + Copy(s, 2, Len); sComplValue := sComplValue + Copy(S, 2, Len);
end; end;
end; end;
end; end;
if sCompl <> '' then //mg 2000-11-07 if sComplKey <> '' then
SaveEntry; SaveEntry;
end; end;
fParsed:=true; fParsed:=true;