CodeTools: CodeCompletion: include templates (optional). Issue #34389

git-svn-id: trunk@62240 -
This commit is contained in:
ondrej 2019-11-15 19:26:51 +00:00
parent 86a7065f15
commit d3e927b65c
8 changed files with 331 additions and 252 deletions

View File

@ -2901,255 +2901,258 @@ begin
ActivateGlobalWriteLock;
try
InitCollectIdentifiers(CursorPos,IdentifierList);
IdentStartXY:=FindIdentifierStartPos(CursorPos);
try
InitCollectIdentifiers(CursorPos,IdentifierList);
IdentStartXY:=FindIdentifierStartPos(CursorPos);
if CheckCursorInCompilerDirective(IdentStartXY) then exit(true);
if not ParseSourceTillCollectionStart(IdentStartXY,CleanCursorPos,CursorNode,
IdentStartPos,IdentEndPos) then
Exit;
Params:=TFindDeclarationParams.Create(Self,CursorNode);
try
if CleanCursorPos=0 then ;
if IdentStartPos>0 then begin
if not ParseSourceTillCollectionStart(IdentStartXY,CleanCursorPos,CursorNode,
IdentStartPos,IdentEndPos) then
Exit;
Params:=TFindDeclarationParams.Create(Self,CursorNode);
try
if CleanCursorPos=0 then ;
if IdentStartPos>0 then begin
MoveCursorToCleanPos(IdentStartPos);
ReadNextAtom;
CurrentIdentifierList.StartAtom:=CurPos;
end;
MoveCursorToCleanPos(IdentStartPos);
ReadNextAtom;
CurrentIdentifierList.StartAtom:=CurPos;
end;
MoveCursorToCleanPos(IdentStartPos);
ReadPriorAtom;
IdentifierPath := '';
while CurPos.Flag = cafPoint do
begin
ReadPriorAtom;
if CurPos.Flag <> cafWord then
Break;
IdentifierPath := GetUpAtom + '.' + IdentifierPath;
ReadPriorAtom;
end;
// find context
GatherContext:=CreateFindContext(Self,CursorNode);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers B',
' CleanCursorPos=',CleanPosToStr(CleanCursorPos),
' IdentStartPos=',CleanPosToStr(IdentStartPos),' IdentEndPos=',CleanPosToStr(IdentEndPos),
' Ident=',copy(Src,IdentStartPos,IdentEndPos-IdentStartPos),
' GatherContext=',FindContextToString(GatherContext));
{$ENDIF}
CurrentIdentifierList.NewMemberVisibility:=GetClassVisibility(CursorNode);
if CursorNode.Desc in [ctnUsesSection,ctnUseUnit,ctnUseUnitNamespace,ctnUseUnitClearName] then begin
GatherUnitNames(IdentifierPath);
MoveCursorToCleanPos(IdentEndPos);
ReadNextAtom;
if (CurPos.Flag=cafWord) and (not UpAtomIs('IN')) then begin
// add comma
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndComma];
end;
end else if (CursorNode.Desc in AllSourceTypes)
and (PositionsInSameLine(Src,CursorNode.StartPos,IdentStartPos)) then begin
GatherSourceNames(GatherContext);
end else begin
FindCollectionContext(Params,IdentStartPos,CursorNode,
ExprType,ContextExprStartPos,StartInSubContext,
HasInheritedKeyword);
//debugln(['TIdentCompletionTool.GatherIdentifiers FindCollectionContext ',ExprTypeToString(ExprType)]);
GatherContext := ExprType.Context;
// find class and ancestors if existing (needed for protected identifiers)
if (GatherContext.Tool = Self) or HasInheritedKeyword then
IdentifierPath := '';
while CurPos.Flag = cafPoint do
begin
FindContextClassAndAncestorsAndExtendedClassOfHelper(IdentStartXY, FICTClassAndAncestorsAndExtClassOfHelper);
end;
CursorContext:=CreateFindContext(Self,CursorNode);
GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
// check for incomplete context
// context bracket level
CurrentIdentifierList.StartBracketLvl:=
GetBracketLvl(Src,CursorNode.StartPos,IdentStartPos,
Scanner.NestedComments);
if CursorNode.Desc in AllPascalStatements then begin
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartInStatement];
end;
// context in front of
StartPosOfVariable:=FindStartOfTerm(IdentStartPos,NodeTermInType(CursorNode));
if StartPosOfVariable>0 then begin
if StartPosOfVariable=IdentStartPos then begin
// cursor is at start of an operand
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartOfOperand];
end else begin
MoveCursorToCleanPos(IdentStartPos);
ReadPriorAtom;
if CurPos.Flag=cafPoint then
// cursor is behind a point
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartIsSubIdent];
end;
MoveCursorToCleanPos(StartPosOfVariable);
ReadPriorAtom;
CurrentIdentifierList.StartAtomInFront:=CurPos;
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags)
then begin
// check if LValue
if (CurPos.Flag in [cafSemicolon,cafEnd,cafColon])
or UpAtomIs('BEGIN')
or UpAtomIs('TRY') or UpAtomIs('FINALLY') or UpAtomIs('EXCEPT')
or UpAtomIs('FOR') or UpAtomIs('DO') or UpAtomIs('THEN')
or UpAtomIs('REPEAT') or UpAtomIs('ASM') or UpAtomIs('ELSE')
then begin
if CurPos.Flag <> cafWord then
Break;
IdentifierPath := GetUpAtom + '.' + IdentifierPath;
ReadPriorAtom;
end;
// find context
GatherContext:=CreateFindContext(Self,CursorNode);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers B',
' CleanCursorPos=',CleanPosToStr(CleanCursorPos),
' IdentStartPos=',CleanPosToStr(IdentStartPos),' IdentEndPos=',CleanPosToStr(IdentEndPos),
' Ident=',copy(Src,IdentStartPos,IdentEndPos-IdentStartPos),
' GatherContext=',FindContextToString(GatherContext));
{$ENDIF}
CurrentIdentifierList.NewMemberVisibility:=GetClassVisibility(CursorNode);
if CursorNode.Desc in [ctnUsesSection,ctnUseUnit,ctnUseUnitNamespace,ctnUseUnitClearName] then begin
GatherUnitNames(IdentifierPath);
MoveCursorToCleanPos(IdentEndPos);
ReadNextAtom;
if (CurPos.Flag=cafWord) and (not UpAtomIs('IN')) then begin
// add comma
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndComma];
end;
end else if (CursorNode.Desc in AllSourceTypes)
and (PositionsInSameLine(Src,CursorNode.StartPos,IdentStartPos)) then begin
GatherSourceNames(GatherContext);
end else begin
FindCollectionContext(Params,IdentStartPos,CursorNode,
ExprType,ContextExprStartPos,StartInSubContext,
HasInheritedKeyword);
//debugln(['TIdentCompletionTool.GatherIdentifiers FindCollectionContext ',ExprTypeToString(ExprType)]);
GatherContext := ExprType.Context;
// find class and ancestors if existing (needed for protected identifiers)
if (GatherContext.Tool = Self) or HasInheritedKeyword then
begin
FindContextClassAndAncestorsAndExtendedClassOfHelper(IdentStartXY, FICTClassAndAncestorsAndExtClassOfHelper);
end;
CursorContext:=CreateFindContext(Self,CursorNode);
GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
// check for incomplete context
// context bracket level
CurrentIdentifierList.StartBracketLvl:=
GetBracketLvl(Src,CursorNode.StartPos,IdentStartPos,
Scanner.NestedComments);
if CursorNode.Desc in AllPascalStatements then begin
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartInStatement];
end;
// context in front of
StartPosOfVariable:=FindStartOfTerm(IdentStartPos,NodeTermInType(CursorNode));
if StartPosOfVariable>0 then begin
if StartPosOfVariable=IdentStartPos then begin
// cursor is at start of an operand
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartOfStatement];
CurrentIdentifierList.ContextFlags+[ilcfStartOfOperand];
end else begin
MoveCursorToCleanPos(IdentStartPos);
ReadPriorAtom;
if CurPos.Flag=cafPoint then
// cursor is behind a point
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartIsSubIdent];
end;
// check if expression
if UpAtomIs('IF') or UpAtomIs('CASE') or UpAtomIs('WHILE')
or UpAtomIs('UNTIL')
MoveCursorToCleanPos(StartPosOfVariable);
ReadPriorAtom;
CurrentIdentifierList.StartAtomInFront:=CurPos;
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags)
then begin
// todo: check at start of expression, not only in front of variable
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfIsExpression, ilcfDontAllowProcedures];
// check if LValue
if (CurPos.Flag in [cafSemicolon,cafEnd,cafColon])
or UpAtomIs('BEGIN')
or UpAtomIs('TRY') or UpAtomIs('FINALLY') or UpAtomIs('EXCEPT')
or UpAtomIs('FOR') or UpAtomIs('DO') or UpAtomIs('THEN')
or UpAtomIs('REPEAT') or UpAtomIs('ASM') or UpAtomIs('ELSE')
then begin
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfStartOfStatement];
end;
// check if expression
if UpAtomIs('IF') or UpAtomIs('CASE') or UpAtomIs('WHILE')
or UpAtomIs('UNTIL')
then begin
// todo: check at start of expression, not only in front of variable
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfIsExpression, ilcfDontAllowProcedures];
end;
// check if procedure is allowed
if (CurPos.Flag in [cafEdgedBracketOpen, cafEqual, cafOtherOperator])
or ((Scanner.CompilerMode<>cmDelphi) and (CurPos.Flag in [cafAssignment, cafComma, cafRoundBracketOpen])) // "MyEvent := MyProc;" and "o.Test(MyProc)" is supported only in Delphi mode
then
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfDontAllowProcedures];
end;
// check if procedure is allowed
if (CurPos.Flag in [cafEdgedBracketOpen, cafEqual, cafOtherOperator])
or ((Scanner.CompilerMode<>cmDelphi) and (CurPos.Flag in [cafAssignment, cafComma, cafRoundBracketOpen])) // "MyEvent := MyProc;" and "o.Test(MyProc)" is supported only in Delphi mode
end;
// context behind
if (IdentEndPos<SrcLen) then begin
MoveCursorToCleanPos(IdentEndPos);
//debugln(['TIdentCompletionTool.GatherIdentifiers "',dbgstr(Src,IdentStartPos,IdentEndPos-IdentStartPos),'"']);
InFrontOfDirective:=(CurPos.StartPos<SrcLen) and (Src[CurPos.StartPos]='{')
and (Src[CurPos.StartPos+1]='$');
ReadNextAtom;
// check end of line
if (not InFrontOfDirective)
and (CursorPos.Code.LineColIsOutside(CursorPos.Y,CursorPos.X)
or (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
then
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfDontAllowProcedures];
end;
end;
// context behind
if (IdentEndPos<SrcLen) then begin
MoveCursorToCleanPos(IdentEndPos);
//debugln(['TIdentCompletionTool.GatherIdentifiers "',dbgstr(Src,IdentStartPos,IdentEndPos-IdentStartPos),'"']);
InFrontOfDirective:=(CurPos.StartPos<SrcLen) and (Src[CurPos.StartPos]='{')
and (Src[CurPos.StartPos+1]='$');
ReadNextAtom;
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
// check end of line
if (not InFrontOfDirective)
and (CursorPos.Code.LineColIsOutside(CursorPos.Y,CursorPos.X)
or (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
then
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
CurrentIdentifierList.StartAtomBehind:=CurPos;
// check if a semicolon is needed or forbidden at the end
if InFrontOfDirective
or (CurrentIdentifierList.StartBracketLvl>0)
or (CurPos.Flag in [cafSemicolon, cafEqual, cafColon, cafComma,
cafPoint, cafRoundBracketOpen, cafRoundBracketClose,
cafEdgedBracketOpen, cafEdgedBracketClose])
or ((CurPos.Flag in [cafWord,cafNone])
and (UpAtomIs('ELSE')
or UpAtomIs('THEN')
or UpAtomIs('DO')
or UpAtomIs('TO')
or UpAtomIs('OF')
or WordIsBinaryOperator.DoItCaseInsensitive(Src,
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)))
then begin
// do not add semicolon
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNoEndSemicolon];
end;
// check if in statement
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then
begin
// check if a semicolon is needed at the end
if (not (ilcfNoEndSemicolon in CurrentIdentifierList.ContextFlags))
CurrentIdentifierList.StartAtomBehind:=CurPos;
// check if a semicolon is needed or forbidden at the end
if InFrontOfDirective
or (CurrentIdentifierList.StartBracketLvl>0)
or (CurPos.Flag in [cafSemicolon, cafEqual, cafColon, cafComma,
cafPoint, cafRoundBracketOpen, cafRoundBracketClose,
cafEdgedBracketOpen, cafEdgedBracketClose])
or ((CurPos.Flag in [cafWord,cafNone])
and (UpAtomIs('ELSE')
or UpAtomIs('THEN')
or UpAtomIs('DO')
or UpAtomIs('TO')
or UpAtomIs('OF')
or WordIsBinaryOperator.DoItCaseInsensitive(Src,
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)))
then begin
// do not add semicolon
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNoEndSemicolon];
end;
// check if in statement
if (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then
begin
// check if a semicolon is needed at the end
if (CurPos.Flag in [cafEnd])
or WordIsBlockKeyWord.DoItCaseInsensitive(Src,
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
or ((CurPos.Flag=cafWord)
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
if (not (ilcfNoEndSemicolon in CurrentIdentifierList.ContextFlags))
then begin
// add semicolon
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndSemicolon];
// check if a semicolon is needed at the end
if (CurPos.Flag in [cafEnd])
or WordIsBlockKeyWord.DoItCaseInsensitive(Src,
CurPos.StartPos,CurPos.EndPos-CurPos.StartPos)
or ((CurPos.Flag=cafWord)
and (not PositionsInSameLine(Src,IdentEndPos,CurPos.StartPos)))
then begin
// add semicolon
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsEndSemicolon];
end;
end;
end;
end;
// check missing 'do' after 'with'
if CurrentIdentifierList.StartUpAtomInFrontIs('WITH')
and (not CurrentIdentifierList.StartUpAtomBehindIs('DO'))
and (not CurrentIdentifierList.StartUpAtomBehindIs('AS'))
and (CurrentIdentifierList.StartBracketLvl=0)
and (not (CurrentIdentifierList.StartAtomBehind.Flag in
[cafComma,cafPoint,cafRoundBracketOpen,cafEdgedBracketOpen]))
and (not CurrentIdentifierList.StartUpAtomBehindIs('^'))
then
// check missing 'do' after 'with'
if CurrentIdentifierList.StartUpAtomInFrontIs('WITH')
and (not CurrentIdentifierList.StartUpAtomBehindIs('DO'))
and (not CurrentIdentifierList.StartUpAtomBehindIs('AS'))
and (CurrentIdentifierList.StartBracketLvl=0)
and (not (CurrentIdentifierList.StartAtomBehind.Flag in
[cafComma,cafPoint,cafRoundBracketOpen,cafEdgedBracketOpen]))
and (not CurrentIdentifierList.StartUpAtomBehindIs('^'))
then
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsDo];
end else begin
// end of source
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfNeedsDo];
end else begin
// end of source
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
end;
// search and gather identifiers in context
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
GatherContext.Tool.MainFilename,
' ',GatherContext.Node.DescAsString,
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
{$ENDIF}
// gather all identifiers in context
Params.ContextNode:=GatherContext.Node;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then
Include(Params.Flags,fdfIgnoreUsedUnits);
if not StartInSubContext then
Include(Params.Flags,fdfSearchInParentNodes);
if Params.ContextNode.Desc in AllClasses then
Exclude(Params.Flags,fdfSearchInParentNodes);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
{$ENDIF}
CurrentIdentifierList.Context:=GatherContext;
if GatherContext.Node.Desc=ctnIdentifier then
Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode];
GatherContext.Tool.FindIdentifierInContext(Params);
end else
if ExprType.Desc in xtAllTypeHelperTypes then
begin
// gather all identifiers in cursor context for basic types (strings etc.)
Params.ContextNode:=CursorNode;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
CurrentIdentifierList.Context:=CursorContext;
FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params);
end;
// check for procedure/method declaration context
CheckProcedureDeclarationContext;
// add useful identifiers
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers G');
{$ENDIF}
GatherUsefulIdentifiers(IdentStartPos,CursorContext,GatherContext);
end;
// search and gather identifiers in context
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
GatherContext.Tool.MainFilename,
' ',GatherContext.Node.DescAsString,
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
{$ENDIF}
// gather all identifiers in context
Params.ContextNode:=GatherContext.Node;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then
Include(Params.Flags,fdfIgnoreUsedUnits);
if not StartInSubContext then
Include(Params.Flags,fdfSearchInParentNodes);
if Params.ContextNode.Desc in AllClasses then
Exclude(Params.Flags,fdfSearchInParentNodes);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
{$ENDIF}
CurrentIdentifierList.Context:=GatherContext;
if GatherContext.Node.Desc=ctnIdentifier then
Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode];
GatherContext.Tool.FindIdentifierInContext(Params);
end else
if ExprType.Desc in xtAllTypeHelperTypes then
begin
// gather all identifiers in cursor context for basic types (strings etc.)
Params.ContextNode:=CursorNode;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
CurrentIdentifierList.Context:=CursorContext;
FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params);
end;
// check for procedure/method declaration context
CheckProcedureDeclarationContext;
// add useful identifiers
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers G');
{$ENDIF}
GatherUsefulIdentifiers(IdentStartPos,CursorContext,GatherContext);
GatherUserIdentifiers(CurrentIdentifierList.ContextFlags);
Result:=true;
finally
FreeListOfPFindContext(FICTClassAndAncestorsAndExtClassOfHelper);
FreeAndNil(FIDCTFoundPublicProperties);
Params.Free;
ClearIgnoreErrorAfter;
end;
Result:=true;
finally
FreeListOfPFindContext(FICTClassAndAncestorsAndExtClassOfHelper);
FreeAndNil(FIDCTFoundPublicProperties);
Params.Free;
ClearIgnoreErrorAfter;
GatherUserIdentifiers(CurrentIdentifierList.ContextFlags);
end;
finally
DeactivateGlobalWriteLock;

