This page shows you how to implement computer language keyword completion in emacs. You should know the basics of writing a major mode. If not, see: How to Write a Emacs Major Mode for Syntax Coloring.
You are writing a emacs major mode for your own language. You want to have a keyword completion feature, so that user can press a key and have the word under cursor automatically expanded to the possible keywords of the language.
The basic concept of keyword completion is pretty simple. You begin with a list of keywords, and you are given a string that you want to complete. You match the string against the keywords, find the maximal match, then replace the current word with that max match. However, you will also need to pop-up a list of possible completions for the user to choose, and allow user some user interface conveniences such as clicking on one of the choices.
Suppose your language xyz has the following list of keywords.
;; this is your lang's keywords (setq xyz-kwdList '("touch" "touch_start" "touch_end" "for" "foreach" "forall" ))
The following is the code that does the completion.
(defun xyz-complete-symbol () "Perform keyword completion on word before cursor." (interactive) (let ((posEnd (point)) (meat (thing-at-point 'symbol)) maxMatchResult) ;; when nil, set it to empty string, so user can see all lang's keywords. ;; if not done, try-completion on nil result lisp error. (when (not meat) (setq meat "")) (setq maxMatchResult (try-completion meat xyz-kwdList)) (cond ((eq maxMatchResult t)) ((null maxMatchResult) (message "Can't find completion for “%s”" meat) (ding)) ((not (string= meat maxMatchResult)) (delete-region (- posEnd (length meat)) posEnd) (insert maxMatchResult)) (t (message "Making completion list…") (with-output-to-temp-buffer "*Completions*" (display-completion-list (all-completions meat xyz-kwdList) meat)) (message "Making completion list…%s" "done"))) ) )
The above code is very easy to understand. First, you grab the word before cursor, save it as “meat”. Then, you find the maximal match, save it as maxMatchResult. Then, we have a few cases:
Lucky for us, emacs does most of the tedious job. The core functions that do the job is
try-completionreturns the maximal match.
all-completionsreturns all possible completions.
display-completion-listtakes care of the user interface for displaying the possible completions, and making them clickable.
Set a keyboard shortcut for your completion function, so that you can easily test it. ⁖
(global-set-key (kbd "<f6>") 'xyz-complete-symbol). When you are ready to put the code in your major mode, make sure you assign it a key
(kbd "M-TAB"). That key is emacs's convention for doing keyword completion.
In the above, we used a simple list for our keywords, and fed them to emacs's completion functions. Emacs's completion functions can also take keyword argument in the form of a alist or hashtable. A alist looks like this:
(setq xyz-kwdList '(("touch" . nil) ("touch_start" . nil) ("touch_end" . nil)))
For hash, see: Emacs Lisp Tutorial: Hash Table.
(info "(elisp) Completion")
Emacs is beautiful.