mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-31 12:16:12 +02:00
codetools: allow variable code completion when cursor is after assignment. Issue #29448
git-svn-id: trunk@51390 -
This commit is contained in:
parent
748caca7e3
commit
d6f267a40d
@ -47,6 +47,7 @@ type
|
||||
cafSemicolon, cafEqual, cafColon, cafComma, cafPoint,
|
||||
cafRoundBracketOpen, cafRoundBracketClose,
|
||||
cafEdgedBracketOpen, cafEdgedBracketClose,
|
||||
cafAssignment,
|
||||
cafWord, cafEnd,
|
||||
cafOtherOperator // = other operator
|
||||
);
|
||||
@ -59,6 +60,7 @@ const
|
||||
'Semicolon', 'Equal', 'Colon', 'Comma', 'Point',
|
||||
'RoundBracketOpen', 'RoundBracketClose',
|
||||
'EdgedBracketOpen', 'EdgedBracketClose',
|
||||
'Assignment',
|
||||
'Word', 'End', 'Operator'
|
||||
);
|
||||
|
||||
|
@ -9256,14 +9256,13 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
||||
end;
|
||||
|
||||
function TryFirstLocalIdentOccurence(CursorNode: TCodeTreeNode;
|
||||
OrigCleanCursorPos, CleanCursorPos: Integer): boolean;
|
||||
CleanCursorPos: Integer): boolean;
|
||||
var
|
||||
AtomContextNode, StatementNode: TCodeTreeNode;
|
||||
IdentAtom, LastCurPos: TAtomPosition;
|
||||
UpIdentifier: string;
|
||||
LastAtomIsDot: Boolean;
|
||||
Params: TFindDeclarationParams;
|
||||
OldCodePos: TCodePosition;
|
||||
begin
|
||||
Result := false;
|
||||
|
||||
@ -9313,10 +9312,7 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
||||
begin
|
||||
FCompletingCursorNode:=CursorNode;
|
||||
try
|
||||
if not CleanPosToCodePos(OrigCleanCursorPos,OldCodePos) then
|
||||
RaiseException('TCodeCompletionCodeTool.TryFirstLocalIdentOccurence CleanPosToCodePos');
|
||||
CompleteCode:=TryCompleteLocalVar(LastCurPos.StartPos,AtomContextNode);
|
||||
AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine);
|
||||
exit(true);
|
||||
finally
|
||||
FCompletingCursorNode:=nil;
|
||||
@ -9331,9 +9327,58 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure ClearAndRaise(var E: ECodeToolError; CleanPos: Integer);
|
||||
var
|
||||
TempE: ECodeToolError;
|
||||
begin
|
||||
TempE := E;
|
||||
E := nil;
|
||||
MoveCursorToCleanPos(CleanPos);
|
||||
RaiseExceptionInstance(TempE);
|
||||
end;
|
||||
|
||||
function TryAssignment(CleanCursorPos: Integer; CursorNode: TCodeTreeNode;
|
||||
var LastCodeToolsError: ECodeToolError; LastCodeToolsErrorCleanPos: Integer): Boolean;
|
||||
begin
|
||||
// Search only within the current instruction - stop on semicolon or else
|
||||
// (else isn't prepended by a semicolon in contrast to other keywords).
|
||||
|
||||
Result := False;
|
||||
MoveCursorToCleanPos(CleanCursorPos);
|
||||
while CurPos.StartPos > 0 do
|
||||
begin
|
||||
ReadPriorAtom;
|
||||
case CurPos.Flag of
|
||||
cafAssignment:
|
||||
begin
|
||||
// OK FOUND!
|
||||
ReadPriorAtom;
|
||||
try
|
||||
if TryComplete(CursorNode, CurPos.StartPos) then
|
||||
exit(true);
|
||||
except
|
||||
if LastCodeToolsError<>nil then
|
||||
ClearAndRaise(LastCodeToolsError, LastCodeToolsErrorCleanPos) // in case of error, raise the last one
|
||||
else
|
||||
raise;
|
||||
end;
|
||||
break;
|
||||
end;
|
||||
cafWord:
|
||||
if UpAtomIs('ELSE') then // stop on else
|
||||
break;
|
||||
cafSemicolon:
|
||||
break; // stop on semicolon
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
CleanCursorPos, OrigCleanCursorPos: integer;
|
||||
CursorNode: TCodeTreeNode;
|
||||
OldCodePos: TCodePosition;
|
||||
LastCodeToolsErrorCleanPos: Integer;
|
||||
LastCodeToolsError: ECodeToolError;
|
||||
begin
|
||||
//DebugLn(['TCodeCompletionCodeTool.CompleteCode CursorPos=',Dbgs(CursorPos),' OldTopLine=',OldTopLine]);
|
||||
|
||||
@ -9364,18 +9409,46 @@ begin
|
||||
CodeCompleteSrcChgCache:=SourceChangeCache;
|
||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||
|
||||
if TryComplete(CursorNode, CleanCursorPos) then
|
||||
exit(true);
|
||||
try
|
||||
LastCodeToolsError := nil;
|
||||
try
|
||||
if TryComplete(CursorNode, CleanCursorPos) then
|
||||
exit(true);
|
||||
|
||||
{ Find the first occurence of the (local) identifier at cursor in current
|
||||
procedure body and try again. }
|
||||
if TryFirstLocalIdentOccurence(CursorNode,OrigCleanCursorPos,CleanCursorPos) then
|
||||
exit(true);
|
||||
{ Find the first occurence of the (local) identifier at cursor in current
|
||||
procedure body and try again. }
|
||||
if TryFirstLocalIdentOccurence(CursorNode,CleanCursorPos) then
|
||||
exit(true);
|
||||
|
||||
if CompleteMethodByBody(OrigCleanCursorPos,OldTopLine,CursorNode,
|
||||
NewPos,NewTopLine,SourceChangeCache)
|
||||
then
|
||||
exit(true);
|
||||
if CompleteMethodByBody(OrigCleanCursorPos,OldTopLine,CursorNode,
|
||||
NewPos,NewTopLine,SourceChangeCache)
|
||||
then
|
||||
exit(true);
|
||||
except
|
||||
on E: ECodeToolError do
|
||||
begin
|
||||
// we have a codetool error, let's try to find the assignment in any case
|
||||
LastCodeToolsErrorCleanPos := CurPos.StartPos;
|
||||
LastCodeToolsError := ECodeToolError.Create(E.Sender, E.Message);
|
||||
end else
|
||||
raise;
|
||||
end;
|
||||
|
||||
// find first assignment before current.
|
||||
if TryAssignment(CleanCursorPos, CursorNode, LastCodeToolsError, LastCodeToolsErrorCleanPos) then
|
||||
Exit(true);
|
||||
|
||||
if LastCodeToolsError<>nil then // no assignment found, reraise
|
||||
ClearAndRaise(LastCodeToolsError, LastCodeToolsErrorCleanPos);
|
||||
finally
|
||||
LastCodeToolsError.Free;
|
||||
if Result then
|
||||
begin
|
||||
if not CleanPosToCodePos(OrigCleanCursorPos,OldCodePos) then
|
||||
RaiseException('TCodeCompletionCodeTool.CompleteCode CleanPosToCodePos');
|
||||
AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine);
|
||||
end;
|
||||
end;
|
||||
|
||||
{$IFDEF CTDEBUG}
|
||||
DebugLn('TCodeCompletionCodeTool.CompleteCode nothing to complete ... ');
|
||||
|
@ -1290,6 +1290,7 @@ begin
|
||||
end else begin
|
||||
// :=
|
||||
inc(CurPos.EndPos);
|
||||
CurPos.Flag:=cafAssignment;
|
||||
end;
|
||||
end;
|
||||
'.':
|
||||
@ -1740,6 +1741,11 @@ begin
|
||||
if CurPos.StartPos>1 then begin
|
||||
c1:=Src[CurPos.StartPos-1];
|
||||
// test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><
|
||||
if ((c2='=') and (c1=':')) then
|
||||
begin
|
||||
dec(CurPos.StartPos);
|
||||
CurPos.Flag:=cafAssignment;
|
||||
end else
|
||||
if ((c2='=') and (IsEqualOperatorStartChar[c1]))
|
||||
or ((c1='<') and (c2='>'))
|
||||
or ((c1='>') and (c2='<'))
|
||||
|
Loading…
Reference in New Issue
Block a user