View File

@ -124,6 +124,7 @@ type
FIdentComplAutoStartAfterPoint: boolean;
FIdentComplAutoUseSingleIdent: boolean;
FIdentComplUseContainsFilter: Boolean;
FIdentComplIncludeCodeTemplates: Boolean;
FIdentComplIncludeWords: TIdentComplIncludeWords;
FIdentComplShowIcons: Boolean;
@ -256,6 +257,8 @@ type
write FIdentComplAutoUseSingleIdent;
property IdentComplUseContainsFilter: boolean read FIdentComplUseContainsFilter
write FIdentComplUseContainsFilter;
property IdentComplIncludeCodeTemplates: boolean read FIdentComplIncludeCodeTemplates
write FIdentComplIncludeCodeTemplates;
property IdentComplIncludeWords: TIdentComplIncludeWords read FIdentComplIncludeWords
write FIdentComplIncludeWords;
property IdentComplShowIcons: boolean read FIdentComplShowIcons
@ -574,6 +577,8 @@ begin
'CodeToolsOptions/IdentifierCompletion/AutoUseSingleIdent',true);
FIdentComplUseContainsFilter:=XMLConfig.GetValue(
'CodeToolsOptions/IdentifierCompletion/UseContainsFilter',true);
FIdentComplIncludeCodeTemplates:=XMLConfig.GetValue(
'CodeToolsOptions/IdentifierCompletion/IncludeCodeTemplates',true);
FIdentComplIncludeWords:=IdentComplIncludeWordsNamesToEnum(XMLConfig.GetValue(
'CodeToolsOptions/IdentifierCompletion/IncludeWords',
IdentComplIncludeWordsNames[icwIncludeFromAllUnits]));
@ -749,6 +754,8 @@ begin
FIdentComplAutoUseSingleIdent,true);
XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/UseContainsFilter',
FIdentComplUseContainsFilter,true);
XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/IncludeCodeTemplates',
FIdentComplIncludeCodeTemplates,true);
XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/IncludeWords',
IdentComplIncludeWordsNames[FIdentComplIncludeWords],
IdentComplIncludeWordsNames[icwIncludeFromAllUnits]);
@ -903,6 +910,7 @@ begin
FIdentComplAutoStartAfterPoint:=CodeToolsOpts.FIdentComplAutoStartAfterPoint;
FIdentComplAutoUseSingleIdent:=CodeToolsOpts.FIdentComplAutoUseSingleIdent;
FIdentComplUseContainsFilter:=CodeToolsOpts.FIdentComplUseContainsFilter;
FIdentComplIncludeCodeTemplates:=CodeToolsOpts.FIdentComplIncludeCodeTemplates;
FIdentComplShowIcons:=CodeToolsOpts.FIdentComplShowIcons;
FIdentComplAddParameterBrackets:=CodeToolsOpts.FIdentComplAddParameterBrackets;
FIdentComplReplaceIdentifier:=CodeToolsOpts.FIdentComplReplaceIdentifier;
@ -970,6 +978,7 @@ begin
FIdentComplAutoStartAfterPoint:=true;
FIdentComplAutoUseSingleIdent:=true;
FIdentComplUseContainsFilter:=true;
FIdentComplIncludeCodeTemplates:=true;
FIdentComplShowIcons:=false;
FIdentComplAddParameterBrackets:=true;
FIdentComplReplaceIdentifier:=true;
@ -1056,6 +1065,7 @@ begin
and (FIdentComplAutoStartAfterPoint=CodeToolsOpts.FIdentComplAutoStartAfterPoint)
and (FIdentComplAutoUseSingleIdent=CodeToolsOpts.FIdentComplAutoUseSingleIdent)
and (FIdentComplUseContainsFilter=CodeToolsOpts.FIdentComplUseContainsFilter)
and (FIdentComplIncludeCodeTemplates=CodeToolsOpts.FIdentComplIncludeCodeTemplates)
and (FIdentComplShowIcons=CodeToolsOpts.FIdentComplShowIcons)
and (FIdentComplAddParameterBrackets=CodeToolsOpts.FIdentComplAddParameterBrackets)
and (FIdentComplReplaceIdentifier=CodeToolsOpts.FIdentComplReplaceIdentifier)

