I am addicted to tab completion in the minibuffer and in shells like bash — so much so that I want it everywhere. By default, emacs comes with dabbrev-expand (bound to M-/). When invoked after typing the first few letters of a word, dabbrev-expand first searches the current buffer and then other open buffers for possible completions. Completions are expanded inline on each subsequent call. This is pretty close to what we want, but it’s not the TAB key. We could rebind dabbrev-expand to TAB, but then how would we indent a line? Let’s apply a little bit of elisp smarts.
1 2 3 4 5 6 7 8 9 | (defun indent-or-expand (arg) "Either indent according to mode, or expand the word preceding point." (interactive "*P") (if (and (or (bobp) (= ?w (char-syntax (char-before)))) (or (eobp) (not (= ?w (char-syntax (char-after)))))) (dabbrev-expand arg) (indent-according-to-mode))) |
If we’re at the end of a word boundary, this function invokes dabrev-expand; otherwise, indent-according-to-mode. To avoid errors, the bobp and eobp calls are there to make sure we’re not looking for characters before or after the buffer’s boundary. An interactive prefix argument is optional and is passed directly to dabbrev (C-h f dabbrev-expand for more info).
A positive prefix argument, N, says to take the Nth backward distinct possibility. A negative argument says search forward.
I find that this makes for some wicked-cool behavior. For me, it seems intuitive and natural. But wait, we haven’t bound this to TAB yet. Let’s do that now.
1 2 3 4 5 6 7 | (defun my-tab-fix () (local-set-key [tab] 'indent-or-expand)) (add-hook 'c-mode-hook 'my-tab-fix) (add-hook 'sh-mode-hook 'my-tab-fix) (add-hook 'emacs-lisp-mode-hook 'my-tab-fix) ;; more mode hooks, yada yada, etc ... |
To avoid strange behavior in the minibuffer and other special buffers, it is necessary to rebind TAB only in local modes. I’m sure there is a smarter/cleaner way to do this by instead excluding only the problematic buffers or modes, but I’ll leave that as an exercise for the reader (please post a comment if you have a solution though).
Credits: While I’ve had this nugget in my .emacs for a very long time, I cannot take credit for it. I’ve seen similar solutions in several places, and while I tweaked it a bit myself, I originally stole it from someone else. Emacs-Rails takes this approach one step further by also including snippet support.
Hippie Expand Alternative
We used dabbrev-expand above, but I am considering changing that to hippie-expand instead. Hippie Expand is more powerful, but might require some customization to suit to your liking. I’m not ready for groovy vans or tie-dye, so we’ll have to talk about the details of Hippie Expand sometime later.
11 responses so far ↓
Nice tip! A similar trick I’ve used is to first run the indent function, then try completion only if it didn’t change anything. i.e. something like this:
Thanks for this topic, I look forward to a future dabbrev-expand or hippie-expand topic.
M-:(eval-expression) has keyword completion, but atM-TAB. Since I am Windows user that prefers using Alt for Meta, I cannot use it (Alt-Tab is grabbed by the OS). So since I useM-:frequently, I use Tab for completion. I found that the following keymapping works for me:One thing that drives me crazy:
You know how in bash, you can copy a path, then go somewhere in the middle of that string to change an ancestor. When you hit tab, it completes.
In emacs (under windows at least), when I go to find a file, does anyone know of a way to get the tab completion working when you are not at the end of the string?
Jeff, What version of Emacs are you running? Granted, I’m on OS X, but under Emacs 22.0.95, my find file minibuffer seems to already work just like bash. In other words, I can tab complete in the minibuffer even if my point is in the middle of a file/directory name.
Thanks ! I never imagined this, but I really like it. Bye M-/
6 Giving ido-mode a Second Chance // May 19, 2008 at 3:59 pm
[...] me off. Today I realized why, and I was finally motivated enough to find a fix. I am a big fan of tab-completion everywhere, so when tab-completion doesn’t work like I expect, I get upset. As it turns out, this is why [...]
I strongly recommend the smart-tab function from http://www.emacswiki.org/cgi-bin/wiki/TabCompletion:
It calls indent-region if the mark is active. Otherwise, it dabbrev-expands if the point is at the end of a symbol. Otherwise, it indents the current line. So, I can indent whole blocks of code by selecting it and pressing TAB (as well as single lines).
The function is also minibuffer compliant.
Nice feature.!
I preferred the version proposed by Marius Andersen, though I removed the dabbrev-expansion for the minibuffer (keeping only minibuffer-complete), since it seems to mostly expand to something useless.
9 I want it my way … « Schemy things, lispy thoughts // May 5, 2009 at 3:54 pm
[...] want it my way … By joelbf The M-x all-things-emacs blog had a post on tab-completion a while ago. It is basically what I need, but I’d like the oportunity to [...]
Hm. This interferes with yasnippet.
No reason why they shouldn’t be able to work together so long as tab-completion is invoked on non-yas-keywords….
I’ll start hacking on it.
11 Emacs autocomplete con tab « Gastón Ramos – Ruby, Rails… // May 22, 2012 at 6:14 pm
[...] disfrutar del autocomplete. La función la saqué de uno de los comentarios de este artículo: http://emacsblog.org/2007/03/12/tab-completion-everywhere/ Like this:LikeBe the first to like this post. Posted by Gastón Ramos Filed in emacs Leave a [...]
Leave a Comment