Emacs Lisp: How to Write Keyword Completion Command

Buy Xah Emacs Tutorial. Master emacs benefits for life.
, , …,

This page shows you how to implement keyword completion in emacs.


xlsl-keyword completion
Keyword completion in emacs.


Suppose your language xyz has the following list of keywords.

;; this is your lang's keywords
(setq xyz-kwdList

The following is the code that does the completion.

(defun xyz-complete-symbol ()
  "Perform keyword completion on word before cursor."
  (let ((posEnd (point))
        (meat (thing-at-point 'symbol))

    ;; 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)
          ((not (string= meat maxMatchResult))
           (delete-region (- posEnd (length meat)) posEnd)
           (insert maxMatchResult))
          (t (message "Making completion list…")
             (with-output-to-temp-buffer "*Completions*"
                (all-completions meat xyz-kwdList)
             (message "Making completion list…%s" "done")))))

Now, to test it, just set a temp key for easy call:

(global-set-key (kbd "<f7>") 'xyz-complete-symbol)

Then, open a new buffer, type any letter, say “t”, then press F7, type some more letter, press F7 again.

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-completion, all-completions, display-completion-list.

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

The keyword list can also be a hash table. See: Emacs Lisp Tutorial: Hash Table.

(info "(elisp) Completion")

Using ido for Completion

A alternative mechanism of completion is to use ido-mode's interface.

emacs keyword completion ido
emacs keyword completion with ido

Here's a example.

;; this is your lang's keywords
(setq abc-kwdList

(defun abc-complete-symbol ()
  "Perform keyword completion on current symbol.
This uses `ido-mode' user interface for completion."
  (let* (
         (ξbds (bounds-of-thing-at-point 'symbol))
         (ξp1 (car ξbds))
         (ξp2 (cdr ξbds))
          (if  (or (null ξp1) (null ξp2) (equal ξp1 ξp2))
            (buffer-substring-no-properties ξp1 ξp2)))
    (when (not ξcurrent-sym) (setq ξcurrent-sym ""))
    (setq ξresult-sym
          (ido-completing-read "" abc-kwdList nil nil ξcurrent-sym ))
    (delete-region ξp1 ξp2)
    (insert ξresult-sym)))

This is much more convenient.

Like it? Buy Xah Emacs Tutorial.
blog comments powered by Disqus