View Issue Details

IDProjectCategoryView StatusLast Update
0033054PatchesPatchpublic2018-07-16 00:56
ReporterregsAssigned To 
PrioritynormalSeverityminorReproducibilityN/A
Status newResolutionopen 
Product VersionProduct Build 
Target VersionFixed in Version 
Summary0033054: Autoinvoke Identifier Completion on type
DescriptionOptionally Invokes Identifier Completion automatically while typing. And in case if cancelled won't bothering until next identifier.

Separated Hint delay and Identifier Completion delay in config, so hint won't annoy if set to 0.
I set hint delay to 1 sec and didn't add it to options, but it still can be changed via config. I guess it won't be that popular. But if crucial, additional trackbar can be added.

32972 crash issue could be a blocker for this patch
https://bugs.freepascal.org/view.php?id=32972

Hope didn't forget anything.

Autoinvoke after point is fixed. Work after point only now.
TagsNo tags attached.
Fixed in Revision
LazTarget-
Widgetset
Attached Files
  • autoinvoke.patch (23,561 bytes)
    Index: components/codetools/identcompletiontool.pas
    ===================================================================
    --- components/codetools/identcompletiontool.pas	(revision 57113)
    +++ components/codetools/identcompletiontool.pas	(working copy)
    @@ -1979,6 +1979,45 @@
             end;
           end;
     
    +    ctnBeginBlock, ctnWithStatement, ctnWithVariable, ctnOnBlock, ctnOnIdentifier,
    +    ctnOnStatement:
    +      begin
    +        Add('and');
    +        Add('as');
    +        Add('asm');
    +        Add('begin');
    +        Add('case');
    +        Add('div');
    +        Add('do');
    +        Add('downto');
    +        Add('else');
    +        Add('end');
    +        Add('except');
    +        Add('finally');
    +        Add('for');
    +        Add('goto');
    +        Add('if');
    +        Add('in');
    +        Add('inherited');
    +        Add('is');
    +        Add('label');
    +        Add('mod');
    +        Add('not');
    +        Add('of');
    +        Add('or');
    +        Add('raise');
    +        Add('repeat');
    +        Add('shl');
    +        Add('shr');
    +        Add('then');
    +        Add('to');
    +        Add('try');
    +        Add('until');
    +        Add('while');
    +        Add('with');
    +        Add('xor');
    +      end;
    +
         ctnProperty:
           CheckProperty(Node);
     
    @@ -2860,7 +2899,6 @@
             end;
     
             CursorContext:=CreateFindContext(Self,CursorNode);
    -        GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
     
             // check for incomplete context
     
    @@ -2919,6 +2957,11 @@
                     CurrentIdentifierList.ContextFlags+[ilcfDontAllowProcedures];
               end;
             end;
    +
    +        if not (ilcfDontAllowProcedures in CurrentIdentifierList.ContextFlags) and
    +           not (GatherContext.Node.Desc in AllClassObjects) then
    +            GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
    +
             // context behind
             if (IdentEndPos<SrcLen) then begin
               MoveCursorToCleanPos(IdentEndPos);
    Index: ide/codetoolsoptions.pas
    ===================================================================
    --- ide/codetoolsoptions.pas	(revision 57113)
    +++ ide/codetoolsoptions.pas	(working copy)
    @@ -110,6 +110,7 @@
         // identifier completion
         FIdentComplAddSemicolon: Boolean;
         FIdentComplAddAssignOperator: Boolean;
    +    FIdentComplAutoInvokeOnType: boolean;
         FIdentComplAutoStartAfterPoint: boolean;
         FIdentComplAutoUseSingleIdent: boolean;
     
    @@ -236,6 +237,8 @@
         property IdentComplAddAssignOperator: Boolean read FIdentComplAddAssignOperator
                                                  write FIdentComplAddAssignOperator;
         property IdentComplAddDo: Boolean read FIdentComplAddDo write FIdentComplAddDo;
    +    property IdentComplAutoInvokeOnType: boolean read FIdentComplAutoInvokeOnType
    +                                           write FIdentComplAutoInvokeOnType;
         property IdentComplAutoStartAfterPoint: boolean read FIdentComplAutoStartAfterPoint
                                                write FIdentComplAutoStartAfterPoint;
         property IdentComplAutoUseSingleIdent: boolean read FIdentComplAutoUseSingleIdent
    @@ -535,6 +538,8 @@
           'CodeToolsOptions/IdentifierCompletion/AddAssignOperator',true);
         FIdentComplAddDo:=XMLConfig.GetValue(
           'CodeToolsOptions/IdentifierCompletion/AddDo',true);
    +    FIdentComplAutoInvokeOnType:=XMLConfig.GetValue(
    +      'CodeToolsOptions/IdentifierCompletion/AutoInvokeOnType',true);
         FIdentComplAutoStartAfterPoint:=XMLConfig.GetValue(
           'CodeToolsOptions/IdentifierCompletion/AutoStartAfterPoint',true);
         FIdentComplAutoUseSingleIdent:=XMLConfig.GetValue(
    @@ -703,6 +708,8 @@
           FIdentComplAddAssignOperator,true);
         XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AddDo',
           FIdentComplAddDo,true);
    +    XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoInvokeOnType',
    +      FIdentComplAutoInvokeOnType,true);
         XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoStartAfterPoint',
           FIdentComplAutoStartAfterPoint,true);
         XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoUseSingleIdent',
    @@ -853,6 +860,7 @@
         FIdentComplAddSemicolon:=CodeToolsOpts.FIdentComplAddSemicolon;
         FIdentComplAddAssignOperator:=CodeToolsOpts.FIdentComplAddAssignOperator;
         FIdentComplAddDo:=CodeToolsOpts.FIdentComplAddDo;
    +    FIdentComplAutoInvokeOnType:=CodeToolsOpts.FIdentComplAutoInvokeOnType;
         FIdentComplAutoStartAfterPoint:=CodeToolsOpts.FIdentComplAutoStartAfterPoint;
         FIdentComplAutoUseSingleIdent:=CodeToolsOpts.FIdentComplAutoUseSingleIdent;
         FIdentComplAddParameterBrackets:=CodeToolsOpts.FIdentComplAddParameterBrackets;
    @@ -918,6 +926,7 @@
       FIdentComplAddSemicolon:=true;
       FIdentComplAddAssignOperator:=true;
       FIdentComplAddDo:=true;
    +  FIdentComplAutoInvokeOnType:=true;
       FIdentComplAutoStartAfterPoint:=true;
       FIdentComplAutoUseSingleIdent:=true;
       FIdentComplAddParameterBrackets:=true;
    @@ -1002,6 +1011,7 @@
         and (FIdentComplAddSemicolon=CodeToolsOpts.FIdentComplAddSemicolon)
         and (FIdentComplAddAssignOperator=CodeToolsOpts.FIdentComplAddAssignOperator)
         and (FIdentComplAddDo=CodeToolsOpts.FIdentComplAddDo)
    +    and (FIdentComplAutoInvokeOnType=CodeToolsOpts.FIdentComplAutoInvokeOnType)
         and (FIdentComplAutoStartAfterPoint=CodeToolsOpts.FIdentComplAutoStartAfterPoint)
         and (FIdentComplAutoUseSingleIdent=CodeToolsOpts.FIdentComplAutoUseSingleIdent)
         and (FIdentComplAddParameterBrackets=CodeToolsOpts.FIdentComplAddParameterBrackets)
    Index: ide/editoroptions.pp
    ===================================================================
    --- ide/editoroptions.pp	(revision 57113)
    +++ ide/editoroptions.pp	(working copy)
    @@ -1380,7 +1380,8 @@
         // Code tools options (MG: these will move to an unit of their own)
         fAutoBlockCompletion: Boolean;
         fAutoCodeParameters: Boolean;
    -    fAutoDelayInMSec: Integer;
    +    fCodeCompletionDelayInMSec: Integer;
    +    fHintDelayInMSec: Integer;
         FAutoRemoveEmptyMethods: Boolean;
         fAutoToolTipExprEval: Boolean;
         fAutoToolTipSymbTools: Boolean;
    @@ -1593,8 +1594,10 @@
         property DbgHintAutoTypeCastClass: Boolean
           read FDbgHintAutoTypeCastClass write FDbgHintAutoTypeCastClass default True; // declaration hints
       public
    -    property AutoDelayInMSec: Integer read fAutoDelayInMSec
    -      write fAutoDelayInMSec default 1000;
    +    property CodeCompletionDelayInMSec: Integer read fCodeCompletionDelayInMSec
    +      write fCodeCompletionDelayInMSec default 10;
    +    property HintDelayInMSec: Integer read fHintDelayInMSec
    +      write fHintDelayInMSec default 1000;
         property CodeTemplateFileName: String
           read fCodeTemplateFileName write fCodeTemplateFileName;
         property CodeTemplateIndentToTokenStart: Boolean
    @@ -4762,8 +4765,10 @@
           XMLConfig.GetValue('EditorOptions/CodeTools/AutoToolTipExprEval', True);
         fAutoToolTipSymbTools :=
           XMLConfig.GetValue('EditorOptions/CodeTools/AutoToolTipSymbTools', True);
    -    fAutoDelayInMSec    :=
    -      XMLConfig.GetValue('EditorOptions/CodeTools/AutoDelayInMSec', 1000);
    +    fCodeCompletionDelayInMSec    :=
    +      XMLConfig.GetValue('EditorOptions/CodeTools/CodeCompletionDelayInMSec', 10);
    +    fHintDelayInMSec    :=
    +      XMLConfig.GetValue('EditorOptions/CodeTools/HintDelayInMSec', 1000);
         fCodeTemplateFileName :=
           XMLConfig.GetValue('EditorOptions/CodeTools/CodeTemplateFileName'
           , TrimFilename(AppendPathDelim(GetPrimaryConfigPath) + DefaultCodeTemplatesFilename));
    @@ -4961,8 +4966,10 @@
           , fAutoToolTipExprEval, True);
         XMLConfig.SetDeleteValue('EditorOptions/CodeTools/AutoToolTipSymbTools'
           , fAutoToolTipSymbTools, True);
    -    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/AutoDelayInMSec'
    -      , fAutoDelayInMSec, 1000);
    +    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/CodeCompletionDelayInMSec'
    +      , fCodeCompletionDelayInMSec, 10);
    +    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/HintDelayInMSec'
    +      , fHintDelayInMSec, 1000);
         XMLConfig.SetDeleteValue('EditorOptions/CodeTools/CodeTemplateFileName'
           , fCodeTemplateFileName, '');
         XMLConfig.SetDeleteValue(
    Index: ide/frames/codetools_identifiercompletion_options.lfm
    ===================================================================
    --- ide/frames/codetools_identifiercompletion_options.lfm	(revision 57113)
    +++ ide/frames/codetools_identifiercompletion_options.lfm	(working copy)
    @@ -19,7 +19,7 @@
         Top = 99
         Width = 161
         Caption = 'ICAddSemicolonCheckBox'
    -    TabOrder = 3
    +    TabOrder = 4
       end
       object ICAddAssignOperatorCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -31,9 +31,9 @@
         Top = 118
         Width = 187
         Caption = 'ICAddAssignOperatorCheckBox'
    -    TabOrder = 4
    +    TabOrder = 5
       end
    -  object ICAutoStartAfterPointCheckBox: TCheckBox
    +  object ICAutoInvokeOnTypeCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
         AnchorSideTop.Control = ICOpenDividerBevel
         AnchorSideTop.Side = asrBottom
    @@ -42,9 +42,21 @@
         Height = 19
         Top = 25
         Width = 187
    -    Caption = 'ICAutoStartAfterPointCheckBox'
    +    Caption = 'ICAutoInvokeOnTypeCheckBox'
         TabOrder = 0
       end
    +  object ICAutoStartAfterPointCheckBox: TCheckBox
    +    AnchorSideLeft.Control = Owner
    +    AnchorSideTop.Control = ICAutoInvokeOnTypeCheckBox
    +    AnchorSideTop.Side = asrBottom
    +    AnchorSideRight.Side = asrBottom
    +    Left = 0
    +    Height = 19
    +    Top = 25
    +    Width = 187
    +    Caption = 'ICAutoStartAfterPointCheckBox'
    +    TabOrder = 1
    +  end
       object ICAutoAddParameterBracketsCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
         AnchorSideTop.Control = ICAddDoCheckBox
    @@ -55,7 +67,7 @@
         Top = 156
         Width = 229
         Caption = 'ICAutoAddParameterBracketsCheckBox'
    -    TabOrder = 6
    +    TabOrder = 7
       end
       object ICShowHelpCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -69,7 +81,7 @@
         Caption = 'ICShowHelpCheckBox'
         ParentShowHint = False
         ShowHint = True
    -    TabOrder = 2
    +    TabOrder = 3
       end
       object ICReplaceCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -83,7 +95,7 @@
         Caption = 'ICReplaceCheckBox'
         ParentShowHint = False
         ShowHint = True
    -    TabOrder = 9
    +    TabOrder = 10
       end
       object ICAddDoCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -95,7 +107,7 @@
         Top = 137
         Width = 120
         Caption = 'ICAddDoCheckBox'
    -    TabOrder = 5
    +    TabOrder = 6
       end
       object ICSortForHistoryCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -106,7 +118,7 @@
         Top = 192
         Width = 159
         Caption = 'ICSortForHistoryCheckBox'
    -    TabOrder = 7
    +    TabOrder = 8
       end
       object ICSortForScopeCheckBox: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -119,7 +131,7 @@
         Caption = 'ICSortForScopeCheckBox'
         ParentShowHint = False
         ShowHint = True
    -    TabOrder = 8
    +    TabOrder = 9
       end
       object ICOpenDividerBevel: TDividerBevel
         AnchorSideLeft.Control = Owner
    @@ -194,7 +206,7 @@
         Caption = 'ICJumpToErrorCheckBox'
         ParentShowHint = False
         ShowHint = True
    -    TabOrder = 10
    +    TabOrder = 11
       end
       object ICAutoUseSingleIdent: TCheckBox
         AnchorSideLeft.Control = Owner
    @@ -208,6 +220,6 @@
         Caption = 'ICAutoUseSingleIdent'
         ParentShowHint = False
         ShowHint = True
    -    TabOrder = 1
    +    TabOrder = 2
       end
     end
    Index: ide/frames/codetools_identifiercompletion_options.pas
    ===================================================================
    --- ide/frames/codetools_identifiercompletion_options.pas	(revision 57113)
    +++ ide/frames/codetools_identifiercompletion_options.pas	(working copy)
    @@ -37,6 +37,7 @@
         ICAutoAddParameterBracketsCheckBox: TCheckBox;
         ICMiscDividerBevel: TDividerBevel;
         ICOpenDividerBevel: TDividerBevel;
    +    ICAutoInvokeOnTypeCheckBox: TCheckBox;
         ICAutoStartAfterPointCheckBox: TCheckBox;
         ICAddAssignOperatorCheckBox: TCheckBox;
         ICAddSemicolonCheckBox: TCheckBox;
    @@ -72,6 +73,7 @@
       ADialog: TAbstractOptionsEditorDialog);
     begin
       ICOpenDividerBevel.Caption:=lisIdCOpening;
    +  ICAutoInvokeOnTypeCheckBox.Caption:=lisAutomaticallyInvokeOnType;
       ICAutoStartAfterPointCheckBox.Caption:=lisAutomaticallyInvokeAfterPoint;
       ICAutoUseSingleIdent.Caption:=lisAutomaticallyUseSinglePossibleIdent;
       ICAutoUseSingleIdent.Hint:=
    @@ -105,6 +107,7 @@
         ICAddSemicolonCheckBox.Checked := IdentComplAddSemicolon;
         ICAddAssignOperatorCheckBox.Checked := IdentComplAddAssignOperator;
         ICAddDoCheckBox.Checked := IdentComplAddDo;
    +    ICAutoInvokeOnTypeCheckBox.Checked := IdentComplAutoInvokeOnType;
         ICAutoStartAfterPointCheckBox.Checked := IdentComplAutoStartAfterPoint;
         ICAutoUseSingleIdent.Checked := IdentComplAutoUseSingleIdent;
         ICAutoAddParameterBracketsCheckBox.Checked:=IdentComplAddParameterBrackets;
    @@ -124,6 +127,7 @@
         IdentComplAddSemicolon := ICAddSemicolonCheckBox.Checked;
         IdentComplAddAssignOperator := ICAddAssignOperatorCheckBox.Checked;
         IdentComplAddDo := ICAddDoCheckBox.Checked;
    +    IdentComplAutoInvokeOnType := ICAutoInvokeOnTypeCheckBox.Checked;
         IdentComplAutoStartAfterPoint := ICAutoStartAfterPointCheckBox.Checked;
         IdentComplAutoUseSingleIdent := ICAutoUseSingleIdent.Checked;
         IdentComplAddParameterBrackets:=ICAutoAddParameterBracketsCheckBox.Checked;
    Index: ide/frames/editor_codetools_options.pas
    ===================================================================
    --- ide/frames/editor_codetools_options.pas	(revision 57113)
    +++ ide/frames/editor_codetools_options.pas	(working copy)
    @@ -110,7 +110,7 @@
         AutoToolTipExprEvalCheckBox.Checked := AutoToolTipExprEval;
         AutoToolTipSymbToolsCheckBox.Checked := AutoToolTipSymbTools;
         DbgToolTipAutoCastClass.Checked := DbgHintAutoTypeCastClass;
    -    AutoDelayTrackBar.Position := AutoDelayInMSec;
    +    AutoDelayTrackBar.Position := CodeCompletionDelayInMSec;
         AutoRemoveEmptyMethodsOnSave.Checked := AutoRemoveEmptyMethods;
         AutoDisplayFuncProtoCheckBox.Checked := AutoDisplayFunctionPrototypes;
         ContainsFilterCheckBox.Checked := ContainsCompletionFilter;
    @@ -132,7 +132,7 @@
         AutoToolTipExprEval := AutoToolTipExprEvalCheckBox.Checked;
         AutoToolTipSymbTools := AutoToolTipSymbToolsCheckBox.Checked;
         DbgHintAutoTypeCastClass := DbgToolTipAutoCastClass.Checked;
    -    AutoDelayInMSec := AutoDelayTrackBar.Position;
    +    CodeCompletionDelayInMSec := AutoDelayTrackBar.Position;
         AutoRemoveEmptyMethods := AutoRemoveEmptyMethodsOnSave.Checked;
         AutoDisplayFunctionPrototypes := AutoDisplayFuncProtoCheckBox.Checked;
         ContainsCompletionFilter := ContainsFilterCheckBox.Checked;
    Index: ide/lazarusidestrconsts.pas
    ===================================================================
    --- ide/lazarusidestrconsts.pas	(revision 57113)
    +++ ide/lazarusidestrconsts.pas	(working copy)
    @@ -1960,7 +1960,7 @@
       dlgAutoDisplayFuncProto = 'Auto Display Function Prototypes';
       lisShowDeclarationHints = 'Show declaration hints';
       dlgEdDelayInSec = '(%s sec delay)';
    -  lisDelayForHintsAndCompletionBox = 'Delay for hints and completion box';
    +  lisDelayForHintsAndCompletionBox = 'Delay for completion box';
       lisDelayForCompletionLongLineHint = 'Delay for long line hints in completion box';
       lisCompletionLongLineHintType = 'Show long line hints';
       lisCompletionLongLineHintTypeNone = 'Never';
    @@ -5793,6 +5793,7 @@
         +'exist. Values were not checked.';
       lisInsertPrintShortTag = 'Insert PrintShort tag';
       lisIdCOpening = 'Opening';
    +  lisAutomaticallyInvokeOnType = 'Automatically invoke on typing';
       lisAutomaticallyInvokeAfterPoint = 'Automatically invoke after point';
       lisAutomaticallyUseSinglePossibleIdent = 'Automatically use single possible identifier';
       lisWhenThereIsOnlyOnePossibleCompletionItemUseItImmed = 'When there is only '
    Index: ide/sourceeditor.pp
    ===================================================================
    --- ide/sourceeditor.pp	(revision 57113)
    +++ ide/sourceeditor.pp	(working copy)
    @@ -954,6 +954,7 @@
         FCompletionPlugins: TFPList;
         FDefaultCompletionForm: TSourceEditCompletion;
         FActiveCompletionPlugin: TSourceEditorCompletionPlugin;
    +    FCodeCompletionReady: Boolean;
         function GetDefaultCompletionForm: TSourceEditCompletion;
         procedure  FreeCompletionPlugins;
         function  GetScreenRectForToken(AnEditor: TCustomSynEdit; PhysColumn, PhysRow, EndColumn: Integer): TRect;
    @@ -973,6 +974,7 @@
         procedure DeactivateCompletionForm; override;
         procedure RegisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
         procedure UnregisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
    +    property CodeCompletionReady: Boolean read FCodeCompletionReady write FCodeCompletionReady;
       protected
         procedure Notification(AComponent: TComponent; Operation: TOperation); override;
         procedure IncUpdateLockInternal;
    @@ -1950,7 +1952,7 @@
       // HintTimer
       FAutoHintTimer := TIdleTimer.Create(nil);
       with FAutoHintTimer do begin
    -    Interval := EditorOpts.AutoDelayInMSec;
    +    Interval := EditorOpts.HintDelayInMSec;
         Enabled := False;
         AutoEnabled := False;
         OnTimer := @HintTimer;
    @@ -2203,6 +2205,7 @@
       //debugln(GetStackTrace(true));
       {$ENDIF}
       Manager.DeactivateCompletionForm;
    +  Manager.CodeCompletionReady := False; // prevent code completion if cancelled until identifier is completed
       {$IFDEF VerboseIDECompletionBox}
       finally
         DebugLnExit(['TSourceNotebook.ccCancel END']);
    @@ -2326,6 +2329,7 @@
       end;
     
       Manager.DeactivateCompletionForm;
    +  Manager.CodeCompletionReady := True;
     
       //DebugLn(['TSourceNotebook.ccComplete ',KeyChar,' ',OldCompletionType=ctIdentCompletion]);
       if (KeyChar='.') and (OldCompletionType=ctIdentCompletion) then
    @@ -3739,6 +3743,12 @@
         end;
       end;
     
    +  if not(
    +     (Command = ecChar) or
    +     (Command = ecDeleteLastChar) or
    +     (Command = ecDeleteChar)) then
    +    Manager.CodeCompletionReady := True;
    +
       case Command of
     
       ecSelEditorTop, ecSelEditorBottom, ecEditorTop, ecEditorBottom:
    @@ -3770,6 +3780,8 @@
         begin
           AddChar:=true;
           //debugln(['TSourceEditor.ProcessCommand AChar="',AChar,'" AutoIdentifierCompletion=',dbgs(EditorOpts.AutoIdentifierCompletion),' Interval=',AutoStartCompletionBoxTimer.Interval,' ',Dbgs(FEditor.CaretXY),' ',FEditor.IsIdentChar(aChar)]);
    +      if (GetWordAtCurrentCaret = '') or not(FEditor.IsIdentChar(AChar)) then
    +        Manager.CodeCompletionReady := True;
           if (aChar=' ') and AutoCompleteChar(aChar,AddChar,acoSpace) then begin
             // completed
           end
    @@ -3776,7 +3788,9 @@
           else if (not FEditor.IsIdentChar(aChar))
           and AutoCompleteChar(aChar,AddChar,acoWordEnd) then begin
             // completed
    -      end else if CodeToolsOpts.IdentComplAutoStartAfterPoint then begin
    +      end else if ((aChar='.') and CodeToolsOpts.IdentComplAutoStartAfterPoint) or
    +                  (CodeToolsOpts.IdentComplAutoInvokeOnType) then
    +      begin
             // store caret position to detect caret changes
             SourceCompletionCaretXY:=FEditor.CaretXY;
             // add the char
    @@ -9961,7 +9975,7 @@
       for i := FSourceWindowList.Count - 1 downto 0 do
         SourceWindows[i].ReloadEditorOptions;
     
    -  AutoStartCompletionBoxTimer.Interval:=EditorOpts.AutoDelayInMSec;
    +  AutoStartCompletionBoxTimer.Interval:=EditorOpts.CodeCompletionDelayInMSec;
       // reload code templates
       with CodeTemplateModul do begin
         if FileExistsUTF8(EditorOpts.CodeTemplateFilename) then
    @@ -9979,7 +9993,7 @@
         IndentToTokenStart:=EditorOpts.CodeTemplateIndentToTokenStart;
       end;
     
    -  FHints.AutoHintTimer.Interval:=EditorOpts.AutoDelayInMSec;
    +  FHints.AutoHintTimer.Interval:=EditorOpts.HintDelayInMSec;
     
       if FDefaultCompletionForm <> nil then begin
         FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
    @@ -10745,17 +10759,43 @@
     
     procedure TSourceEditorManager.OnSourceCompletionTimer(Sender: TObject);
     
    +  function CheckCodeAttribute (XY: TPoint; out CodeAttri: String): Boolean;
    +  var
    +    SrcEdit: TSourceEditor;
    +    Token: string;
    +    Attri: TSynHighlighterAttributes;
    +  begin
    +
    +    Result := False;
    +
    +    SrcEdit := ActiveEditor;
    +    if SrcEdit = nil then exit;
    +
    +    Token:='';
    +    Attri:=nil;
    +    dec(XY.X);
    +    if SrcEdit.EditorComponent.GetHighlighterAttriAtRowCol(XY,Token,Attri)
    +    and (Attri<>nil) {and (Attri.StoredName=AttriName)} then
    +    begin
    +      CodeAttri := Attri.StoredName;
    +      Result := True;
    +    end;
    +
    +  end;
    +
       function CheckStartIdentCompletion: boolean;
       var
         Line: String;
         LogCaret: TPoint;
    -    p: Integer;
    -    InStringConstant: Boolean;
         SrcEdit: TSourceEditor;
    -    Token: string;
    -    Attri: TSynHighlighterAttributes;
    +    CodeAttribute: String;
    +    aChar: Char;
       begin
         Result := false;
    +
    +    if not FCodeCompletionReady then
    +      Exit;
    +
         SrcEdit := ActiveEditor;
         if SrcEdit = nil then exit;
         if not (SrcEdit.FEditor.Highlighter is TSynPasSyn) then
    @@ -10765,35 +10805,40 @@
         LogCaret := SrcEdit.FEditor.LogicalCaretXY;
         //DebugLn(['CheckStartIdentCompletion Line="',Line,'" LogCaret=',dbgs(LogCaret)]);
     
    -    // check if last character is a point
    -    if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line))
    -    or (Line[LogCaret.X-1]<>'.') then
    +    // check for empty line
    +    if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line)) then
           exit;
     
    +    aChar := Line[LogCaret.X-1];
    +
    +    // quick check for valid letters
    +    if not(aChar in ['a'..'z', 'A'..'Z', '_', '0'..'9', '.', '$']) then
    +      Exit;
    +
    +    if not CheckCodeAttribute(LogCaret, CodeAttribute) then
    +      Exit;
    +
    +    // check for attributes
    +    if (aChar= '.') and not(CodeAttribute = SYNS_XML_AttrSymbol) then
    +      Exit;
    +
    +    if (aChar in ['a'..'z', 'A'..'Z', '_', '0'..'9']) and
    +       not ((CodeAttribute = SYNS_XML_AttrIdentifier) or (CodeAttribute = SYNS_XML_AttrDirective)) then
    +      Exit;
    +
    +    if (aChar='$') and not(CodeAttribute = SYNS_XML_AttrDirective) then
    +        Exit;
    +
    +    if CodeAttribute = SYNS_XML_AttrComment then
    +      Exit;
    +
    +    if CodeAttribute = SYNS_XML_AttrString then
    +      Exit;
    +
         // check if range operator '..'
         if (LogCaret.X>2) and (Line[LogCaret.X-2]='.') then
           exit; // this is a double point ..
     
    -    // check if in a string constant
    -    p:=1;
    -    InStringConstant:=false;
    -    while (p<LogCaret.X) and (p<=length(Line)) do begin
    -      if Line[p]='''' then
    -        InStringConstant:=not InStringConstant;
    -      inc(p);
    -    end;
    -    if InStringConstant then exit;
    -
    -    // check if in a comment
    -    Token:='';
    -    Attri:=nil;
    -    dec(LogCaret.X);
    -    if SrcEdit.EditorComponent.GetHighlighterAttriAtRowCol(LogCaret,Token,Attri)
    -    and (Attri<>nil) and (Attri.StoredName=SYNS_XML_AttrComment) then
    -    begin
    -      exit;
    -    end;
    -
         // invoke identifier completion
         SrcEdit.StartIdentCompletionBox(false,false);
         Result:=true;
    @@ -10867,6 +10912,7 @@
       inherited Create(AOwner);
     
       FDefaultCompletionForm := nil;
    +  FCodeCompletionReady := True;
     
       // word completion
       if aWordCompletion=nil then begin
    @@ -10883,7 +10929,7 @@
         Name:='AutoStartCompletionBoxTimer';
         AutoEnabled := False;
         Enabled := false;
    -    Interval := EditorOpts.AutoDelayInMSec;
    +    Interval := EditorOpts.CodeCompletionDelayInMSec;
         OnTimer := @OnSourceCompletionTimer;
       end;
     
    
    autoinvoke.patch (23,561 bytes)
  • autoinvokecc.gif (1,305,805 bytes)

Relationships

related to 0032972 assignedMattias Gaertner Lazarus Crash when calling Identifier completion in interface section 

Activities

regs

2018-01-20 03:11

reporter  

autoinvoke.patch (23,561 bytes)
Index: components/codetools/identcompletiontool.pas
===================================================================
--- components/codetools/identcompletiontool.pas	(revision 57113)
+++ components/codetools/identcompletiontool.pas	(working copy)
@@ -1979,6 +1979,45 @@
         end;
       end;
 
+    ctnBeginBlock, ctnWithStatement, ctnWithVariable, ctnOnBlock, ctnOnIdentifier,
+    ctnOnStatement:
+      begin
+        Add('and');
+        Add('as');
+        Add('asm');
+        Add('begin');
+        Add('case');
+        Add('div');
+        Add('do');
+        Add('downto');
+        Add('else');
+        Add('end');
+        Add('except');
+        Add('finally');
+        Add('for');
+        Add('goto');
+        Add('if');
+        Add('in');
+        Add('inherited');
+        Add('is');
+        Add('label');
+        Add('mod');
+        Add('not');
+        Add('of');
+        Add('or');
+        Add('raise');
+        Add('repeat');
+        Add('shl');
+        Add('shr');
+        Add('then');
+        Add('to');
+        Add('try');
+        Add('until');
+        Add('while');
+        Add('with');
+        Add('xor');
+      end;
+
     ctnProperty:
       CheckProperty(Node);
 
@@ -2860,7 +2899,6 @@
         end;
 
         CursorContext:=CreateFindContext(Self,CursorNode);
-        GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
 
         // check for incomplete context
 
@@ -2919,6 +2957,11 @@
                 CurrentIdentifierList.ContextFlags+[ilcfDontAllowProcedures];
           end;
         end;
+
+        if not (ilcfDontAllowProcedures in CurrentIdentifierList.ContextFlags) and
+           not (GatherContext.Node.Desc in AllClassObjects) then
+            GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
+
         // context behind
         if (IdentEndPos<SrcLen) then begin
           MoveCursorToCleanPos(IdentEndPos);
Index: ide/codetoolsoptions.pas
===================================================================
--- ide/codetoolsoptions.pas	(revision 57113)
+++ ide/codetoolsoptions.pas	(working copy)
@@ -110,6 +110,7 @@
     // identifier completion
     FIdentComplAddSemicolon: Boolean;
     FIdentComplAddAssignOperator: Boolean;
+    FIdentComplAutoInvokeOnType: boolean;
     FIdentComplAutoStartAfterPoint: boolean;
     FIdentComplAutoUseSingleIdent: boolean;
 
@@ -236,6 +237,8 @@
     property IdentComplAddAssignOperator: Boolean read FIdentComplAddAssignOperator
                                              write FIdentComplAddAssignOperator;
     property IdentComplAddDo: Boolean read FIdentComplAddDo write FIdentComplAddDo;
+    property IdentComplAutoInvokeOnType: boolean read FIdentComplAutoInvokeOnType
+                                           write FIdentComplAutoInvokeOnType;
     property IdentComplAutoStartAfterPoint: boolean read FIdentComplAutoStartAfterPoint
                                            write FIdentComplAutoStartAfterPoint;
     property IdentComplAutoUseSingleIdent: boolean read FIdentComplAutoUseSingleIdent
@@ -535,6 +538,8 @@
       'CodeToolsOptions/IdentifierCompletion/AddAssignOperator',true);
     FIdentComplAddDo:=XMLConfig.GetValue(
       'CodeToolsOptions/IdentifierCompletion/AddDo',true);
+    FIdentComplAutoInvokeOnType:=XMLConfig.GetValue(
+      'CodeToolsOptions/IdentifierCompletion/AutoInvokeOnType',true);
     FIdentComplAutoStartAfterPoint:=XMLConfig.GetValue(
       'CodeToolsOptions/IdentifierCompletion/AutoStartAfterPoint',true);
     FIdentComplAutoUseSingleIdent:=XMLConfig.GetValue(
@@ -703,6 +708,8 @@
       FIdentComplAddAssignOperator,true);
     XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AddDo',
       FIdentComplAddDo,true);
+    XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoInvokeOnType',
+      FIdentComplAutoInvokeOnType,true);
     XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoStartAfterPoint',
       FIdentComplAutoStartAfterPoint,true);
     XMLConfig.SetDeleteValue('CodeToolsOptions/IdentifierCompletion/AutoUseSingleIdent',
@@ -853,6 +860,7 @@
     FIdentComplAddSemicolon:=CodeToolsOpts.FIdentComplAddSemicolon;
     FIdentComplAddAssignOperator:=CodeToolsOpts.FIdentComplAddAssignOperator;
     FIdentComplAddDo:=CodeToolsOpts.FIdentComplAddDo;
+    FIdentComplAutoInvokeOnType:=CodeToolsOpts.FIdentComplAutoInvokeOnType;
     FIdentComplAutoStartAfterPoint:=CodeToolsOpts.FIdentComplAutoStartAfterPoint;
     FIdentComplAutoUseSingleIdent:=CodeToolsOpts.FIdentComplAutoUseSingleIdent;
     FIdentComplAddParameterBrackets:=CodeToolsOpts.FIdentComplAddParameterBrackets;
@@ -918,6 +926,7 @@
   FIdentComplAddSemicolon:=true;
   FIdentComplAddAssignOperator:=true;
   FIdentComplAddDo:=true;
+  FIdentComplAutoInvokeOnType:=true;
   FIdentComplAutoStartAfterPoint:=true;
   FIdentComplAutoUseSingleIdent:=true;
   FIdentComplAddParameterBrackets:=true;
@@ -1002,6 +1011,7 @@
     and (FIdentComplAddSemicolon=CodeToolsOpts.FIdentComplAddSemicolon)
     and (FIdentComplAddAssignOperator=CodeToolsOpts.FIdentComplAddAssignOperator)
     and (FIdentComplAddDo=CodeToolsOpts.FIdentComplAddDo)
+    and (FIdentComplAutoInvokeOnType=CodeToolsOpts.FIdentComplAutoInvokeOnType)
     and (FIdentComplAutoStartAfterPoint=CodeToolsOpts.FIdentComplAutoStartAfterPoint)
     and (FIdentComplAutoUseSingleIdent=CodeToolsOpts.FIdentComplAutoUseSingleIdent)
     and (FIdentComplAddParameterBrackets=CodeToolsOpts.FIdentComplAddParameterBrackets)
Index: ide/editoroptions.pp
===================================================================
--- ide/editoroptions.pp	(revision 57113)
+++ ide/editoroptions.pp	(working copy)
@@ -1380,7 +1380,8 @@
     // Code tools options (MG: these will move to an unit of their own)
     fAutoBlockCompletion: Boolean;
     fAutoCodeParameters: Boolean;
-    fAutoDelayInMSec: Integer;
+    fCodeCompletionDelayInMSec: Integer;
+    fHintDelayInMSec: Integer;
     FAutoRemoveEmptyMethods: Boolean;
     fAutoToolTipExprEval: Boolean;
     fAutoToolTipSymbTools: Boolean;
@@ -1593,8 +1594,10 @@
     property DbgHintAutoTypeCastClass: Boolean
       read FDbgHintAutoTypeCastClass write FDbgHintAutoTypeCastClass default True; // declaration hints
   public
-    property AutoDelayInMSec: Integer read fAutoDelayInMSec
-      write fAutoDelayInMSec default 1000;
+    property CodeCompletionDelayInMSec: Integer read fCodeCompletionDelayInMSec
+      write fCodeCompletionDelayInMSec default 10;
+    property HintDelayInMSec: Integer read fHintDelayInMSec
+      write fHintDelayInMSec default 1000;
     property CodeTemplateFileName: String
       read fCodeTemplateFileName write fCodeTemplateFileName;
     property CodeTemplateIndentToTokenStart: Boolean
@@ -4762,8 +4765,10 @@
       XMLConfig.GetValue('EditorOptions/CodeTools/AutoToolTipExprEval', True);
     fAutoToolTipSymbTools :=
       XMLConfig.GetValue('EditorOptions/CodeTools/AutoToolTipSymbTools', True);
-    fAutoDelayInMSec    :=
-      XMLConfig.GetValue('EditorOptions/CodeTools/AutoDelayInMSec', 1000);
+    fCodeCompletionDelayInMSec    :=
+      XMLConfig.GetValue('EditorOptions/CodeTools/CodeCompletionDelayInMSec', 10);
+    fHintDelayInMSec    :=
+      XMLConfig.GetValue('EditorOptions/CodeTools/HintDelayInMSec', 1000);
     fCodeTemplateFileName :=
       XMLConfig.GetValue('EditorOptions/CodeTools/CodeTemplateFileName'
       , TrimFilename(AppendPathDelim(GetPrimaryConfigPath) + DefaultCodeTemplatesFilename));
@@ -4961,8 +4966,10 @@
       , fAutoToolTipExprEval, True);
     XMLConfig.SetDeleteValue('EditorOptions/CodeTools/AutoToolTipSymbTools'
       , fAutoToolTipSymbTools, True);
-    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/AutoDelayInMSec'
-      , fAutoDelayInMSec, 1000);
+    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/CodeCompletionDelayInMSec'
+      , fCodeCompletionDelayInMSec, 10);
+    XMLConfig.SetDeleteValue('EditorOptions/CodeTools/HintDelayInMSec'
+      , fHintDelayInMSec, 1000);
     XMLConfig.SetDeleteValue('EditorOptions/CodeTools/CodeTemplateFileName'
       , fCodeTemplateFileName, '');
     XMLConfig.SetDeleteValue(
Index: ide/frames/codetools_identifiercompletion_options.lfm
===================================================================
--- ide/frames/codetools_identifiercompletion_options.lfm	(revision 57113)
+++ ide/frames/codetools_identifiercompletion_options.lfm	(working copy)
@@ -19,7 +19,7 @@
     Top = 99
     Width = 161
     Caption = 'ICAddSemicolonCheckBox'
-    TabOrder = 3
+    TabOrder = 4
   end
   object ICAddAssignOperatorCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -31,9 +31,9 @@
     Top = 118
     Width = 187
     Caption = 'ICAddAssignOperatorCheckBox'
-    TabOrder = 4
+    TabOrder = 5
   end
-  object ICAutoStartAfterPointCheckBox: TCheckBox
+  object ICAutoInvokeOnTypeCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
     AnchorSideTop.Control = ICOpenDividerBevel
     AnchorSideTop.Side = asrBottom
@@ -42,9 +42,21 @@
     Height = 19
     Top = 25
     Width = 187
-    Caption = 'ICAutoStartAfterPointCheckBox'
+    Caption = 'ICAutoInvokeOnTypeCheckBox'
     TabOrder = 0
   end
+  object ICAutoStartAfterPointCheckBox: TCheckBox
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = ICAutoInvokeOnTypeCheckBox
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Side = asrBottom
+    Left = 0
+    Height = 19
+    Top = 25
+    Width = 187
+    Caption = 'ICAutoStartAfterPointCheckBox'
+    TabOrder = 1
+  end
   object ICAutoAddParameterBracketsCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
     AnchorSideTop.Control = ICAddDoCheckBox
@@ -55,7 +67,7 @@
     Top = 156
     Width = 229
     Caption = 'ICAutoAddParameterBracketsCheckBox'
-    TabOrder = 6
+    TabOrder = 7
   end
   object ICShowHelpCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -69,7 +81,7 @@
     Caption = 'ICShowHelpCheckBox'
     ParentShowHint = False
     ShowHint = True
-    TabOrder = 2
+    TabOrder = 3
   end
   object ICReplaceCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -83,7 +95,7 @@
     Caption = 'ICReplaceCheckBox'
     ParentShowHint = False
     ShowHint = True
-    TabOrder = 9
+    TabOrder = 10
   end
   object ICAddDoCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -95,7 +107,7 @@
     Top = 137
     Width = 120
     Caption = 'ICAddDoCheckBox'
-    TabOrder = 5
+    TabOrder = 6
   end
   object ICSortForHistoryCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -106,7 +118,7 @@
     Top = 192
     Width = 159
     Caption = 'ICSortForHistoryCheckBox'
-    TabOrder = 7
+    TabOrder = 8
   end
   object ICSortForScopeCheckBox: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -119,7 +131,7 @@
     Caption = 'ICSortForScopeCheckBox'
     ParentShowHint = False
     ShowHint = True
-    TabOrder = 8
+    TabOrder = 9
   end
   object ICOpenDividerBevel: TDividerBevel
     AnchorSideLeft.Control = Owner
@@ -194,7 +206,7 @@
     Caption = 'ICJumpToErrorCheckBox'
     ParentShowHint = False
     ShowHint = True
-    TabOrder = 10
+    TabOrder = 11
   end
   object ICAutoUseSingleIdent: TCheckBox
     AnchorSideLeft.Control = Owner
@@ -208,6 +220,6 @@
     Caption = 'ICAutoUseSingleIdent'
     ParentShowHint = False
     ShowHint = True
-    TabOrder = 1
+    TabOrder = 2
   end
 end
Index: ide/frames/codetools_identifiercompletion_options.pas
===================================================================
--- ide/frames/codetools_identifiercompletion_options.pas	(revision 57113)
+++ ide/frames/codetools_identifiercompletion_options.pas	(working copy)
@@ -37,6 +37,7 @@
     ICAutoAddParameterBracketsCheckBox: TCheckBox;
     ICMiscDividerBevel: TDividerBevel;
     ICOpenDividerBevel: TDividerBevel;
+    ICAutoInvokeOnTypeCheckBox: TCheckBox;
     ICAutoStartAfterPointCheckBox: TCheckBox;
     ICAddAssignOperatorCheckBox: TCheckBox;
     ICAddSemicolonCheckBox: TCheckBox;
@@ -72,6 +73,7 @@
   ADialog: TAbstractOptionsEditorDialog);
 begin
   ICOpenDividerBevel.Caption:=lisIdCOpening;
+  ICAutoInvokeOnTypeCheckBox.Caption:=lisAutomaticallyInvokeOnType;
   ICAutoStartAfterPointCheckBox.Caption:=lisAutomaticallyInvokeAfterPoint;
   ICAutoUseSingleIdent.Caption:=lisAutomaticallyUseSinglePossibleIdent;
   ICAutoUseSingleIdent.Hint:=
@@ -105,6 +107,7 @@
     ICAddSemicolonCheckBox.Checked := IdentComplAddSemicolon;
     ICAddAssignOperatorCheckBox.Checked := IdentComplAddAssignOperator;
     ICAddDoCheckBox.Checked := IdentComplAddDo;
+    ICAutoInvokeOnTypeCheckBox.Checked := IdentComplAutoInvokeOnType;
     ICAutoStartAfterPointCheckBox.Checked := IdentComplAutoStartAfterPoint;
     ICAutoUseSingleIdent.Checked := IdentComplAutoUseSingleIdent;
     ICAutoAddParameterBracketsCheckBox.Checked:=IdentComplAddParameterBrackets;
@@ -124,6 +127,7 @@
     IdentComplAddSemicolon := ICAddSemicolonCheckBox.Checked;
     IdentComplAddAssignOperator := ICAddAssignOperatorCheckBox.Checked;
     IdentComplAddDo := ICAddDoCheckBox.Checked;
+    IdentComplAutoInvokeOnType := ICAutoInvokeOnTypeCheckBox.Checked;
     IdentComplAutoStartAfterPoint := ICAutoStartAfterPointCheckBox.Checked;
     IdentComplAutoUseSingleIdent := ICAutoUseSingleIdent.Checked;
     IdentComplAddParameterBrackets:=ICAutoAddParameterBracketsCheckBox.Checked;
Index: ide/frames/editor_codetools_options.pas
===================================================================
--- ide/frames/editor_codetools_options.pas	(revision 57113)
+++ ide/frames/editor_codetools_options.pas	(working copy)
@@ -110,7 +110,7 @@
     AutoToolTipExprEvalCheckBox.Checked := AutoToolTipExprEval;
     AutoToolTipSymbToolsCheckBox.Checked := AutoToolTipSymbTools;
     DbgToolTipAutoCastClass.Checked := DbgHintAutoTypeCastClass;
-    AutoDelayTrackBar.Position := AutoDelayInMSec;
+    AutoDelayTrackBar.Position := CodeCompletionDelayInMSec;
     AutoRemoveEmptyMethodsOnSave.Checked := AutoRemoveEmptyMethods;
     AutoDisplayFuncProtoCheckBox.Checked := AutoDisplayFunctionPrototypes;
     ContainsFilterCheckBox.Checked := ContainsCompletionFilter;
@@ -132,7 +132,7 @@
     AutoToolTipExprEval := AutoToolTipExprEvalCheckBox.Checked;
     AutoToolTipSymbTools := AutoToolTipSymbToolsCheckBox.Checked;
     DbgHintAutoTypeCastClass := DbgToolTipAutoCastClass.Checked;
-    AutoDelayInMSec := AutoDelayTrackBar.Position;
+    CodeCompletionDelayInMSec := AutoDelayTrackBar.Position;
     AutoRemoveEmptyMethods := AutoRemoveEmptyMethodsOnSave.Checked;
     AutoDisplayFunctionPrototypes := AutoDisplayFuncProtoCheckBox.Checked;
     ContainsCompletionFilter := ContainsFilterCheckBox.Checked;
Index: ide/lazarusidestrconsts.pas
===================================================================
--- ide/lazarusidestrconsts.pas	(revision 57113)
+++ ide/lazarusidestrconsts.pas	(working copy)
@@ -1960,7 +1960,7 @@
   dlgAutoDisplayFuncProto = 'Auto Display Function Prototypes';
   lisShowDeclarationHints = 'Show declaration hints';
   dlgEdDelayInSec = '(%s sec delay)';
-  lisDelayForHintsAndCompletionBox = 'Delay for hints and completion box';
+  lisDelayForHintsAndCompletionBox = 'Delay for completion box';
   lisDelayForCompletionLongLineHint = 'Delay for long line hints in completion box';
   lisCompletionLongLineHintType = 'Show long line hints';
   lisCompletionLongLineHintTypeNone = 'Never';
@@ -5793,6 +5793,7 @@
     +'exist. Values were not checked.';
   lisInsertPrintShortTag = 'Insert PrintShort tag';
   lisIdCOpening = 'Opening';
+  lisAutomaticallyInvokeOnType = 'Automatically invoke on typing';
   lisAutomaticallyInvokeAfterPoint = 'Automatically invoke after point';
   lisAutomaticallyUseSinglePossibleIdent = 'Automatically use single possible identifier';
   lisWhenThereIsOnlyOnePossibleCompletionItemUseItImmed = 'When there is only '
Index: ide/sourceeditor.pp
===================================================================
--- ide/sourceeditor.pp	(revision 57113)
+++ ide/sourceeditor.pp	(working copy)
@@ -954,6 +954,7 @@
     FCompletionPlugins: TFPList;
     FDefaultCompletionForm: TSourceEditCompletion;
     FActiveCompletionPlugin: TSourceEditorCompletionPlugin;
+    FCodeCompletionReady: Boolean;
     function GetDefaultCompletionForm: TSourceEditCompletion;
     procedure  FreeCompletionPlugins;
     function  GetScreenRectForToken(AnEditor: TCustomSynEdit; PhysColumn, PhysRow, EndColumn: Integer): TRect;
@@ -973,6 +974,7 @@
     procedure DeactivateCompletionForm; override;
     procedure RegisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
     procedure UnregisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
+    property CodeCompletionReady: Boolean read FCodeCompletionReady write FCodeCompletionReady;
   protected
     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
     procedure IncUpdateLockInternal;
@@ -1950,7 +1952,7 @@
   // HintTimer
   FAutoHintTimer := TIdleTimer.Create(nil);
   with FAutoHintTimer do begin
-    Interval := EditorOpts.AutoDelayInMSec;
+    Interval := EditorOpts.HintDelayInMSec;
     Enabled := False;
     AutoEnabled := False;
     OnTimer := @HintTimer;
@@ -2203,6 +2205,7 @@
   //debugln(GetStackTrace(true));
   {$ENDIF}
   Manager.DeactivateCompletionForm;
+  Manager.CodeCompletionReady := False; // prevent code completion if cancelled until identifier is completed
   {$IFDEF VerboseIDECompletionBox}
   finally
     DebugLnExit(['TSourceNotebook.ccCancel END']);
@@ -2326,6 +2329,7 @@
   end;
 
   Manager.DeactivateCompletionForm;
+  Manager.CodeCompletionReady := True;
 
   //DebugLn(['TSourceNotebook.ccComplete ',KeyChar,' ',OldCompletionType=ctIdentCompletion]);
   if (KeyChar='.') and (OldCompletionType=ctIdentCompletion) then
@@ -3739,6 +3743,12 @@
     end;
   end;
 
+  if not(
+     (Command = ecChar) or
+     (Command = ecDeleteLastChar) or
+     (Command = ecDeleteChar)) then
+    Manager.CodeCompletionReady := True;
+
   case Command of
 
   ecSelEditorTop, ecSelEditorBottom, ecEditorTop, ecEditorBottom:
@@ -3770,6 +3780,8 @@
     begin
       AddChar:=true;
       //debugln(['TSourceEditor.ProcessCommand AChar="',AChar,'" AutoIdentifierCompletion=',dbgs(EditorOpts.AutoIdentifierCompletion),' Interval=',AutoStartCompletionBoxTimer.Interval,' ',Dbgs(FEditor.CaretXY),' ',FEditor.IsIdentChar(aChar)]);
+      if (GetWordAtCurrentCaret = '') or not(FEditor.IsIdentChar(AChar)) then
+        Manager.CodeCompletionReady := True;
       if (aChar=' ') and AutoCompleteChar(aChar,AddChar,acoSpace) then begin
         // completed
       end
@@ -3776,7 +3788,9 @@
       else if (not FEditor.IsIdentChar(aChar))
       and AutoCompleteChar(aChar,AddChar,acoWordEnd) then begin
         // completed
-      end else if CodeToolsOpts.IdentComplAutoStartAfterPoint then begin
+      end else if ((aChar='.') and CodeToolsOpts.IdentComplAutoStartAfterPoint) or
+                  (CodeToolsOpts.IdentComplAutoInvokeOnType) then
+      begin
         // store caret position to detect caret changes
         SourceCompletionCaretXY:=FEditor.CaretXY;
         // add the char
@@ -9961,7 +9975,7 @@
   for i := FSourceWindowList.Count - 1 downto 0 do
     SourceWindows[i].ReloadEditorOptions;
 
-  AutoStartCompletionBoxTimer.Interval:=EditorOpts.AutoDelayInMSec;
+  AutoStartCompletionBoxTimer.Interval:=EditorOpts.CodeCompletionDelayInMSec;
   // reload code templates
   with CodeTemplateModul do begin
     if FileExistsUTF8(EditorOpts.CodeTemplateFilename) then
@@ -9979,7 +9993,7 @@
     IndentToTokenStart:=EditorOpts.CodeTemplateIndentToTokenStart;
   end;
 
-  FHints.AutoHintTimer.Interval:=EditorOpts.AutoDelayInMSec;
+  FHints.AutoHintTimer.Interval:=EditorOpts.HintDelayInMSec;
 
   if FDefaultCompletionForm <> nil then begin
     FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
@@ -10745,17 +10759,43 @@
 
 procedure TSourceEditorManager.OnSourceCompletionTimer(Sender: TObject);
 
+  function CheckCodeAttribute (XY: TPoint; out CodeAttri: String): Boolean;
+  var
+    SrcEdit: TSourceEditor;
+    Token: string;
+    Attri: TSynHighlighterAttributes;
+  begin
+
+    Result := False;
+
+    SrcEdit := ActiveEditor;
+    if SrcEdit = nil then exit;
+
+    Token:='';
+    Attri:=nil;
+    dec(XY.X);
+    if SrcEdit.EditorComponent.GetHighlighterAttriAtRowCol(XY,Token,Attri)
+    and (Attri<>nil) {and (Attri.StoredName=AttriName)} then
+    begin
+      CodeAttri := Attri.StoredName;
+      Result := True;
+    end;
+
+  end;
+
   function CheckStartIdentCompletion: boolean;
   var
     Line: String;
     LogCaret: TPoint;
-    p: Integer;
-    InStringConstant: Boolean;
     SrcEdit: TSourceEditor;
-    Token: string;
-    Attri: TSynHighlighterAttributes;
+    CodeAttribute: String;
+    aChar: Char;
   begin
     Result := false;
+
+    if not FCodeCompletionReady then
+      Exit;
+
     SrcEdit := ActiveEditor;
     if SrcEdit = nil then exit;
     if not (SrcEdit.FEditor.Highlighter is TSynPasSyn) then
@@ -10765,35 +10805,40 @@
     LogCaret := SrcEdit.FEditor.LogicalCaretXY;
     //DebugLn(['CheckStartIdentCompletion Line="',Line,'" LogCaret=',dbgs(LogCaret)]);
 
-    // check if last character is a point
-    if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line))
-    or (Line[LogCaret.X-1]<>'.') then
+    // check for empty line
+    if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line)) then
       exit;
 
+    aChar := Line[LogCaret.X-1];
+
+    // quick check for valid letters
+    if not(aChar in ['a'..'z', 'A'..'Z', '_', '0'..'9', '.', '$']) then
+      Exit;
+
+    if not CheckCodeAttribute(LogCaret, CodeAttribute) then
+      Exit;
+
+    // check for attributes
+    if (aChar= '.') and not(CodeAttribute = SYNS_XML_AttrSymbol) then
+      Exit;
+
+    if (aChar in ['a'..'z', 'A'..'Z', '_', '0'..'9']) and
+       not ((CodeAttribute = SYNS_XML_AttrIdentifier) or (CodeAttribute = SYNS_XML_AttrDirective)) then
+      Exit;
+
+    if (aChar='$') and not(CodeAttribute = SYNS_XML_AttrDirective) then
+        Exit;
+
+    if CodeAttribute = SYNS_XML_AttrComment then
+      Exit;
+
+    if CodeAttribute = SYNS_XML_AttrString then
+      Exit;
+
     // check if range operator '..'
     if (LogCaret.X>2) and (Line[LogCaret.X-2]='.') then
       exit; // this is a double point ..
 
-    // check if in a string constant
-    p:=1;
-    InStringConstant:=false;
-    while (p<LogCaret.X) and (p<=length(Line)) do begin
-      if Line[p]='''' then
-        InStringConstant:=not InStringConstant;
-      inc(p);
-    end;
-    if InStringConstant then exit;
-
-    // check if in a comment
-    Token:='';
-    Attri:=nil;
-    dec(LogCaret.X);
-    if SrcEdit.EditorComponent.GetHighlighterAttriAtRowCol(LogCaret,Token,Attri)
-    and (Attri<>nil) and (Attri.StoredName=SYNS_XML_AttrComment) then
-    begin
-      exit;
-    end;
-
     // invoke identifier completion
     SrcEdit.StartIdentCompletionBox(false,false);
     Result:=true;
