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:

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

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

    ReplyDelete
  3. 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.

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

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

    ReplyDelete
  6. 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.

    ReplyDelete
  7. @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

    ReplyDelete
  8. 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.

    ReplyDelete
  9. @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

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

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

    thanks djcb.

    ReplyDelete
  11. I keep getting an error with the example:

    Wrong type argument: sequencep, \,

    ReplyDelete