mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-10 11:56:09 +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,
|
cafSemicolon, cafEqual, cafColon, cafComma, cafPoint,
|
||||||
cafRoundBracketOpen, cafRoundBracketClose,
|
cafRoundBracketOpen, cafRoundBracketClose,
|
||||||
cafEdgedBracketOpen, cafEdgedBracketClose,
|
cafEdgedBracketOpen, cafEdgedBracketClose,
|
||||||
|
cafAssignment,
|
||||||
cafWord, cafEnd,
|
cafWord, cafEnd,
|
||||||
cafOtherOperator // = other operator
|
cafOtherOperator // = other operator
|
||||||
);
|
);
|
||||||
@ -59,6 +60,7 @@ const
|
|||||||
'Semicolon', 'Equal', 'Colon', 'Comma', 'Point',
|
'Semicolon', 'Equal', 'Colon', 'Comma', 'Point',
|
||||||
'RoundBracketOpen', 'RoundBracketClose',
|
'RoundBracketOpen', 'RoundBracketClose',
|
||||||
'EdgedBracketOpen', 'EdgedBracketClose',
|
'EdgedBracketOpen', 'EdgedBracketClose',
|
||||||
|
'Assignment',
|
||||||
'Word', 'End', 'Operator'
|
'Word', 'End', 'Operator'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9256,14 +9256,13 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TryFirstLocalIdentOccurence(CursorNode: TCodeTreeNode;
|
function TryFirstLocalIdentOccurence(CursorNode: TCodeTreeNode;
|
||||||
OrigCleanCursorPos, CleanCursorPos: Integer): boolean;
|
CleanCursorPos: Integer): boolean;
|
||||||
var
|
var
|
||||||
AtomContextNode, StatementNode: TCodeTreeNode;
|
AtomContextNode, StatementNode: TCodeTreeNode;
|
||||||
IdentAtom, LastCurPos: TAtomPosition;
|
IdentAtom, LastCurPos: TAtomPosition;
|
||||||
UpIdentifier: string;
|
UpIdentifier: string;
|
||||||
LastAtomIsDot: Boolean;
|
LastAtomIsDot: Boolean;
|
||||||
Params: TFindDeclarationParams;
|
Params: TFindDeclarationParams;
|
||||||
OldCodePos: TCodePosition;
|
|
||||||
begin
|
begin
|
||||||
Result := false;
|
Result := false;
|
||||||
|
|
||||||
@ -9313,10 +9312,7 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
|||||||
begin
|
begin
|
||||||
FCompletingCursorNode:=CursorNode;
|
FCompletingCursorNode:=CursorNode;
|
||||||
try
|
try
|
||||||
if not CleanPosToCodePos(OrigCleanCursorPos,OldCodePos) then
|
|
||||||
RaiseException('TCodeCompletionCodeTool.TryFirstLocalIdentOccurence CleanPosToCodePos');
|
|
||||||
CompleteCode:=TryCompleteLocalVar(LastCurPos.StartPos,AtomContextNode);
|
CompleteCode:=TryCompleteLocalVar(LastCurPos.StartPos,AtomContextNode);
|
||||||
AdjustCursor(OldCodePos,OldTopLine,NewPos,NewTopLine);
|
|
||||||
exit(true);
|
exit(true);
|
||||||
finally
|
finally
|
||||||
FCompletingCursorNode:=nil;
|
FCompletingCursorNode:=nil;
|
||||||
@ -9331,9 +9327,58 @@ function TCodeCompletionCodeTool.CompleteCode(CursorPos: TCodeXYPosition;
|
|||||||
end;
|
end;
|
||||||
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
|
var
|
||||||
CleanCursorPos, OrigCleanCursorPos: integer;
|
CleanCursorPos, OrigCleanCursorPos: integer;
|
||||||
CursorNode: TCodeTreeNode;
|
CursorNode: TCodeTreeNode;
|
||||||
|
OldCodePos: TCodePosition;
|
||||||
|
LastCodeToolsErrorCleanPos: Integer;
|
||||||
|
LastCodeToolsError: ECodeToolError;
|
||||||
begin
|
begin
|
||||||
//DebugLn(['TCodeCompletionCodeTool.CompleteCode CursorPos=',Dbgs(CursorPos),' OldTopLine=',OldTopLine]);
|
//DebugLn(['TCodeCompletionCodeTool.CompleteCode CursorPos=',Dbgs(CursorPos),' OldTopLine=',OldTopLine]);
|
||||||
|
|
||||||
@ -9364,18 +9409,46 @@ begin
|
|||||||
CodeCompleteSrcChgCache:=SourceChangeCache;
|
CodeCompleteSrcChgCache:=SourceChangeCache;
|
||||||
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
|
|
||||||
|
try
|
||||||
|
LastCodeToolsError := nil;
|
||||||
|
try
|
||||||
if TryComplete(CursorNode, CleanCursorPos) then
|
if TryComplete(CursorNode, CleanCursorPos) then
|
||||||
exit(true);
|
exit(true);
|
||||||
|
|
||||||
{ Find the first occurence of the (local) identifier at cursor in current
|
{ Find the first occurence of the (local) identifier at cursor in current
|
||||||
procedure body and try again. }
|
procedure body and try again. }
|
||||||
if TryFirstLocalIdentOccurence(CursorNode,OrigCleanCursorPos,CleanCursorPos) then
|
if TryFirstLocalIdentOccurence(CursorNode,CleanCursorPos) then
|
||||||
exit(true);
|
exit(true);
|
||||||
|
|
||||||
if CompleteMethodByBody(OrigCleanCursorPos,OldTopLine,CursorNode,
|
if CompleteMethodByBody(OrigCleanCursorPos,OldTopLine,CursorNode,
|
||||||
NewPos,NewTopLine,SourceChangeCache)
|
NewPos,NewTopLine,SourceChangeCache)
|
||||||
then
|
then
|
||||||
exit(true);
|
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}
|
{$IFDEF CTDEBUG}
|
||||||
DebugLn('TCodeCompletionCodeTool.CompleteCode nothing to complete ... ');
|
DebugLn('TCodeCompletionCodeTool.CompleteCode nothing to complete ... ');
|
||||||
|
@ -1290,6 +1290,7 @@ begin
|
|||||||
end else begin
|
end else begin
|
||||||
// :=
|
// :=
|
||||||
inc(CurPos.EndPos);
|
inc(CurPos.EndPos);
|
||||||
|
CurPos.Flag:=cafAssignment;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
'.':
|
'.':
|
||||||
@ -1740,6 +1741,11 @@ begin
|
|||||||
if CurPos.StartPos>1 then begin
|
if CurPos.StartPos>1 then begin
|
||||||
c1:=Src[CurPos.StartPos-1];
|
c1:=Src[CurPos.StartPos-1];
|
||||||
// test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><
|
// test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><
|
||||||
|
if ((c2='=') and (c1=':')) then
|
||||||
|
begin
|
||||||
|
dec(CurPos.StartPos);
|
||||||
|
CurPos.Flag:=cafAssignment;
|
||||||
|
end else
|
||||||
if ((c2='=') and (IsEqualOperatorStartChar[c1]))
|
if ((c2='=') and (IsEqualOperatorStartChar[c1]))
|
||||||
or ((c1='<') and (c2='>'))
|
or ((c1='<') and (c2='>'))
|
||||||
or ((c1='>') and (c2='<'))
|
or ((c1='>') and (c2='<'))
|
||||||
|
Loading…
Reference in New Issue
Block a user