Emacs Lisp: Syntax Color Comment in Major Mode

By Xah Lee. Date: . Last updated: .

This page shows how to implement comment coloring for writing a major mode.

emacs doge comment coloring
coloring of comment and string.

Here's the doge text.

-*- coding: utf-8 -*-
         "Wow"

                   ▄              ▄
 such             ▌▒█           ▄▀▒▌
   simple mode    ▌▒▒█        ▄▀▒▒▒▐
                 ▐▄▀▒▒▀▀▀▀▄▄▄▀▒▒▒▒▒▐  # comment
               ▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐
             ▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌
            ▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒▌
            ▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐   # colored
           ▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄▌
"string"   ▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒▌
          ▌▒▀▐▄█▄█▌▄░▀▒▒░░░░░░░░░░▒▒▒▐
          ▐▒▒▐▀▐▀▒░▄▄▒▄▒▒▒▒▒▒░▒░▒░▒▒▒▒▌
          ▐▒▒▒▀▀▄▄▒▒▒▄▒▒▒▒▒▒▒▒░▒░▒░▒▒▐
           ▌▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒░▒░▒░▒░▒▒▒▌
           ▐▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▒▄▒▒▐
 #  colored ▀▄▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▄▒▒▒▒▌
              ▀▄▒▒▒▒▒▒▒▒▒▒▄▄▄▀▒▒▒▒▄▀
     " too      ▀▄▄▄▄▄▄▀▀▀▒▒▒▒▒▄▄▀   too"
                  ▒▒▒▒▒▒▒▒▒▒▀▀     Concern

Problem

You are writing a major mode for a language. You want comment be syntax colored.

(For how to write a command to comment/uncomment, see: Emacs Lisp: How to Write Comment/Uncomment Command for a Major Mode)

Solution

The typical way to syntax color comment is via emacs syntax table. Two things you need to do:

  1. Set syntax table for the comment characters.
  2. Set font-lock-defaults to non-nil.

Comment AND string will then automatically be syntax colored, when font-lock-mode is on. (it is on by default)

Let's do a example.

Say our comment syntax is # to the end of line, used by Ruby, Python, Perl, PHP, Bash.

Here's complete code of a major mode:

;; sample mode that does coloring of python style commment syntax

(defvar xpy-mode-syntax-table nil "Syntax table for `xpy-mode'.")

(setq xpy-mode-syntax-table
      (let ( (synTable (make-syntax-table)))
        ;; python style comment: “# …”
        (modify-syntax-entry ?# "<" synTable)
        (modify-syntax-entry ?\n ">" synTable)
        synTable))

(define-derived-mode xpy-mode prog-mode "xpy"
  "xpy-mode is a major mode for editing language xpy."

  (setq font-lock-defaults (list nil nil))

  (set-syntax-table xpy-mode-syntax-table)
  ;; actually no need, because our syntax table name is “xpy-mode” + “-syntax-table”, so define-derived-mode will find it and set it
  )

Now, copy paste the above into a buffer then call eval-buffer to evaluate the code.

Now, open a new buffer, type the following:

some "thing" # wow

Then, M-x xpy-mode, you see that the string and comment are colored.

How Does Syntax Coloring Works

3 essential things you need to know.

  1. font-lock-mode
  2. font-lock-defaults
  3. syntax table

[see Emacs Lisp: Font Lock Mode Basics]

[see Emacs Lisp: Syntax Table]

Here's the appropriate syntax table setup for popular languages.

C++ Style Comments

Comment style of the form //…

(defvar xcpp-mode-syntax-table nil "Syntax table for `xcpp-mode'.")

(setq xcpp-mode-syntax-table
      (let ( (synTable (make-syntax-table)))
        ;; C++ style comment “// …”
        (modify-syntax-entry ?\/ ". 12b" synTable)
        (modify-syntax-entry ?\n "> b" synTable)
        synTable))

(define-derived-mode xcpp-mode prog-mode "xcpp"
  "xcpp-mode is a major mode for editing language xcpp."
  (setq font-lock-defaults (list nil)))

Java Style Comments

Comment style of the form /*…*/

(defvar xjv-mode-syntax-table nil "Syntax table for `xjv-mode'.")

(setq xjv-mode-syntax-table
      (let ( (synTable (make-syntax-table)))
        ;; comment style “/* … */”
        (modify-syntax-entry ?\/ ". 14" synTable)
        (modify-syntax-entry ?* ". 23" synTable)
        synTable))

(define-derived-mode xjv-mode prog-mode "xjv"
  "xjv-mode is a major mode for editing language xjv."
  (setq font-lock-defaults (list nil)))

Haskell Style Comments

Here's example for comment style of the form

etc.

(defvar xwl-mode-syntax-table nil "Syntax table for `xwl-mode'.")

(setq xwl-mode-syntax-table
      (let ((synTable (make-syntax-table)))
        ;; Wolfram Language style comment “(* … *)”
        (modify-syntax-entry ?\( ". 1" synTable)
        (modify-syntax-entry ?\) ". 4" synTable)
        (modify-syntax-entry ?* ". 23" synTable)
        synTable))

(define-derived-mode xwl-mode prog-mode "xwl"
  "xwl-mode is a major mode for editing language xwl."
  (setq font-lock-defaults (list nil)))

Syntax Table Supports Limited Comment Syntax

Emacs's syntax table only supports comment syntaxes that are used in mainstream languages.

Emacs Syntax Table Support of Comment Syntax Types
ExampleSyntax Type
# …\n (Python, Perl, PHP, Bash, shells)
; …\n (lisp)
' …\n (Visual Basic)
Start with a char to newline char.
// … \n (C, C++, C#, Java, JavaScript, PHP)Start with 2 identical chars to newline char.
(* … *) (Mathematica, Pascal, OCaml, Applescript)
{- … -} (Haskell)
A matching pair chars with another char.
/* … */ (C, C++, C#, Java, JavaScript)Two chars used in a ad hoc way as matching pair.

If your language's comment syntax is not one of the above, then emacs syntax table is not able to capture it.

To handle non-mainstream comment syntax, you have 2 ways:

Now, continue to Emacs Lisp: How to Write Comment/Uncomment Command for a Major Mode