@@ -10867,6 +10912,7 @@
   inherited Create(AOwner);
 
   FDefaultCompletionForm := nil;
+  FCodeCompletionReady := True;
 
   // word completion
   if aWordCompletion=nil then begin
@@ -10883,7 +10929,7 @@
     Name:='AutoStartCompletionBoxTimer';
     AutoEnabled := False;
     Enabled := false;
-    Interval := EditorOpts.AutoDelayInMSec;
+    Interval := EditorOpts.CodeCompletionDelayInMSec;
     OnTimer := @OnSourceCompletionTimer;
   end;
 
autoinvoke.patch (23,561 bytes)

regs

2018-01-20 03:12

reporter  

autoinvokecc.gif (1,305,805 bytes)

Ondrej Pokorny

2018-01-20 06:02

developer   ~0105948

Maybe better to fix 0032972 before indroducing autoinvoke then?

regs

2018-01-20 20:15

reporter   ~0105961

Maybe. But that's quite difficult to dig in.

Ondrej Pokorny

2018-01-21 09:59

developer   ~0105977

BTW. this feature is called Identifier Completion, not Code Completion. Code Completion is invoked with Ctrl+Shift+C: http://wiki.lazarus.freepascal.org/Lazarus_IDE_Tools#Code_Completion

Martin Friebe

