25
votes

Recently I've discovered M-x ielm (the Emacs self-REPL) and was pleasantly surprised that there's a working tab-completion in that mode. Say, I can start typing ecb-, then hit TAB and ielm will show me what functions are exposed by ECB. Very convenient for exploration!

However, when I start editing one of my *.el files (in Emacs Lisp major mode), TAB no longer works as autocomplete and performs indentation, which I find unfortunate.

I tried to figure out how autocompletion works within ielm in order to possibly transplant it into Emacs Lisp mode. However, apparently, autocompletion in ielm uses comint-dynamic-complete, which, as far as I understand, works only in comint-based buffers. I guess, this means that I'm out of luck here.

So, well, how do I enable autocompletion for Emacs Lisp?

2

2 Answers

33
votes

In recent versions of Emacs, you can use a little-known piece of built-in functionality which enables TAB completion:

(setq tab-always-indent 'complete)
(add-to-list 'completion-styles 'initials t)

With this setup, TAB - which is usually bound to indent-for-tab-command - first tries to adjust the indentation according to the mode's settings, but if the indentation is already correct, completion is triggered. This is usually the desired behavior, and IMHO works better than third-party plugins like smart-tab.

Note, however, that in some modes, TAB is not bound to indent-for-tab-command, so further rebinding is necessary for those modes, e.g. with smart-tab. Also, when modes have "bounce indent" (e.g. python-mode), this technique will also not work.

3
votes

I find both indenting and completion helpful at times, so I have a function that chooses based on whether the last thing I did was inserting text or not:

(global-set-key [tab] 'indent-or-expand)
(defun indent-or-expand ()
  "Either indent according to mode, or expand the word preceding point."
  (interactive)
  (if (or
       (eq last-command 'self-insert-command)
       (eq last-command 'dabbrev-expand))
      (progn
        (setq this-command 'dabbrev-expand)
        (dabbrev-expand nil))
    (indent-according-to-mode)))

You can probably use comint-dynamic-complete instead of dabbrev if you want, but I find that dabbrev works great for emacs lisp - particularly when combined with completer.el, which can expand even f-f-r-o into find-file-read-only.