From: Xah Lee
Subject: tutorial: Implementing Keyword Completion in Emacs
Date: 
Message-ID: <a888bc79-0a13-476a-90f5-6fa4f8998f83@l33g2000pri.googlegroups.com>
A new page of my emacs lisp tutorial:

• How To Implement Keyword Completion in Emacs
  http://xahlee.org/emacs/elisp_keyword_completion.html

plain text version follows. Your comment welcome.

--------------------------------------------------
How To Implement Keyword Completion in Emacs

Xah Lee, 2009-03-06

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.

The Problem

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.
xlsl-keyword completion

Solution

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 tha max match. However, you
will also need to popup 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 completion on word under cursor."
  (interactive)
  (let* (
         (cusorPoint (point))
         (meat (thing-at-point 'symbol))
         (maxMatchResult (try-completion meat xyz-kwdList))
         )
    (when meat
      (cond ((eq maxMatchResult t))
            ((null maxMatchResult)
             (message "Can't find completion for “%s”" meat)
             (ding))
            ((not (string= meat maxMatchResult))
             (delete-region (- cusorPoint (length meat)) cusorPoint)
             (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:

    * (1) If the max match is the same as the word under cursor, then
do nothing, because the word is already complete.
    * (2) If the max match is empty, then tell user there is no
completion.
    * (3) If not the above two cases, then expand the current word to
max match.
    * (4) Otherwise, pop up a dialog to list possible completions.

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”.

    * The “try-completion” returns the maximal match.
    * The “all-completions” returns all possible completions.
    * The “display-completion-list” takes 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. e.g. “(global-set-key (kbd "<f1>") 'xyz-complete-
symbol)”.

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: Elisp Lesson: Hash Table.

(info "(elisp)Completion")

Emacs is beautiful.

  Xah
∑ http://xahlee.org/

☄