Hello - In ESS, we have 'ess-first-tab-never-complete' which governs whether TAB offers completion. The gist of it is that if you're in a buffer (with | representing point): (def|var foo) and you hit TAB, you might not want completion offered. I've put together a patch that incorporates this into Emacs by adding a new defcustom `tab-first-completion'. The values are currently based on ESS's implementation, though we can certainly change that if we want. Perhaps it should be a function that receives one argument (position) and if it returns non-nil, then we complete? Is this something people would be interested in adding? Thanks, Alex From eb4c1a9c8bcd2f5018150b0502e8ed945c181e74 Mon Sep 17 00:00:00 2001 From: Alex Branham Date: Fri, 8 Mar 2019 12:09:04 -0600 Subject: [PATCH] New defcustom tab-first-completion * lisp/indent.el (tab-always-indent): Mention 'tab-first-completion'. (tab-first-completion): New defcustom. (indent-for-tab-command): Use 'tab-first-completion'. Bug# --- lisp/indent.el | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/lisp/indent.el b/lisp/indent.el index 34757a43d7..08087effa6 100644 --- a/lisp/indent.el +++ b/lisp/indent.el @@ -51,6 +51,7 @@ If nil, hitting TAB indents the current line if point is at the left margin or in the line's indentation, otherwise it inserts a \"real\" TAB character. If `complete', TAB first tries to indent the current line, and if the line was already indented, then try to complete the thing at point. +See also `tab-first-completion'. Some programming language modes have their own variable to control this, e.g., `c-tab-always-indent', and do not respect this variable." @@ -60,6 +61,27 @@ e.g., `c-tab-always-indent', and do not respect this variable." (const :tag "Indent if inside indentation, else TAB" nil) (const :tag "Indent, or if already indented complete" complete))) +(defcustom tab-first-completion nil + "Governs the behavior of TAB completion on the first press of the key. +When nil, complete. When `eol', only complete if point is at the +end of a line. When `word', complete unless the next character +has word syntax (according to `syntax-after'). When +`word-or-paren', complete unless the next character is part of a +word or a parenthesis. When `word-or-paren-or-punct', complete +unless the next character is part of a word, parenthesis, or +punctuation. Typing TAB a second time always results in +completion. + +This variable has no effect unless `tab-always-indent' is `complete'." + :group 'indent + :type '(choice + (const :tag "Always complete" nil) + (const :tag "Unless at the end of a line" 'eol) + (const :tag "Unless looking at a word" 'word) + (const :tag "Unless at a word or parenthesis" 'word-or-paren) + (const :tag "Unless at a word, parenthesis, or punctuation." 'word-or-paren-or-punct)) + :version "27.1") + (defun indent-according-to-mode () "Indent line in proper way for current major mode. @@ -111,7 +133,7 @@ or performs symbol completion, depending on `tab-always-indent'. The function called to actually indent the line or insert a tab is given by the variable `indent-line-function'. -If a prefix argument is given, after this function indents the +If a prefix argument is given (ARG), after this function indents the current line or inserts a tab, it also rigidly indents the entire balanced expression which starts at the beginning of the current line, to reflect the current line's indentation. @@ -139,7 +161,8 @@ prefix argument is ignored." (t (let ((old-tick (buffer-chars-modified-tick)) (old-point (point)) - (old-indent (current-indentation))) + (old-indent (current-indentation)) + (syn (syntax-after (point)))) ;; Indent the line. (or (not (eq (indent--funcall-widened indent-line-function) 'noindent)) @@ -152,7 +175,18 @@ prefix argument is ignored." ;; If the text was already indented right, try completion. ((and (eq tab-always-indent 'complete) (eq old-point (point)) - (eq old-tick (buffer-chars-modified-tick))) + (eq old-tick (buffer-chars-modified-tick)) + (or (null tab-first-completion) + (eq last-command this-command) + (and (equal tab-first-completion 'eol) + (eolp)) + (and (member tab-first-completion '(word word-or-paren word-or-paren-or-punct)) + (not (member 2 syn))) + (and (member tab-first-completion '(word-or-paren word-or-paren-or-punct)) + (not (or (member 4 syn) + (member 5 syn)))) + (and (equal tab-first-completion 'word-or-paren-or-punct) + (not (member 1 syn))))) (completion-at-point)) ;; If a prefix argument was given, rigidly indent the following -- 2.19.2