View File

@ -78,12 +78,12 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
AnchorSideRight.Side = asrBottom
Left = 0
Height = 19
Top = 344
Top = 365
Width = 124
Caption = 'ICReplaceCheckBox'
ParentShowHint = False
ShowHint = True
TabOrder = 12
TabOrder = 13
end
object ICAddDoCheckBox: TCheckBox
AnchorSideLeft.Control = Owner
@ -174,7 +174,7 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
AnchorSideRight.Side = asrBottom
Left = 0
Height = 15
Top = 329
Top = 350
Width = 537
Caption = 'ICMiscDividerBevel'
Anchors = [akTop, akLeft, akRight]
@ -189,12 +189,12 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
AnchorSideRight.Side = asrBottom
Left = 0
Height = 19
Top = 363
Top = 384
Width = 151
Caption = 'ICJumpToErrorCheckBox'
ParentShowHint = False
ShowHint = True
TabOrder = 13
TabOrder = 14
end
object ICAutoUseSingleIdent: TCheckBox
AnchorSideLeft.Control = Owner
@ -223,13 +223,13 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
end
object ICAppearanceDividerBevel: TDividerBevel
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = ICAddWordsComboBox
AnchorSideTop.Control = ICIncludeCodeTemplatesCheckBox
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 15
Top = 293
Top = 314
Width = 537
Caption = 'ICAppearanceDividerBevel'
Anchors = [akTop, akLeft, akRight]
@ -243,10 +243,10 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
AnchorSideTop.Side = asrBottom
Left = 0
Height = 19
Top = 308
Top = 329
Width = 222
Caption = 'ICUseIconsInCompletionBoxCheckBox'
TabOrder = 11
TabOrder = 12
end
object ICContentDividerBevel: TDividerBevel
AnchorSideLeft.Control = Owner
@ -289,4 +289,16 @@ object CodetoolsIndentifierCompletionOptionsFrame: TCodetoolsIndentifierCompleti
Style = csDropDownList
TabOrder = 10
end
object ICIncludeCodeTemplatesCheckBox: TCheckBox
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = ICAddWordsComboBox
AnchorSideTop.Side = asrBottom
Left = 0
Height = 19
Top = 293
Width = 205
BorderSpacing.Top = 2
Caption = 'ICIncludeCodeTemplatesCheckBox'
TabOrder = 11
end
end