2018-07-16 00:56

manager   ~0109507

First of all, really nice feature.

But a couple of notes:


1) I am missing an option to set the time for the new HintDelayInMSec
I can see it will be saved and loaded to/from the xml, but I do not see any of the options frames allowing to config it.


2) You did not mention the addition of keywords in your description.
Nice feature too, but if possible: separate patch. (The changes inside of codetools itself may be handled by a different developer / So the rest of my comments ignores identcompletiontool.pas)

about keywords: from a quick test, they only appear in the list, if the caret is at the begin of a new statement?
Makes sense for "begin", but "xor" would have to only appear in expressions (never at the start)
Have not gone through the entire list. So there may be more.


3) After cancelling a completion, if I press cursor-left, and keep typing in the same word, the completion appears again. Same after setting a bookmark. There will be plenty more...

I thought about storing the start x/y of the current word. But that is not easy either. With Syncro and multi-caret, the current word may move (even to diff y pos) while you edit it (and while the caret stays at the end of the word.
The same can happen if the unit is open in 2 source editors. If you edit in the other editor then the entire text + caret in the other move accordingly.

It might be best to have a whitelist of commands that will reactivate the completion. Such as
- whitespace
- ecLeft/Right IF going over none identifier chars
- ec WordLeft/Right if leaving the current word (check in afterCommand hook). Its a bit more work....
- ecUp/Down

If you have a better idea...


Btw, there is a case were it is not re-enabled, but maybe should.
- Start typing
- cancel
- use mouse to position caret into another word
- type => nothing


4) CheckCodeAttribute
Better compare "token" to tkIdentifier or tkSymbol ....
  TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber,
    tkSpace, tkString, tkSymbol, tkDirective, tkIDEDirective,
    tkUnknown);

if Token = ord(tkSymbol) then

Apparently that was already in the old code. Comparing the name should work, at least currently, but using the type would be better.

Issue History

Date Modified Username Field Change
2018-01-20 03:11 regs New Issue
2018-01-20 03:11 regs File Added: autoinvoke.patch
2018-01-20 03:12 regs File Added: autoinvokecc.gif
2018-01-20 06:02 Ondrej Pokorny Relationship added related to 0032972
2018-01-20 06:02 Ondrej Pokorny Note Added: 0105948
2018-01-20 20:15 regs Note Added: 0105961
2018-01-21 09:58 Ondrej Pokorny LazTarget => -
2018-01-21 09:58 Ondrej Pokorny Summary Autoinvoke Code Completion on type => Autoinvoke Identifier Completion on type
2018-01-21 09:58 Ondrej Pokorny Description Updated View Revisions
2018-01-21 09:58 Ondrej Pokorny Additional Information Updated View Revisions
2018-01-21 09:59 Ondrej Pokorny Note Added: 0105977
2018-01-21 09:59 Ondrej Pokorny Additional Information Updated View Revisions
2018-07-16 00:56 Martin Friebe Note Added: 0109507