mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-09 05:37:08 +02:00
codetools: code completion for string iterators
git-svn-id: trunk@22412 -
This commit is contained in:
parent
87b819f60f
commit
a0bc0d475c
@ -319,7 +319,8 @@ type
|
|||||||
ContextLearn: boolean = true // true = learn policies from Source
|
ContextLearn: boolean = true // true = learn policies from Source
|
||||||
): boolean;
|
): boolean;
|
||||||
function GetIndents(const Source: string; Positions: TFABPositionIndents;
|
function GetIndents(const Source: string; Positions: TFABPositionIndents;
|
||||||
NewNestedComments: boolean; UseLineStart: boolean
|
NewNestedComments: boolean; UseLineStart: boolean;
|
||||||
|
ContextLearn: boolean = true // true = learn policies from Source
|
||||||
): boolean;
|
): boolean;
|
||||||
procedure GetDefaultSrcIndent(const Source: string; CleanPos: integer;
|
procedure GetDefaultSrcIndent(const Source: string; CleanPos: integer;
|
||||||
NewNestedComments: boolean;
|
NewNestedComments: boolean;
|
||||||
@ -1528,7 +1529,7 @@ end;
|
|||||||
|
|
||||||
function TFullyAutomaticBeautifier.GetIndents(const Source: string;
|
function TFullyAutomaticBeautifier.GetIndents(const Source: string;
|
||||||
Positions: TFABPositionIndents; NewNestedComments: boolean;
|
Positions: TFABPositionIndents; NewNestedComments: boolean;
|
||||||
UseLineStart: boolean): boolean;
|
UseLineStart: boolean; ContextLearn: boolean): boolean;
|
||||||
var
|
var
|
||||||
Needed: LongInt;
|
Needed: LongInt;
|
||||||
|
|
||||||
@ -1583,9 +1584,11 @@ begin
|
|||||||
inc(Item^.CleanPos);
|
inc(Item^.CleanPos);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Policies:=TFABPolicies.Create;
|
Policies:=nil;
|
||||||
Stack:=TFABBlockStack.Create;
|
Stack:=TFABBlockStack.Create;
|
||||||
try
|
try
|
||||||
|
if ContextLearn then
|
||||||
|
Policies:=TFABPolicies.Create;
|
||||||
{$IFDEF ShowCodeBeautifierLearn}
|
{$IFDEF ShowCodeBeautifierLearn}
|
||||||
Policies.Code:=TCodeBuffer.Create;
|
Policies.Code:=TCodeBuffer.Create;
|
||||||
Policies.Code.Source:=Source;
|
Policies.Code.Source:=Source;
|
||||||
@ -1655,6 +1658,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if Policies<>nil then begin
|
||||||
// parse source behind
|
// parse source behind
|
||||||
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
|
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
|
||||||
{$IFDEF VerboseIndenter}
|
{$IFDEF VerboseIndenter}
|
||||||
@ -1665,8 +1669,10 @@ begin
|
|||||||
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
|
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
|
||||||
if CheckPolicies(Policies,Item) then exit(true);
|
if CheckPolicies(Policies,Item) then exit(true);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
finally
|
finally
|
||||||
Stack.Free;
|
Stack.Free;
|
||||||
|
if Policies<>nil then
|
||||||
FreeAndNil(Policies.Code);
|
FreeAndNil(Policies.Code);
|
||||||
Policies.Free;
|
Policies.Free;
|
||||||
end;
|
end;
|
||||||
|
@ -170,6 +170,8 @@ type
|
|||||||
SourceChangeCache: TSourceChangeCache);
|
SourceChangeCache: TSourceChangeCache);
|
||||||
function CheckLocalVarAssignmentSyntax(CleanCursorPos: integer;
|
function CheckLocalVarAssignmentSyntax(CleanCursorPos: integer;
|
||||||
out VarNameAtom,AssignmentOperator,TermAtom: TAtomPosition): boolean;
|
out VarNameAtom,AssignmentOperator,TermAtom: TAtomPosition): boolean;
|
||||||
|
function CheckLocalVarForInSyntax(CleanCursorPos: integer;
|
||||||
|
out VarNameAtom,TermAtom: TAtomPosition): boolean;
|
||||||
function AddLocalVariable(CleanCursorPos: integer; OldTopLine: integer;
|
function AddLocalVariable(CleanCursorPos: integer; OldTopLine: integer;
|
||||||
VariableName, VariableType, VariableTypeUnitName: string;
|
VariableName, VariableType, VariableTypeUnitName: string;
|
||||||
out NewPos: TCodeXYPosition; out NewTopLine: integer;
|
out NewPos: TCodeXYPosition; out NewTopLine: integer;
|
||||||
@ -186,6 +188,10 @@ type
|
|||||||
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||||
SourceChangeCache: TSourceChangeCache): boolean;
|
SourceChangeCache: TSourceChangeCache): boolean;
|
||||||
|
function CompleteLocalVariableForIn(CleanCursorPos,
|
||||||
|
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||||
|
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||||
|
SourceChangeCache: TSourceChangeCache): boolean;
|
||||||
function CompleteLocalVariableByParameter(CleanCursorPos,
|
function CompleteLocalVariableByParameter(CleanCursorPos,
|
||||||
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||||
@ -869,6 +875,42 @@ begin
|
|||||||
Result:=TermAtom.EndPos>TermAtom.StartPos;
|
Result:=TermAtom.EndPos>TermAtom.StartPos;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCodeCompletionCodeTool.CheckLocalVarForInSyntax(
|
||||||
|
CleanCursorPos: integer; out VarNameAtom, TermAtom: TAtomPosition): boolean;
|
||||||
|
// check for: for VarName in Term do
|
||||||
|
var
|
||||||
|
InAtomEndPos: LongInt;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
MoveCursorToCleanPos(CleanCursorPos);
|
||||||
|
|
||||||
|
// find variable name
|
||||||
|
GetIdentStartEndAtPosition(Src,CleanCursorPos,
|
||||||
|
VarNameAtom.StartPos,VarNameAtom.EndPos);
|
||||||
|
//debugln('TCodeCompletionCodeTool.CheckLocalVarAssignmentSyntax A ',GetAtom(VarNameAtom),' "',copy(Src,CleanCursorPos,10),'"');
|
||||||
|
if VarNameAtom.StartPos=VarNameAtom.EndPos then exit;
|
||||||
|
MoveCursorToAtomPos(VarNameAtom);
|
||||||
|
if AtomIsKeyWord then exit;
|
||||||
|
|
||||||
|
// find 'in' operator
|
||||||
|
ReadNextAtom;
|
||||||
|
if not UpAtomIs('IN') then exit;
|
||||||
|
InAtomEndPos:=CurPos.EndPos;
|
||||||
|
|
||||||
|
// find 'for' keyword
|
||||||
|
MoveCursorToCleanPos(VarNameAtom.StartPos);
|
||||||
|
ReadPriorAtom;
|
||||||
|
if not UpAtomIs('FOR') then exit;
|
||||||
|
|
||||||
|
// find term
|
||||||
|
MoveCursorToCleanPos(InAtomEndPos);
|
||||||
|
ReadNextAtom;
|
||||||
|
TermAtom.StartPos:=CurPos.StartPos;
|
||||||
|
TermAtom.EndPos:=FindEndOfExpression(TermAtom.StartPos);
|
||||||
|
|
||||||
|
Result:=TermAtom.EndPos>TermAtom.StartPos;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCodeCompletionCodeTool.AddLocalVariable(
|
function TCodeCompletionCodeTool.AddLocalVariable(
|
||||||
CleanCursorPos: integer; OldTopLine: integer;
|
CleanCursorPos: integer; OldTopLine: integer;
|
||||||
VariableName, VariableType, VariableTypeUnitName: string;
|
VariableName, VariableType, VariableTypeUnitName: string;
|
||||||
@ -1151,6 +1193,76 @@ begin
|
|||||||
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
|
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCodeCompletionCodeTool.CompleteLocalVariableForIn(CleanCursorPos,
|
||||||
|
OldTopLine: integer; CursorNode: TCodeTreeNode; var NewPos: TCodeXYPosition;
|
||||||
|
var NewTopLine: integer; SourceChangeCache: TSourceChangeCache): boolean;
|
||||||
|
var
|
||||||
|
VarNameAtom: TAtomPosition;
|
||||||
|
TermAtom: TAtomPosition;
|
||||||
|
Params: TFindDeclarationParams;
|
||||||
|
NewType: String;
|
||||||
|
ExprType: TExpressionType;
|
||||||
|
MissingUnit: String;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn(' CompleteLocalVariableForIn: A');
|
||||||
|
{$ENDIF}
|
||||||
|
if not ((CursorNode.Desc=ctnBeginBlock)
|
||||||
|
or CursorNode.HasParentOfType(ctnBeginBlock)) then exit;
|
||||||
|
if CursorNode.Desc=ctnBeginBlock then
|
||||||
|
BuildSubTreeForBeginBlock(CursorNode);
|
||||||
|
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
|
||||||
|
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn(' CompleteLocalVariableForIn: B CheckLocalVarForInSyntax ...');
|
||||||
|
{$ENDIF}
|
||||||
|
// check assignment syntax
|
||||||
|
if not CheckLocalVarForInSyntax(CleanCursorPos,
|
||||||
|
VarNameAtom,TermAtom)
|
||||||
|
then
|
||||||
|
exit;
|
||||||
|
DebugLn(['TCodeCompletionCodeTool.CompleteLocalVariableForIn Var=',GetAtom(VarNameAtom),' Term=',GetAtom(TermAtom)]);
|
||||||
|
|
||||||
|
// search variable
|
||||||
|
ActivateGlobalWriteLock;
|
||||||
|
Params:=TFindDeclarationParams.Create;
|
||||||
|
try
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn(' CompleteLocalVariableForIn: check if variable is already defined ...');
|
||||||
|
{$ENDIF}
|
||||||
|
// check if identifier exists
|
||||||
|
Result:=IdentifierIsDefined(VarNameAtom,CursorNode,Params);
|
||||||
|
if Result then begin
|
||||||
|
MoveCursorToCleanPos(VarNameAtom.StartPos);
|
||||||
|
ReadNextAtom;
|
||||||
|
RaiseExceptionFmt(ctsIdentifierAlreadyDefined,[GetAtom]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{$IFDEF CTDEBUG}
|
||||||
|
DebugLn(' CompleteLocalVariableForIn: Find type of term ...',
|
||||||
|
' Term="',copy(Src,TermAtom.StartPos,TermAtom.EndPos-TermAtom.StartPos),'"');
|
||||||
|
{$ENDIF}
|
||||||
|
// find type of term
|
||||||
|
NewType:=FindForInTypeAsString(TermAtom,CursorNode,Params,ExprType);
|
||||||
|
if NewType='' then
|
||||||
|
RaiseException('CompleteLocalVariableForIn Internal error: NewType=""');
|
||||||
|
|
||||||
|
finally
|
||||||
|
Params.Free;
|
||||||
|
DeactivateGlobalWriteLock;
|
||||||
|
end;
|
||||||
|
|
||||||
|
MissingUnit:='';
|
||||||
|
if (ExprType.Desc=xtContext)
|
||||||
|
and (ExprType.Context.Tool<>nil) then
|
||||||
|
MissingUnit:=GetUnitForUsesSection(ExprType.Context.Tool);
|
||||||
|
|
||||||
|
Result:=AddVariable(CursorNode,CleanCursorPos,OldTopLine,GetAtom(VarNameAtom),
|
||||||
|
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
|
||||||
|
end;
|
||||||
|
|
||||||
function TCodeCompletionCodeTool.CompleteLocalVariableByParameter(
|
function TCodeCompletionCodeTool.CompleteLocalVariableByParameter(
|
||||||
CleanCursorPos, OldTopLine: integer; CursorNode: TCodeTreeNode;
|
CleanCursorPos, OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||||
@ -6789,6 +6901,11 @@ begin
|
|||||||
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
||||||
if Result then exit;
|
if Result then exit;
|
||||||
|
|
||||||
|
// test if Local variable iterator (for i in j)
|
||||||
|
Result:=CompleteLocalVariableForIn(CleanCursorPos,OldTopLine,
|
||||||
|
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
||||||
|
if Result then exit;
|
||||||
|
|
||||||
// test if undeclared local variable as parameter (GetPenPos(x,y))
|
// test if undeclared local variable as parameter (GetPenPos(x,y))
|
||||||
Result:=CompleteLocalVariableByParameter(CleanCursorPos,OldTopLine,
|
Result:=CompleteLocalVariableByParameter(CleanCursorPos,OldTopLine,
|
||||||
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
||||||
|
@ -643,6 +643,9 @@ type
|
|||||||
function FindTermTypeAsString(TermPos: TAtomPosition;
|
function FindTermTypeAsString(TermPos: TAtomPosition;
|
||||||
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
|
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
|
||||||
out ExprType: TExpressionType): string;
|
out ExprType: TExpressionType): string;
|
||||||
|
function FindForInTypeAsString(TermPos: TAtomPosition;
|
||||||
|
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
|
||||||
|
out ExprType: TExpressionType): string;
|
||||||
function IsTermEdgedBracket(TermPos: TAtomPosition;
|
function IsTermEdgedBracket(TermPos: TAtomPosition;
|
||||||
out EdgedBracketsStartPos: integer): boolean;
|
out EdgedBracketsStartPos: integer): boolean;
|
||||||
function IsTermNamedPointer(TermPos: TAtomPosition;
|
function IsTermNamedPointer(TermPos: TAtomPosition;
|
||||||
@ -8827,6 +8830,93 @@ begin
|
|||||||
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,Params);
|
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,Params);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFindDeclarationTool.FindForInTypeAsString(TermPos: TAtomPosition;
|
||||||
|
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams; out
|
||||||
|
ExprType: TExpressionType): string;
|
||||||
|
|
||||||
|
procedure RaiseTermHasNoIterator;
|
||||||
|
begin
|
||||||
|
if TermPos.StartPos<1 then
|
||||||
|
TermPos.StartPos:=1;
|
||||||
|
MoveCursorToCleanPos(TermPos.StartPos);
|
||||||
|
RaiseException('Can not find an enumerator for '''+TrimCodeSpace(GetAtom(TermPos))+'''');
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ExprType:=CleanExpressionType;
|
||||||
|
Params.ContextNode:=CursorNode;
|
||||||
|
Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
|
||||||
|
fdfTopLvlResolving,fdfFunctionResult];
|
||||||
|
ExprType:=FindExpressionResultType(Params,TermPos.StartPos,TermPos.EndPos);
|
||||||
|
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn('TFindDeclarationTool.FindForInTypeAsString TermType=',
|
||||||
|
ExprTypeToString(ExprType));
|
||||||
|
{$ENDIF}
|
||||||
|
case ExprType.Desc of
|
||||||
|
xtContext:
|
||||||
|
begin
|
||||||
|
// ToDo
|
||||||
|
RaiseTermHasNoIterator;
|
||||||
|
end;
|
||||||
|
xtNone,
|
||||||
|
xtChar,
|
||||||
|
xtWideChar,
|
||||||
|
xtReal,
|
||||||
|
xtSingle,
|
||||||
|
xtDouble,
|
||||||
|
xtExtended,
|
||||||
|
xtCurrency,
|
||||||
|
xtComp,
|
||||||
|
xtInt64,
|
||||||
|
xtCardinal,
|
||||||
|
xtQWord,
|
||||||
|
xtBoolean,
|
||||||
|
xtByteBool,
|
||||||
|
xtLongBool,
|
||||||
|
xtPointer,
|
||||||
|
xtFile,
|
||||||
|
xtText,
|
||||||
|
xtConstOrdInteger,
|
||||||
|
xtConstReal,
|
||||||
|
xtConstBoolean,
|
||||||
|
xtLongint,
|
||||||
|
xtLongWord,
|
||||||
|
xtWord,
|
||||||
|
xtSmallInt,
|
||||||
|
xtShortInt,
|
||||||
|
xtByte,
|
||||||
|
xtCompilerFunc,
|
||||||
|
xtVariant,
|
||||||
|
xtNil:
|
||||||
|
RaiseTermHasNoIterator;
|
||||||
|
xtString,
|
||||||
|
xtAnsiString,
|
||||||
|
xtShortString,
|
||||||
|
xtPChar,
|
||||||
|
xtConstString:
|
||||||
|
begin
|
||||||
|
ExprType.Desc:=xtChar;
|
||||||
|
Result:=ExpressionTypeDescNames[ExprType.Desc];
|
||||||
|
end;
|
||||||
|
xtWideString,
|
||||||
|
xtUnicodeString:
|
||||||
|
begin
|
||||||
|
ExprType.Desc:=xtWideChar;
|
||||||
|
Result:=ExpressionTypeDescNames[ExprType.Desc];
|
||||||
|
end;
|
||||||
|
xtConstSet:
|
||||||
|
RaiseTermHasNoIterator; // ToDo
|
||||||
|
else
|
||||||
|
DebugLn('TFindDeclarationTool.FindForInTypeAsString ExprType=',
|
||||||
|
ExprTypeToString(ExprType));
|
||||||
|
RaiseTermHasNoIterator;
|
||||||
|
end;
|
||||||
|
{$IFDEF ShowExprEval}
|
||||||
|
DebugLn('TFindDeclarationTool.FindForInTypeAsString Result=',Result);
|
||||||
|
{$ENDIF}
|
||||||
|
end;
|
||||||
|
|
||||||
function TFindDeclarationTool.IsTermEdgedBracket(TermPos: TAtomPosition; out
|
function TFindDeclarationTool.IsTermEdgedBracket(TermPos: TAtomPosition; out
|
||||||
EdgedBracketsStartPos: integer): boolean;
|
EdgedBracketsStartPos: integer): boolean;
|
||||||
{ allowed:
|
{ allowed:
|
||||||
@ -8890,6 +8980,7 @@ end;
|
|||||||
|
|
||||||
function TFindDeclarationTool.IsTermNamedPointer(TermPos: TAtomPosition; out
|
function TFindDeclarationTool.IsTermNamedPointer(TermPos: TAtomPosition; out
|
||||||
ExprType: TExpressionType): boolean;
|
ExprType: TExpressionType): boolean;
|
||||||
|
// check if TermPos is @Name and a pointer (= ^Name) can be found
|
||||||
var
|
var
|
||||||
SubExprType: TExpressionType;
|
SubExprType: TExpressionType;
|
||||||
Node: TCodeTreeNode;
|
Node: TCodeTreeNode;
|
||||||
|
Loading…
Reference in New Issue
Block a user