View File

@ -44,6 +44,7 @@ type
ICContainsFilterCheckBox: TCheckBox;
ICAddDoCheckBox: TCheckBox;
ICAutoAddParameterBracketsCheckBox: TCheckBox;
ICIncludeCodeTemplatesCheckBox: TCheckBox;
ICMiscDividerBevel: TDividerBevel;
ICOpenDividerBevel: TDividerBevel;
ICAutoStartAfterPointCheckBox: TCheckBox;
@ -110,6 +111,7 @@ begin
dlgIncludeWordsToIdentCompl_IncludeFromAllUnits+LineEnding+
dlgIncludeWordsToIdentCompl_IncludeFromCurrentUnit+LineEnding+
dlgIncludeWordsToIdentCompl_DontInclude;
ICIncludeCodeTemplatesCheckBox.Caption := dlgIncludeCodeTemplatesToIdentCompl;
ICAppearanceDividerBevel.Caption:=lisAppearance;
ICUseIconsInCompletionBoxCheckBox.Caption := dlgUseIconsInCompletionBox;
@ -138,6 +140,7 @@ begin
ICSortForHistoryCheckBox.Checked:=IdentComplSortForHistory;
ICSortForScopeCheckBox.Checked:=IdentComplSortForScope;
ICContainsFilterCheckBox.Checked:=IdentComplUseContainsFilter;
ICIncludeCodeTemplatesCheckBox.Checked:=IdentComplIncludeCodeTemplates;
ICUseIconsInCompletionBoxCheckBox.Checked:=IdentComplShowIcons;
case IdentComplIncludeWords of
icwIncludeFromAllUnits: ICAddWordsComboBox.ItemIndex:=0;
@ -165,6 +168,7 @@ begin
IdentComplSortForHistory:=ICSortForHistoryCheckBox.Checked;
IdentComplSortForScope:=ICSortForScopeCheckBox.Checked;
IdentComplUseContainsFilter:=ICContainsFilterCheckBox.Checked;
IdentComplIncludeCodeTemplates:=ICIncludeCodeTemplatesCheckBox.Checked;
IdentComplShowIcons:=ICUseIconsInCompletionBoxCheckBox.Checked;
case ICAddWordsComboBox.ItemIndex of
0: IdentComplIncludeWords := icwIncludeFromAllUnits;

