mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-01 20:36: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
|
||||
): boolean;
|
||||
function GetIndents(const Source: string; Positions: TFABPositionIndents;
|
||||
NewNestedComments: boolean; UseLineStart: boolean
|
||||
NewNestedComments: boolean; UseLineStart: boolean;
|
||||
ContextLearn: boolean = true // true = learn policies from Source
|
||||
): boolean;
|
||||
procedure GetDefaultSrcIndent(const Source: string; CleanPos: integer;
|
||||
NewNestedComments: boolean;
|
||||
@ -1528,7 +1529,7 @@ end;
|
||||
|
||||
function TFullyAutomaticBeautifier.GetIndents(const Source: string;
|
||||
Positions: TFABPositionIndents; NewNestedComments: boolean;
|
||||
UseLineStart: boolean): boolean;
|
||||
UseLineStart: boolean; ContextLearn: boolean): boolean;
|
||||
var
|
||||
Needed: LongInt;
|
||||
|
||||
@ -1583,9 +1584,11 @@ begin
|
||||
inc(Item^.CleanPos);
|
||||
end;
|
||||
|
||||
Policies:=TFABPolicies.Create;
|
||||
Policies:=nil;
|
||||
Stack:=TFABBlockStack.Create;
|
||||
try
|
||||
if ContextLearn then
|
||||
Policies:=TFABPolicies.Create;
|
||||
{$IFDEF ShowCodeBeautifierLearn}
|
||||
Policies.Code:=TCodeBuffer.Create;
|
||||
Policies.Code.Source:=Source;
|
||||
@ -1655,19 +1658,22 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// parse source behind
|
||||
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
|
||||
{$IFDEF VerboseIndenter}
|
||||
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
|
||||
{$ENDIF}
|
||||
for ItemIndex:=0 to Positions.Count-1 do begin
|
||||
Item:=@Positions.Items[ItemIndex];
|
||||
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
|
||||
if CheckPolicies(Policies,Item) then exit(true);
|
||||
if Policies<>nil then begin
|
||||
// parse source behind
|
||||
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
|
||||
{$IFDEF VerboseIndenter}
|
||||
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
|
||||
{$ENDIF}
|
||||
for ItemIndex:=0 to Positions.Count-1 do begin
|
||||
Item:=@Positions.Items[ItemIndex];
|
||||
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
|
||||
if CheckPolicies(Policies,Item) then exit(true);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
Stack.Free;
|
||||
FreeAndNil(Policies.Code);
|
||||
if Policies<>nil then
|
||||
FreeAndNil(Policies.Code);
|
||||
Policies.Free;
|
||||
end;
|
||||
|
||||
|
@ -170,6 +170,8 @@ type
|
||||
SourceChangeCache: TSourceChangeCache);
|
||||
function CheckLocalVarAssignmentSyntax(CleanCursorPos: integer;
|
||||
out VarNameAtom,AssignmentOperator,TermAtom: TAtomPosition): boolean;
|
||||
function CheckLocalVarForInSyntax(CleanCursorPos: integer;
|
||||
out VarNameAtom,TermAtom: TAtomPosition): boolean;
|
||||
function AddLocalVariable(CleanCursorPos: integer; OldTopLine: integer;
|
||||
VariableName, VariableType, VariableTypeUnitName: string;
|
||||
out NewPos: TCodeXYPosition; out NewTopLine: integer;
|
||||
@ -186,6 +188,10 @@ type
|
||||
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
SourceChangeCache: TSourceChangeCache): boolean;
|
||||
function CompleteLocalVariableForIn(CleanCursorPos,
|
||||
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
SourceChangeCache: TSourceChangeCache): boolean;
|
||||
function CompleteLocalVariableByParameter(CleanCursorPos,
|
||||
OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
@ -869,6 +875,42 @@ begin
|
||||
Result:=TermAtom.EndPos>TermAtom.StartPos;
|
||||
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(
|
||||
CleanCursorPos: integer; OldTopLine: integer;
|
||||
VariableName, VariableType, VariableTypeUnitName: string;
|
||||
@ -1151,6 +1193,76 @@ begin
|
||||
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
|
||||
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(
|
||||
CleanCursorPos, OldTopLine: integer; CursorNode: TCodeTreeNode;
|
||||
var NewPos: TCodeXYPosition; var NewTopLine: integer;
|
||||
@ -6789,6 +6901,11 @@ begin
|
||||
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
||||
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))
|
||||
Result:=CompleteLocalVariableByParameter(CleanCursorPos,OldTopLine,
|
||||
CursorNode,NewPos,NewTopLine,SourceChangeCache);
|
||||
|
@ -643,6 +643,9 @@ type
|
||||
function FindTermTypeAsString(TermPos: TAtomPosition;
|
||||
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
|
||||
out ExprType: TExpressionType): string;
|
||||
function FindForInTypeAsString(TermPos: TAtomPosition;
|
||||
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
|
||||
out ExprType: TExpressionType): string;
|
||||
function IsTermEdgedBracket(TermPos: TAtomPosition;
|
||||
out EdgedBracketsStartPos: integer): boolean;
|
||||
function IsTermNamedPointer(TermPos: TAtomPosition;
|
||||
@ -8827,6 +8830,93 @@ begin
|
||||
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,Params);
|
||||
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
|
||||
EdgedBracketsStartPos: integer): boolean;
|
||||
{ allowed:
|
||||
@ -8890,6 +8980,7 @@ end;
|
||||
|
||||
function TFindDeclarationTool.IsTermNamedPointer(TermPos: TAtomPosition; out
|
||||
ExprType: TExpressionType): boolean;
|
||||
// check if TermPos is @Name and a pointer (= ^Name) can be found
|
||||
var
|
||||
SubExprType: TExpressionType;
|
||||
Node: TCodeTreeNode;
|
||||
|
Loading…
Reference in New Issue
Block a user