Codetools: Identifier completion, improve/fix limit for recent history items shown. issue #40332

- take into account that some items in history may not be in the current unfiltered items, and that "HistoryIndex" may have gaps
This commit is contained in:
Martin 2023-07-17 19:54:43 +02:00
parent e7c438c50b
commit 9146a986b4
2 changed files with 121 additions and 38 deletions

View File

@ -1095,8 +1095,8 @@ begin
{$ENDIF}
FreeAndNil(DefaultLFMTrees);
FreeAndNil(Positions);
FreeAndNil(IdentifierHistory);
FreeAndNil(IdentifierList);
FreeAndNil(IdentifierHistory);
FPascalTools.FreeAndClear;
FreeAndNil(FPascalTools);
FDirectivesTools.FreeAndClear;

View File

@ -226,6 +226,11 @@ type
TIdentComplSortMethod = (icsScopedAlphabetic, icsAlphabetic, icsScopedDeclaration);
const
IdentComplSortMethodUsingCompatibility = [icsScopedAlphabetic, icsScopedDeclaration];
type
TOnGatherUserIdentifiersToFilteredList = procedure(Sender: TIdentifierList;
FilteredList: TFPList; PriorityCount: Integer) of object;
@ -248,6 +253,7 @@ type
FFilteredList: TFPList; // list of TIdentifierListItem
FFlags: TIdentifierListFlags;
FHistory: TIdentifierHistoryList;
FFoundHistoryItems: array of TIdentifierListItem; // Items that have a HistoryIndex / list may have gaps
FItems: TAvlTree; // tree of TIdentifierListItem (completely sorted)
FIdentView: TAVLTree; // tree of TIdentifierListItem sorted for identifiers
FUsedTools: TAVLTree; // tree of TFindDeclarationTool
@ -590,7 +596,7 @@ var
Item2: TIdentifierListItem absolute Data2;
begin
if SortMethodForCompletion in [icsScopedAlphabetic, icsScopedDeclaration] then begin
if SortMethodForCompletion in IdentComplSortMethodUsingCompatibility then begin
// first sort for Compatibility (lower is better)
if ord(Item1.Compatibility)<ord(Item2.Compatibility) then begin
Result:=-1;
@ -601,25 +607,6 @@ begin
end;
end;
if SortForHistory then begin
// then sort for History (lower is better)
if Item1.HistoryIndex<Item2.HistoryIndex then begin
if Item1.HistoryIndex <SortForHistoryLimit then
begin
Result:=-1;
exit;
end;
end else
if Item1.HistoryIndex>Item2.HistoryIndex then
begin
if Item2.HistoryIndex <SortForHistoryLimit then
begin
Result:=1;
exit;
end;
end;
end;
if SortMethodForCompletion in [icsScopedAlphabetic, icsScopedDeclaration] then begin
// then sort for Level (i.e. scope, lower is better)
if Item1.Level<Item2.Level then begin
@ -680,9 +667,56 @@ end;
procedure TIdentifierList.UpdateFilteredList;
var
AnAVLNode: TAvlTreeNode;
CurItem: TIdentifierListItem;
cPriorityCount: Integer;
CurItem, CurItem2: TIdentifierListItem;
cPriorityCount, TotalHistLimit, j: Integer;
i: PtrInt;
HistoryLimits: array [TIdentifierCompatibility] of integer;
HasCompSort: Boolean;
HistComp, CurItmComp: TIdentifierCompatibility;
procedure InsertCurItem; inline;
begin
if (length(Prefix)=length(CurItem.Identifier))
and (not (iliAtCursor in CurItem.Flags)) then
// put exact matches at the beginning
FFilteredList.Insert(0,CurItem)
else
FFilteredList.Insert(cPriorityCount, CurItem);
Inc(cPriorityCount);
end;
function FilterCurItem: Integer; inline;
begin
if FContainsFilter then
Result:=IdentifierPos(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier)))
else if ComparePrefixIdent(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier))) then
Result:=0
else
Result:=-1;
end;
procedure AddHistoryCurItem(ForceComp: Boolean);
var
CurItmComp: TIdentifierCompatibility;
j: integer;
begin
for j := 0 to length(FFoundHistoryItems) - 1 do begin
CurItem := FFoundHistoryItems[j];
if (CurItem = nil) then
continue;
if ForceComp then
CurItmComp := low(TIdentifierCompatibility)
else
CurItmComp := CurItem.Compatibility;
if (CurItmComp <> HistComp) then
Continue;
if (CurItem.HistoryIndex > HistoryLimits[CurItmComp]) then
break;
if (CurItem.Identifier<>'') and (FilterCurItem >= 0) then
InsertCurItem;
end;
end;
begin
if not (ilfFilteredListNeedsUpdate in FFlags) then exit;
if FFilteredList=nil then FFilteredList:=TFPList.Create;
@ -691,39 +725,79 @@ begin
{$IFDEF CTDEBUG}
DebugLn(['TIdentifierList.UpdateFilteredList Prefix="',Prefix,'"']);
{$ENDIF}
AnAVLNode:=FItems.FindLowest;
// Update HistoryLimits
TotalHistLimit := 0;
HasCompSort := SortMethodForCompletion in IdentComplSortMethodUsingCompatibility;
if FSortForHistory then
TotalHistLimit := FSortForHistoryLimit;
for HistComp in TIdentifierCompatibility do begin
HistoryLimits[HistComp] := -1;
end;
for HistComp in TIdentifierCompatibility do begin
for j := 0 to length(FFoundHistoryItems) - 1 do begin
if TotalHistLimit <= 0 then
break;
if (FFoundHistoryItems[j] <> nil) and
( (FFoundHistoryItems[j].Compatibility = HistComp) or (not HasCompSort) ) and
(FFoundHistoryItems[j].Identifier <> '')
then begin
HistoryLimits[HistComp] := FFoundHistoryItems[j].HistoryIndex;
dec(TotalHistLimit);
end;
end;
if not HasCompSort then
break;
end;
cPriorityCount := 0;
HistComp := Low(TIdentifierCompatibility);
AddHistoryCurItem(not HasCompSort);
AnAVLNode:=FItems.FindLowest;
while AnAVLNode<>nil do begin
CurItem:=TIdentifierListItem(AnAVLNode.Data);
CurItem2:=TIdentifierListItem(AnAVLNode.Data);
// history for each compatibility
if HasCompSort then begin
while HistComp < CurItem2.Compatibility do begin
inc(HistComp);
AddHistoryCurItem(False);
end;
end;
CurItem := CurItem2;
if CurItem.Identifier<>'' then
begin
if FContainsFilter then
i:=IdentifierPos(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier)))
else if ComparePrefixIdent(PChar(Pointer(Prefix)),PChar(Pointer(CurItem.Identifier))) then
i:=0
i := FilterCurItem;
if HasCompSort then
CurItmComp := CurItem.Compatibility
else
i:=-1;
CurItmComp := low(TIdentifierCompatibility);
if i=0 then begin
{$IFDEF ShowFilteredIdents}
DebugLn(['::: FILTERED ITEM ',FFilteredList.Count,' ',CurItem.Identifier]);
{$ENDIF}
if (length(Prefix)=length(CurItem.Identifier))
and (not (iliAtCursor in CurItem.Flags)) then
// put exact matches at the beginning
FFilteredList.Insert(0,CurItem)
else
FFilteredList.Insert(cPriorityCount, CurItem);
Inc(cPriorityCount);
if CurItem.HistoryIndex > HistoryLimits[CurItmComp] then
InsertCurItem;
end
else if i>0 then begin
{$IFDEF ShowFilteredIdents}
DebugLn(['::: FILTERED ITEM ',FFilteredList.Count,' ',CurItem.Identifier]);
{$ENDIF}
FFilteredList.Add(CurItem);
if CurItem.HistoryIndex > HistoryLimits[CurItmComp] then
FFilteredList.Add(CurItem);
end;
end;
AnAVLNode:=FItems.FindSuccessor(AnAVLNode);
end;
if HasCompSort then begin
while HistComp < high(TIdentifierCompatibility) do begin
inc(HistComp);
AddHistoryCurItem(False);
end;
end;
if Assigned(FOnGatherUserIdentifiersToFilteredList) then
FOnGatherUserIdentifiersToFilteredList(Self, FFilteredList, cPriorityCount);
{$IFDEF CTDEBUG}
@ -803,6 +877,9 @@ begin
FreeMem(p);
end;
FCreatedIdentifiers.Clear;
FFoundHistoryItems := nil;
if FHistory <> nil then
SetLength(FFoundHistoryItems, FHistory.Capacity);
FItems.FreeAndClear;
FIdentView.Clear;
if FUsedTools<>nil then
@ -826,6 +903,12 @@ begin
if AnAVLNode=nil then begin
if History<>nil then
NewItem.HistoryIndex:=History.GetHistoryIndex(NewItem);
if (NewItem.HistoryIndex >= 0) and
(NewItem.HistoryIndex < Length(FFoundHistoryItems))
then begin
assert(FFoundHistoryItems[NewItem.HistoryIndex]=nil, 'TIdentifierList.Add: FFoundHistoryItems[NewItem.HistoryIndex]=nil');
FFoundHistoryItems[NewItem.HistoryIndex] := NewItem;
end;
FItems.Add(NewItem);
FIdentView.Add(NewItem);
FFlags:=FFlags+[ilfFilteredListNeedsUpdate,ilfUsedToolsNeedsUpdate];