2010-04-18

creating custom modes the easy way with generic-mode

Syntax highlighting is useful when editing configuration files, programs and so on, as it helps to prevent errors and makes it easier to quickly scan documents.

Emacs supports syntax highlighting (font locking in emacs lingo) for many different file types. For many common cases (e.g. editing for many programming languages, org-mode), emacs' support goes much further than merely colorizing keywords, and offers all kinds of 'magic' (auto-completion, 'electricity', special key bindings, …). For some other file types, at least keywords are given some different color.

Still, there are files that are not recognized by emacs as having some special format; these are displayed as plain text. This may be the case for less-common configuration files, or your own specific formats.

Defining a full 'mode' for such file types can be a lot of work. Fortunately, emacs offers a easier way: generic-mode. generic-mode defines a whole lot of mode of modes for common formats, but also defines the define-generic-mode macro to create your own modes.

Suppose we have a little language called foo; a typical foo-file might look something like:

!! this is a comment
account=foo; !! another comment
user=jimmy;
password=$3cre7;

Using define-generic-mode, we can easily define a mode for this:

(require 'generic-x) ;; we need this

(define-generic-mode 
  'foo-mode                         ;; name of the mode to create
  '("!!")                           ;; comments start with '!!'
  '("account" "user" 
    "password")                     ;; some keywords
  '(("=" . 'font-lock-operator)     ;; '=' is an operator
    (";" . 'font-lock-builtin))     ;; ';' is a a built-in 
  '("\\.foo$")                      ;; files for which to activate this mode 
   nil                              ;; other functions to call
  "A mode for foo files"            ;; doc string for this mode
)

Now, this will look something like this (if necessary, see the colorized version):

!! this is a comment
account = foo; !! another comment
user = jimmy;
password = $3cre7;

11 comments:

vinhdizzo said...

wow awesome. always thought creating a mode would require a lot of lisp but this makes the task do-able at least from my end.

luckily I've always found a mode for whatever I needed to.

Rasmus Toftdahl Olesen said...

Terrific post, thanks, defining a mode now sounds much more doable than before.

Sébastien said...

Thanks a lot for this post.
I've searched for a while how to add comments in text-mode. Your code does the job perfectly.

Chris Thiel said...

How does it know what the comments and keywords are? Is it just which order that you specify the arguments to define-generic-mode?

Jeff Miller said...

Thanks for this post. It was hugely helpful, and your example was spot-on.

Lalit said...

thanks for such useful blog. i am also big fan of emacs :-)

i am creating a emacs mode for cpf langauge. this is the command format of cpf file.

define_library_set -name set2_bc -libraries lib3_bc
define_library_set -name set2_wc -libraries lib3_wc
define_library_set -name set3_bc -libraries lib4_bc

i am not able to highlight -name and -libraries in command file. can u help in this regard.

djcb said...

@lalit: if i change the example with something like:

================================
(define-generic-mode
'foo-mode ;; name of the mode to create
'("!!") ;; comments start with '!!'
'("-name" "-libraries")
'(("=" . 'font-lock-operator) ;; '=' is an operator
(";" . 'font-lock-builtin)) ;; ';' is a a built-in
'("\\.foo$") ;; files for which to activate this mode
nil ;; other functions to call
"A mode for foo files" ;; doc string for this mode
)
================================

I can see the colorized -name and -libraries

Lalit said...

its a bit obvious solution :-)
In this particular language, there is lots of commands and they have many options like name, libraries etc. all options start with "-" like -name and -libraries. so i was trying to find some regular expression for searching all words starting with "-" and ending with white space. then coloring them all. i dont know much about lisp regular exp.

djcb said...

@lalit: note that the list of keywords are simple strings, not regexps. It may good to write down the full list of keywords rather than using a regexp; a regexp would would match non-keywords ("-foobar") as well.

For regexps, M-x re-builder is an easy way to figure them out.

Also: C-h g define-generic-mode

Lalit said...

after doing some trial and error finally i find this :-)

("[-][a-z_]+" . 'font-lock-type-face) ;; -option highlight

thanks djcb.

Anonymous said...

I keep getting an error with the example:

Wrong type argument: sequencep, \,