View Issue Details

IDProjectCategoryView StatusLast Update
0033054PatchesPatchpublic2020-09-12 02:16
Reporterregs Assigned ToMartin Friebe  
PrioritynormalSeverityminorReproducibilityN/A
Status resolvedResolutionfixed 
Fixed in Version2.2 
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 Revision63314
LazTarget2.2
Widgetset
Attached Files

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.

Martin Friebe

2020-06-06 17:19

manager   ~0123271

Please test and close if ok.

Implemented in a slightly different way.
- setting is off by default.
- added some settings for tuning

Re-used the "compare attribute name" from the patch.

Did not include codetool changes / Please submit as different issue, if important.

regs

2020-09-12 02:16

reporter   ~0125496

Little bit forgot about it and didn't notice it was implemented in trunk until now. One thing noticed immediately. I've been placing operators on top, because when typing operators, if, do, else etc, pressing space after them would insert something else. Solution is either bring operators atop or bring atop line that is fully equal of typed identifier. Or both of those.

May be little late, but i'll answer on above

1. Well, i split them, as if completion is 0 sec, 0 sec hint would be annoying. This is weird. I use TortoiseSVN for patch generation. Looks like it missed that one lfm file. But i see it's been implemented.

2. That's for a reason above. So typing space after them wouldn't bring something else.

3. Don't really remember now, i'm not sure, but i think i haven't found a way to reset it in case if identifier completely erased. Pretty sure i remember it was working. With current implementation i have to press space then backspace to get it working again. Might be idea, but i haven't found anything back then. Have to look at the code again. I didn't see it as a problem, as in most situations we only need to cancel completion for current typing. Moving cursor any direction meaning we starting over.

4. Same here. I was digging, but haven't found better way back them. Attribution comparison was already there, but rest was parsed right in the function. So instead i made everything rely on attribution, which was better then parsing right in that function. I don't think tokens brought my attention back then.

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
2020-06-06 17:19 Martin Friebe Assigned To => Martin Friebe
2020-06-06 17:19 Martin Friebe Status new => resolved
2020-06-06 17:19 Martin Friebe Resolution open => fixed
2020-06-06 17:19 Martin Friebe Fixed in Version => 2.2
2020-06-06 17:19 Martin Friebe Fixed in Revision => 63314
2020-06-06 17:19 Martin Friebe LazTarget - => 2.2
2020-06-06 17:19 Martin Friebe Note Added: 0123271
2020-09-12 02:16 regs Note Added: 0125496