Tassilo’s Blog

The personal blog of Tassilo Horn

Using TAB to complete and indent

with 17 comments

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)))
         (t
          (indent-according-to-mode))))

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.

Written by Tassilo Horn

December 2, 2006 at 8:41 pm

Posted in Emacs

17 Responses

Subscribe to comments with RSS.

  1. Never touched dabbrev, always used pabbrev (which shows some preview of a possible completion; see http://homepages.cs.ncl.ac.uk/phillip.lord/download/emacs/pabbrev.el). Thought about using your code with pabbrev, until I noticed it already seems to do something similar.

    Schimmi

    December 2, 2006 at 9:22 pm

  2. 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.

    Tassilo Horn

    December 2, 2006 at 9:51 pm

  3. 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…

    Paul Huff

    December 5, 2006 at 3:11 am

  4. 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!

    Nate

    December 12, 2006 at 4:48 pm

  5. @Nate:

    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)))

    Tassilo Horn

    December 12, 2006 at 5:34 pm

  6. Thanks! Works great now.

    Nate

    December 12, 2006 at 6:18 pm

  7. 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?

    Fernando

    January 5, 2007 at 7:08 am

  8. 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…

    Tassilo Horn

    January 5, 2007 at 1:38 pm

  9. 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…

    Armen

    January 5, 2007 at 4:05 pm

  10. 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 \\(?:\\>\\|\\(?:[].,;:#=?()[{}]\\)\\).

    Tassilo Horn

    January 5, 2007 at 4:34 pm

  11. This makes my life so much better….

    Armen

    January 5, 2007 at 4:59 pm

  12. 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.

    Fernando

    January 5, 2007 at 7:20 pm

  13. Another alterative can be found on Ryan McGeary’s Blog: http://www.emacsblog.org/2007/03/12/tab-completion-everywhere/

    Tassilo Horn

    March 12, 2007 at 8:36 pm

  14. Peace people

    We love you

    HelloWorld

    April 28, 2007 at 2:18 pm

  15. Hi.
    Good design, who make it?

    naisioxerloro

    November 28, 2007 at 3:42 pm

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

    Tassilo Horn

    November 28, 2007 at 4:20 pm

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

    Jacob

    May 15, 2009 at 2:21 am


Leave a Reply