Using TAB to complete and indent

Posted: December 2, 2006 in Emacs

I’m not a too fast typist, but emacs’ dabbrev-expand makes even me fly. Ok, not as fast as a hawk, but maybe like a quail. ;-)

So it wouldn’t be a bad idea to bind dabbrev-expand to the TAB key, if indenting wasn’t such an important command when programming.

Because I didn’t want to choose between pestilence and cholera, I wrote this function:

(defun th-complete-or-indent (arg)
  "If preceding character is a word character and the following
character is a whitespace or non-word character, then
`dabbrev-expand', else indent according to mode."
  (interactive "*P")
  (cond ((and
          (= (char-syntax (preceding-char)) ?w)
          (looking-at (rx (or word-end (any ".,;:#=?()[]{}")))))
         (require 'sort)
         (let ((case-fold-search t))
           (dabbrev-expand arg)))

Bind this function to the TAB key. Then TAB completes the current word with dabbrev-expand. But if you a not at the end of a word, it will indent according to the current major mode instead.

  1. Schimmi says:

    Never touched dabbrev, always used pabbrev (which shows some preview of a possible completion; see Thought about using your code with pabbrev, until I noticed it already seems to do something similar.

  2. Tassilo Horn says:

    I’ve read the description and it sounds really interesting. One thing which I think is a bit inconvenient is that it openes a separate buffer on the secont TAB hit, so that you can choose another possible completion. Simply cycling through all completions sounds faster. Anyway, I really should give it a try.

  3. Paul Huff says:

    Hmmmm… doesn’t emacs have some kind of overlays or something where you can overlay text over a buffer? I think I remember reading about it in passing in the elisp manual, but maybe I’m smoking crack. Anyway, if it does, you could get it do be all visual-studio-esque by presenting the possibilities in an overlay of some sort…

    But, it seems like cycling through is the best behavior to me, if the overlay thing doesn’t work…

  4. Nate says:

    This is really cool, but it causes problems for me in the minibuffer. When using tab with ido-find-file, it tries to look up abbreviations instead of completing from the list of suggestions ido gives. My elisp skills are very weak. Is there a way I could bind th-tab-or-indent only when I’m NOT in the minibuffer? Thanks!

  5. Tassilo Horn says:


    th-tab-or-indent is meant to be bound in a mode specific manner, not globally. E.g. if you want to use it while programmng in C/C++, add this to your ~/.emacs.
    (add-hook 'c++-mode-hook
    (lambda ()
    (local-set-key "\C-i" 'th-complete-or-indent)))

    (add-hook 'c-mode-hook
    (lambda ()
    (local-set-key "\C-i" 'th-complete-or-indent)))

  6. Nate says:

    Thanks! Works great now.

  7. Fernando says:

    Quick question: this looks great, but I enabled it on my system and added it as a python-mode-hook, but now auto-indenting seems broken. If I now type

    for i in [1,2,3]:

    the next line is not automatically indented. Am I doing something wrong? Is there a way to preserve auto-indentation while getting tab-dabbrev completions?

  8. Tassilo Horn says:

    Hi Fernando,

    I cannot confirm your problems.

    (add-hook 'python-mode-hook
    (lambda ()
    (local-set-key "\C-i" 'th-complete-or-indent)
    (local-set-key (kbd "RET") 'newline-and-indent)))

    works as expected here…

  9. Armen says:

    I’m using Xemacs 21.4.20. I’m getting an undefined on (rx). any idea what to do about this? I’ve done some digging, I think it’s a regxp function…

  10. Tassilo Horn says:

    Hi Armen,

    yeah, `rx’ is a macro for constructing regular expressions in emacs 22. Try replacing the rx-sexp with an equivalent regexp:

    (rx (or word-end (any ".,;:#=?()[]{}"))) stands for the regular expression \\(?:\\>\\|\\(?:[].,;:#=?()[{}]\\)\\).

  11. Armen says:

    This makes my life so much better….

  12. Fernando says:

    Thanks! I have no clue, but I can’t reproduce it again either. I was probably tired last night and made a silly mistake.

    In any case, your reply prompted me to test again, and it’s fine now.

    Fantastic enhancement, since TAB is completely hardwired in my muscle memory by now.

    Thanks again for your help and this little snippet.

  13. HelloWorld says:

    Peace people

    We love you

  14. naisioxerloro says:

    Good design, who make it?

  15. Tassilo Horn says:

    @naisioxerloro: What? `rx’? rx.el is written by Gerd Moellmann.

  16. Jacob says:

    Thanks, I tried pabbrev mode out, but i feel dabbrev does a better job and binding it to the tab key makes life heavenly.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s