From 2a34ee3ad9b2a6e024ff3701b466645f31c6d7f5 Mon Sep 17 00:00:00 2001 From: ondrej Date: Mon, 18 Jun 2018 13:16:58 +0000 Subject: [PATCH] IDE: identifier completion: - handle "Include words" option - don't scan a unit several times if it is open in several source editor windows git-svn-id: trunk@58308 - --- ide/main.pp | 7 +- ide/sourceeditor.pp | 147 +++++++++++++++++++++++++++++++----------- ide/wordcompletion.pp | 97 +++++++++++++++------------- 3 files changed, 168 insertions(+), 83 deletions(-) diff --git a/ide/main.pp b/ide/main.pp index b136d73355..361b6259d3 100644 --- a/ide/main.pp +++ b/ide/main.pp @@ -655,6 +655,7 @@ type OldCompilerFilename, OldLanguage: String; OIChangedTimer: TIdleTimer; + FIdentifierWordCompletion: TSourceEditorWordCompletion; FIdentifierWordCompletionWordList: TStringList; FIdentifierWordCompletionEnabled: Boolean; @@ -1676,6 +1677,7 @@ begin FreeThenNil(ObjectInspector1); FreeThenNil(SourceEditorManagerIntf); FreeAndNil(FIdentifierWordCompletionWordList); + FreeAndNil(FIdentifierWordCompletion); // disconnect handlers Application.RemoveAllHandlersOfObject(Self); @@ -6482,10 +6484,13 @@ begin FIdentifierWordCompletionWordList.OwnsObjects := True; end else FIdentifierWordCompletionWordList.Clear; + if FIdentifierWordCompletion=nil then + FIdentifierWordCompletion := TSourceEditorWordCompletion.Create; OldPriorityCount := PriorityCount; PriorityCount := FilteredList.Count; - AWordCompletion.GetWordList(FIdentifierWordCompletionWordList, Sender.Prefix, Sender.ContainsFilter, False, 100); + FIdentifierWordCompletion.IncludeWords := CodeToolsOpts.IdentComplIncludeWords; + FIdentifierWordCompletion.GetWordList(FIdentifierWordCompletionWordList, Sender.Prefix, Sender.ContainsFilter, False, 100); FilteredList.Capacity := FilteredList.Count+FIdentifierWordCompletionWordList.Count; for I := 0 to FIdentifierWordCompletionWordList.Count-1 do begin diff --git a/ide/sourceeditor.pp b/ide/sourceeditor.pp index c1278ae017..8cc43a4318 100644 --- a/ide/sourceeditor.pp +++ b/ide/sourceeditor.pp @@ -44,7 +44,7 @@ uses {$ENDIF} SynEditMouseCmds, // RTL + FCL - Classes, SysUtils, StrUtils, types, Math, RegExpr, Laz_AVL_Tree, + Classes, SysUtils, StrUtils, Types, Contnrs, Math, RegExpr, Laz_AVL_Tree, // LCL Controls, Forms, ComCtrls, StdCtrls, Graphics, Dialogs, Extctrls, Menus, LCLProc, LCLType, LCLIntf, ClipBrd, HelpIntfs, Messages, LMessages, @@ -1192,9 +1192,6 @@ type Index: integer); protected procedure CodeToolsToSrcEditTimerTimer(Sender: TObject); - procedure OnWordCompletionGetSource(var Source: TStrings; - var {%H-}SourceTopLine,{%H-}SourceBottomLine: integer; - var IgnoreWordPos: TPoint; SourceIndex: integer); procedure OnSourceCompletionTimer(Sender: TObject); // marks procedure OnSourceMarksAction(AMark: TSourceMark; {%H-}AAction: TMarksAction); @@ -1306,6 +1303,26 @@ type read FOnPackageForSourceEditor write FOnPackageForSourceEditor; end; + TSourceEditorWordCompletion = class(TWordCompletion) + private type + TSourceListItem = class + Source: TStrings; + IgnoreWordPos: TPoint; + end; + private + FIncludeWords: TIdentComplIncludeWords; + FSourceList: TObjectList; + procedure ReloadSourceList; + protected + procedure DoGetSource(var Source: TStrings; var {%H-}TopLine, + {%H-}BottomLine: Integer; var IgnoreWordPos: TPoint; SourceIndex: integer); override; + public + constructor Create; + destructor Destroy; override; + public + property IncludeWords: TIdentComplIncludeWords read FIncludeWords write FIncludeWords; + end; + function SourceEditorManager: TSourceEditorManager; inline; @@ -1405,14 +1422,14 @@ var EnglishModifiedLGPLNotice: string; EnglishMITNotice: string; -var - AWordCompletion: TWordCompletion = nil; - implementation {$R *.lfm} {$R ../images/bookmark.res} +var + AWordCompletion: TWordCompletion = nil; + var SRCED_LOCK, SRCED_OPEN, SRCED_CLOSE, SRCED_PAGES: PLazLoggerLogGroup; @@ -1774,6 +1791,89 @@ begin Result:=CompareFilenames(AnsiString(FileNameStr),SE1.FileName); end; +{ TSourceEditorWordCompletion } + +constructor TSourceEditorWordCompletion.Create; +begin + inherited Create; + + FSourceList := TObjectList.Create; + FIncludeWords := icwIncludeFromAllUnits; +end; + +destructor TSourceEditorWordCompletion.Destroy; +begin + FSourceList.Free; + + inherited Destroy; +end; + +procedure TSourceEditorWordCompletion.DoGetSource(var Source: TStrings; + var TopLine, BottomLine: Integer; var IgnoreWordPos: TPoint; + SourceIndex: integer); +var + SourceItem: TSourceListItem; +begin + if SourceIndex=0 then + ReloadSourceList; + + if SourceIndex>=FSourceList.Count then + Exit; + + SourceItem := FSourceList[SourceIndex] as TSourceListItem; + Source := SourceItem.Source; + IgnoreWordPos := SourceItem.IgnoreWordPos; +end; + +procedure TSourceEditorWordCompletion.ReloadSourceList; +var + CurEditor, TempEditor: TSourceEditor; + I: integer; + Mng: TSourceEditorManager; + New: TSourceListItem; + AddedFileNames: TStringList; +begin + FSourceList.Clear; + if FIncludeWords=icwDontInclude then + Exit; + + Mng := SourceEditorManager; + CurEditor:=Mng.GetActiveSE; + if (CurEditor<>nil) then + begin + New := TSourceListItem.Create; + New.Source:=CurEditor.EditorComponent.Lines; + New.IgnoreWordPos:=CurEditor.EditorComponent.LogicalCaretXY; + Dec(New.IgnoreWordPos.Y); // LogicalCaretXY starts with 1 as top line + FSourceList.Add(New); + end; + + if FIncludeWords=icwIncludeFromAllUnits then + begin + AddedFileNames := TStringList.Create; + try + AddedFileNames.Sorted := True; + AddedFileNames.Duplicates := dupIgnore; + for I := 0 to Mng.SourceEditorCount-1 do + begin + TempEditor := Mng.SourceEditors[I]; + if ( TempEditor<>CurEditor) + and (TempEditor.FileName<>CurEditor.FileName) + and (AddedFileNames.IndexOf(TempEditor.FileName)=-1) then + begin + New := TSourceListItem.Create; + New.Source:=TempEditor.EditorComponent.Lines; + New.IgnoreWordPos:=Point(-1,-1); + FSourceList.Add(New); + AddedFileNames.Add(TempEditor.FileName); + end; + end; + finally + AddedFileNames.Free; + end; + end; +end; + { TBrowseEditorTabHistoryDialog } procedure TBrowseEditorTabHistoryDialog.DoCreate; @@ -10802,32 +10902,6 @@ begin end; end; -procedure TSourceEditorManager.OnWordCompletionGetSource(var Source: TStrings; - var SourceTopLine, SourceBottomLine: integer; var IgnoreWordPos: TPoint; - SourceIndex: integer); -var - TempEditor: TSourceEditor; - i:integer; -begin - TempEditor:=GetActiveSE; - if (SourceIndex=0) and (TempEditor<>nil) then begin - Source:=TempEditor.EditorComponent.Lines; - IgnoreWordPos:=TempEditor.EditorComponent.LogicalCaretXY; - Dec(IgnoreWordPos.Y); // LogicalCaretXY starts with 1 as top line - end else begin - i:=0; - while (i < SourceEditorCount) do begin - if SourceEditors[i] <> TempEditor then dec(SourceIndex); - if SourceIndex <= 0 then begin - Source := SourceEditors[i].EditorComponent.Lines; - exit; - end; - inc(i); - end; - Source := nil; - end; -end; - procedure TSourceEditorManager.OnSourceCompletionTimer(Sender: TObject); function CheckStartIdentCompletion: boolean; @@ -10955,11 +11029,8 @@ begin // word completion if aWordCompletion=nil then begin - aWordCompletion:=TWordCompletion.Create; - with AWordCompletion do begin - WordBufferCapacity:=100; - OnGetSource:=@OnWordCompletionGetSource; - end; + AWordCompletion:=TSourceEditorWordCompletion.Create; + AWordCompletion.WordBufferCapacity:=100; end; // timer for auto start identifier completion diff --git a/ide/wordcompletion.pp b/ide/wordcompletion.pp index a5b9f26aac..ac8589855b 100644 --- a/ide/wordcompletion.pp +++ b/ide/wordcompletion.pp @@ -34,6 +34,9 @@ type procedure SetWordBufferCapacity(NewCapacity: integer); function CaseInsensitiveIndexOf(const AWord: string):integer; function CaseSensitiveIndexOf(const AWord: string):integer; + protected + procedure DoGetSource(var Source:TStrings; var TopLine, BottomLine: Integer; + var IgnoreWordPos: TPoint; SourceIndex:integer); virtual; public constructor Create; destructor Destroy; override; @@ -104,7 +107,7 @@ procedure TWordCompletion.GetWordList(AWordList: TStrings; MaxResults: integer); var i, Line, x, FilterLen, MaxHash, LineLen: integer; UpFilter, LineText, UpLineText, UpWordBuffer: string; - SourceText: TStringList; + SourceText: TStrings; HashList: ^integer;// index list. Every entry points to a word in the AWordList SourceTextIndex, SourceTopLine, SourceBottomLine:integer; LastCharType:TCharType; @@ -188,53 +191,52 @@ begin if AWordList.Count>=MaxResults then exit; // then search in all sources for more words that could fit SourceTextIndex:=0; - if Assigned(FOnGetSource) then begin + + SourceText:=nil; + SourceTopLine:=0; + SourceBottomLine:=-1; + IgnoreWordPos:=Point(-1,-1); + DoGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex); + UpLineText:=''; + repeat + if SourceText<>nil then begin + Line:=SourceTopLine; + if SourceBottomLine<0 then + SourceBottomLine := SourceText.Count-1; + while (Line<=SourceBottomLine) do begin + LineText:=SourceText[line]; + LineLen:=length(LineText); + if not CaseSensitive then + UpLineText:=uppercase(LineText); + x:=1; + LastCharType:=ctNone; + while (x<=LineLen) do begin + if (LastCharType=ctNone) and (CharTable[LineText[x]]=ctWordBegin) + then begin + // word found + i:=x; + repeat + inc(i); + until (i>LineLen) or (CharTable[LineText[i]]=ctNone); + if (i-x>=FilterLen) and not ((Line=IgnoreWordPos.Y) and (x<=IgnoreWordPos.X) and (IgnoreWordPos.X<=i)) then begin + AddIfMatch(LineText,UpLineText,x,i-x); + if AWordList.Count>=MaxResults then exit; + end; + x:=i; + end else + inc(x); + LastCharType:=CharTable[LineText[x-1]]; + end; + inc(line); + end; + end; + inc(SourceTextIndex); SourceText:=nil; SourceTopLine:=0; SourceBottomLine:=-1; IgnoreWordPos:=Point(-1,-1); - FOnGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex); - UpLineText:=''; - repeat - if SourceText<>nil then begin - Line:=SourceTopLine; - if SourceBottomLine<0 then - SourceBottomLine := SourceText.Count-1; - while (Line<=SourceBottomLine) do begin - LineText:=SourceText[line]; - LineLen:=length(LineText); - if not CaseSensitive then - UpLineText:=uppercase(LineText); - x:=1; - LastCharType:=ctNone; - while (x<=LineLen) do begin - if (LastCharType=ctNone) and (CharTable[LineText[x]]=ctWordBegin) - then begin - // word found - i:=x; - repeat - inc(i); - until (i>LineLen) or (CharTable[LineText[i]]=ctNone); - if (i-x>=FilterLen) and not ((Line=IgnoreWordPos.Y) and (x<=IgnoreWordPos.X) and (IgnoreWordPos.X<=i)) then begin - AddIfMatch(LineText,UpLineText,x,i-x); - if AWordList.Count>=MaxResults then exit; - end; - x:=i; - end else - inc(x); - LastCharType:=CharTable[LineText[x-1]]; - end; - inc(line); - end; - end; - inc(SourceTextIndex); - SourceText:=nil; - SourceTopLine:=0; - SourceBottomLine:=-1; - IgnoreWordPos:=Point(-1,-1); - FOnGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex); - until SourceText=nil; - end; + DoGetSource(SourceText,SourceTopLine,SourceBottomLine,IgnoreWordPos,SourceTextIndex); + until SourceText=nil; finally FreeMem(HashList); end; @@ -298,6 +300,13 @@ begin inherited Destroy; end; +procedure TWordCompletion.DoGetSource(var Source: TStrings; var TopLine, + BottomLine: Integer; var IgnoreWordPos: TPoint; SourceIndex: integer); +begin + if Assigned(FOnGetSource) then + FOnGetSource(Source,TopLine,BottomLine,IgnoreWordPos,SourceIndex); +end; + function TWordCompletion.GetWordBufferCapacity:integer; begin Result:=FWordBufferCapacity;