View File

@ -2055,6 +2055,7 @@ resourcestring
dlgIncludeWordsToIdentCompl_IncludeFromAllUnits = 'from all units';
dlgIncludeWordsToIdentCompl_IncludeFromCurrentUnit = 'from current unit';
dlgIncludeWordsToIdentCompl_DontInclude = 'don''t include';
dlgIncludeCodeTemplatesToIdentCompl = 'Include code templates';
dlgMarkupUserDefined = 'User defined markup';
dlgMarkupUserDefinedNoLists = 'No lists';

View File

@ -667,6 +667,7 @@ type
function OIHelpProvider: TAbstractIDEHTMLProvider;
procedure DoAddWordsToIdentCompletion(Sender: TIdentifierList;
FilteredList: TFPList; PriorityCount: Integer);
procedure DoAddCodeTemplatesToIdentCompletion;
// form editor and designer
procedure DoBringToFrontFormOrUnit;
procedure DoBringToFrontFormOrInspector(ForceInspector: boolean);
@ -2053,6 +2054,8 @@ procedure TMainIDE.CodeToolBossGatherUserIdentifiers(
);
begin
FIdentifierWordCompletionEnabled := not (ilcfStartIsSubIdent in ContextFlags);
if not (ilcfStartIsSubIdent in ContextFlags) then
DoAddCodeTemplatesToIdentCompletion;
end;
procedure TMainIDE.CodeToolBossGatherUserIdentifiersToFilteredList(
@ -7297,6 +7300,24 @@ begin
AbortBuild;
end;
procedure TMainIDE.DoAddCodeTemplatesToIdentCompletion;
var
New: TCodeTemplateIdentifierListItem;
I: Integer;
begin
if not CodeToolsOpts.IdentComplIncludeCodeTemplates then
Exit;
for I := 0 to SourceEditorManager.CodeTemplateModul.Completions.Count-1 do
begin
New := TCodeTemplateIdentifierListItem.Create(CodeTemplateCompatibility, False, CodeTemplateHistoryIndex,
PChar(SourceEditorManager.CodeTemplateModul.Completions[I]),
CodeTemplateLevel, nil, nil, ctnCodeTemplate);
New.Comment := SourceEditorManager.CodeTemplateModul.CompletionComments[I];
CodeToolBoss.IdentifierList.Add(New);
end;
end;
procedure TMainIDE.DoCompile;
var
ASrcEdit: TSourceEditor;

View File

@ -56,7 +56,7 @@ uses
LazStringUtils,
// codetools
BasicCodeTools, CodeBeautifier, CodeToolManager, CodeCache, SourceLog,
LinkScanner, CodeTree, SourceChanger,
LinkScanner, CodeTree, SourceChanger, IdentCompletionTool,
// synedit
SynEditLines, SynEditStrConst, SynEditTypes, SynEdit,
SynEditHighlighter, SynEditAutoComplete, SynEditKeyCmds, SynCompletion,
@ -1204,8 +1204,6 @@ type
procedure OnSourceMarksAction(AMark: TSourceMark; {%H-}AAction: TMarksAction);
procedure OnSourceMarksGetSynEdit(Sender: TObject; aFilename: string;
var aSynEdit: TSynEdit);
property CodeTemplateModul: TSynEditAutoComplete
read FCodeTemplateModul write FCodeTemplateModul;
// goto dialog
function GotoDialog: TfrmGoto;
public
@ -1216,6 +1214,8 @@ type
AnID: Integer = -1
): TSourceNotebook;
function SenderToEditor(Sender: TObject): TSourceEditor;
property CodeTemplateModul: TSynEditAutoComplete
read FCodeTemplateModul write FCodeTemplateModul;
private
// Context-Menu
procedure CloseOtherPagesClicked(Sender: TObject);
@ -2427,6 +2427,7 @@ var
OldCompletionType: TCompletionType;
prototypeAdded: boolean;
SourceNoteBook: TSourceNotebook;
IdentItem: TIdentifierListItem;
Begin
{$IFDEF VerboseIDECompletionBox}
DebugLnEnter(['TSourceNotebook.ccComplete START']);
@ -2444,22 +2445,29 @@ Begin
SourceStart,SourceEnd,KeyChar,Shift);
Manager.FActiveCompletionPlugin:=nil;
end else begin
IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[Position];
// add to history
CodeToolBoss.IdentifierHistory.Add(
CodeToolBoss.IdentifierList.FilteredItems[Position]);
// get value
NewValue:=GetIdentCompletionValue(Self, KeyChar, ValueType, CursorToLeft);
if ValueType=icvIdentifier then ;
// insert value plus special chars like brackets, semicolons, ...
if ValueType <> icvNone then
Editor.TextBetweenPointsEx[SourceStart, SourceEnd, scamEnd] := NewValue;
if ValueType in [icvProcWithParams,icvIndexedProp] then
prototypeAdded := true;
if CursorToLeft>0 then
CodeToolBoss.IdentifierHistory.Add(IdentItem);
if IdentItem is TCodeTemplateIdentifierListItem then
begin
NewCaretXY:=Editor.CaretXY;
dec(NewCaretXY.X,CursorToLeft);
Editor.CaretXY:=NewCaretXY;
if IdentItem.Identifier<>'' then
Manager.CodeTemplateModul.ExecuteCompletion(IdentItem.Identifier, Editor);
end else
begin
// get value
NewValue:=GetIdentCompletionValue(Self, KeyChar, ValueType, CursorToLeft);
if ValueType=icvIdentifier then ;
// insert value plus special chars like brackets, semicolons, ...
if ValueType <> icvNone then
Editor.TextBetweenPointsEx[SourceStart, SourceEnd, scamEnd] := NewValue;
if ValueType in [icvProcWithParams,icvIndexedProp] then
prototypeAdded := true;
if CursorToLeft>0 then
begin
NewCaretXY:=Editor.CaretXY;
dec(NewCaretXY.X,CursorToLeft);
Editor.CaretXY:=NewCaretXY;
end;
end;
ccSelection := '';
Value:='';

View File

@ -90,6 +90,11 @@ type
procedure BeautifyIdentifier(IdentList: TIdentifierList); override;
end;
TCodeTemplateIdentifierListItem = class(TIdentifierListItem)
public
Comment: string;
end;
procedure SetupTextConverters;
procedure FreeTextConverters;
@ -128,7 +133,11 @@ function BreakLinesInText(const s: string; MaxLineLength: integer): string;
const
ctnWord = ctnUser + 1;
ctnCodeTemplate = ctnUser + 2;
WordCompatibility = icompUnknown;
CodeTemplateCompatibility = icompUnknown;
CodeTemplateHistoryIndex = High(Integer);
CodeTemplateLevel = High(Integer);
implementation
@ -497,6 +506,12 @@ begin
s:='text';
end;
ctnCodeTemplate:
begin
AColor:=clGray;
s:='template';
end;
ctnNone:
if not UseImages then
begin
@ -704,6 +719,11 @@ begin
s := s + ':' + IdentItem.ResultType;
s:=s+';'
end;
ctnCodeTemplate:
begin
if IdentItem is TCodeTemplateIdentifierListItem then
s:=' - '+TCodeTemplateIdentifierListItem(IdentItem).Comment;
end;
end;
end;