I briefly mentioned dabbrev expand in one of my interesting links posts when I noted a post that was covering auto-complete.el. Dabbrev expand is a great little feature of emacs. With one keychord, you can expand text using any match from any buffer that you have opened. Until now, I haven’t particularly wanted more.
However, now it is time to move to auto-complete. It’s nice to get feedback about potential completions. In the linked post, it states that auto-complete is just a framework and it needs quite a bit of tweaking to get the behaviour I want.
The primary thing I want to fix is that by default it only uses completions from the current buffer. I like completion to use all open buffers as dabbrev does by default. I thought that it would be easy to add this by setting ac-sources
to ac-source-words-in-all-buffer
.
(setq-default ac-sources '(ac-source-words-in-all-buffer))
Unfortunately, that isn’t come close to what I want. There is also an extension called ac-dabbrev.el but that doesn’t work for me either. Fortunately, it is fairly easy to fix myself.
We can use functions from dabbrev to get all of the possible dabbrev expansions.
(require 'cl)
(require 'dabbrev)
(require 'auto-complete)
(defun ac-source-dabbrev (abbrev)
(interactive)
(dabbrev--reset-global-variables)
(let ((dabbrev-check-all-buffers t))
(sort (dabbrev--find-all-expansions abbrev t) #'string<)))
auto-complete
allows you to list multiple sources for completions in ac-sources. Here we just want one but I could see that it might be nice to add language keywords or something like that.
(defvar ac-source-dabbrev-words
'((candidates
. (lambda () (all-completions ac-target
(ac-source-dabbrev ac-target)))))
"Get all the completions using dabbrev")
(setq-default ac-sources '(ac-source-dabbrev-words))
I prefer to manually start completion rather than have it trigger automatically.
(setq ac-auto-start nil)
(global-set-key (kbd "M-/") 'ac-start)
There is a keymap you can add your own keys to. By default, C-g
doesn’t cancel the completion window which feels really strange to me. In emacs C-g
is pervasive for cancelling options. Fortunately, it is pretty easy to fix that.
(define-key ac-complete-mode-map (kbd "M-x") 'execute-extended-command)
(define-key ac-complete-mode-map (kbd "C-n") 'ac-next)
(define-key ac-complete-mode-map (kbd "C-p") 'ac-previous)
(define-key ac-complete-mode-map (kbd "C-g") 'ac-stop)
I like both RETURN
and TAB
for completion.
(define-key ac-complete-mode-map "\t" 'ac-complete)
(define-key ac-complete-mode-map "\r" 'ac-complete)
I want completions to update as you type. Did you know that by adding a vector to a keymap, you can capture all ascii keypresses?
(defun ac-self-insert ()
(interactive)
(self-insert-command 1)
(ac-start))
;; (define-key ac-complete-mode-map [t] 'ac-self-insert)
However, [t]
also absorbs other ASCII keypresses you’ve defined such as TAB
and RETURN
. Therefore, we have to define them all individually.
(defun ac-fix-keymap ()
(let ((i 32))
(while (<= i ?z)
(define-key ac-complete-mode-map
(make-string 1 i) 'ac-self-insert)
(incf i))))
(ac-fix-keymap)
I also want DELETE
to trigger a new completion update.
(define-key ac-complete-mode-map (kbd "DEL")
(lambda ()
(interactive)
(backward-delete-char-untabify 1)
(ac-start)))
(provide 'auto-complete-config)
Read Full Post »