Emacs Faces - Using Overlays

February 4, 2009 by John Jenkins · Leave a Comment
Filed under: Emacs 

I mentioned last time that (add-text-properties ...) doesn’t usually work in a buffer with font-lock activated. How then can we highlight keywords in the general case?

I didn’t know the answer myself before I started implementing article mode, so I looked at a minor mode that does correctly highlight words in a font-locked buffer - flyspell-mode I opened the code by typing C-h f flyspell-mode<RET> and then clicking on the `flyspell.el' part of the resultant document.

flyspell uses overlays to highlight misspelled and duplicate words. It specifies the properties of the highlights using defface. You can see in the code below I’m a lazy commenter.

(defvar am-overlays nil)

(defface article-keyword-face
  '((((class color)) (:background "yellow" :foreground "black" :bold t))
     (t (:bold t)))
  "Article mode keyword face")

Let me explain defface as I found the relevant emacs manual section slightly confusing on first reading. A face can appear differently depending on the properties of the terminal it is displayed on. e.g. a vt100 terminal won’t have colours available whereas a GUI will.

I’ve highlighted a couple of sections here - ((class color)) means the face will look like this on a colour terminal. The (t …) section is a fall through and matches if nothing else did.


(defun am-add-overlay (begin end)
  (let ((overlay (make-overlay begin end)))
    (overlay-put overlay 'face 'am-keyword-face)
    (push overlay am-overlays)))

(defun am-delete-overlays ()
  (dolist (overlay am-overlays)
    (delete-overlay overlay))
  (setq am-overlays nil))

Okay, here I’ve defined functions to highlight a single region and to delete all overlays as this will tie in well with the original functions that made similar calls to (add-text-properties ...) and (remove-text-properties ...)


You can see how the new functions substituted in (am-highlight-keywords) and (am-remove-highlight) below.

Before

    (while (re-search-forward am-keywords-regex nil t)
      (add-text-properties (match-beginning 1)
                           (match-end 1)
                           '(face highlight)))

After

    (while (re-search-forward am-keywords-regex nil t)
      (am-add-overlay (match-beginning 1) (match-end 1)))

Before

(defun am-remove-highlight ()
  (remove-text-properties (point-min) (point-max) '(face highlight))

After

(defun am-remove-highlight ()
  (am-delete-overlays)

Here is the new article-mode.

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!