Question

I'm trying to get tab complete within all open buffers and yasnippet to both work with the tab key. At the moment I can have one or the other. The following code is how I'm handling the yasnippet expand, but as I'm not a lisp programmer I cannot see the mistake here.

If it cannot expand the snippet I would like it to try and expand from the buffer.

;; Auto complete settings / tab settings
;; http://emacsblog.org/2007/03/12/tab-completion-everywhere/ <-- in the comments
(global-set-key [(tab)] 'smart-tab)
(defun smart-tab ()
  "This smart tab is minibuffer compliant: it acts as usual in
    the minibuffer. Else, if mark is active, indents region. Else if
    point is at the end of a symbol, expands it. Else indents the
    current line."
  (interactive)
  (if (minibufferp)
      (unless (minibuffer-complete)
        (dabbrev-expand nil))
    (if mark-active
        (indent-region (region-beginning)
                       (region-end))
      (if (looking-at "\\_>")
          (unless (yas/expand)
            (dabbrev-expand nil))
        (indent-for-tab-command)))))
Was it helpful?

Solution

First, I try to understand what the code does, and what you would like it does.

Your code

  • first checks if the point is in the minibuffer.

    • If so, then it tries to complete the minibuffer

      • if (in minibuffer) cannot complete it, it calls dabbrev-expand
  • else if the point is not in minibuffer

    • if some region is marked , it indents the region.

    • if no mark is active, it checks to see if the point is at the end of some word

      • if so, it checks is yasnippet can expand.

        • if yas cannot expand, it calls dabbrev-expand
      • if not, it tries to indent the current line

This is what your code does.

Your code fails due to yas/expand. This command does not return in case the expansion fails.

In case that this command fails, it checks the state of the variable yas/fallback-behavior. If this variable has the value call-other-command, as in your case, the failed yas expansion calls the command bound to the key kept in the variable yas/trigger-key.

In your case , this variable is TAB.

So: You are at the end of the word, You press TAB to complete it, this triggers the interactive smart-tab, which calls yas/expand which in case it fails to expand calls the bound function of TAB, and here is the infinite loop.

The Solution for your problem is to temporaily bound nil to yas/fallback-behavior in this smart-tab function.

Here is how to fix it:

(if (looking-at "\\_>")
      (let ((yas/fallback-behavior nil))
        (unless (yas/expand)
          (dabbrev-expand nil)))
    (indent-for-tab-command))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top