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 -
This commit is contained in:
ondrej 2018-06-18 13:16:58 +00:00
parent 0db8c632c5
commit 2a34ee3ad9
3 changed files with 168 additions and 83 deletions

View File

@ -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

View File

@ -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

View File

@ -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;