24.2.9 Major Mode Examples

Text mode is perhaps the simplest mode besides Fundamental mode. Here are excerpts from text-mode.el that illustrate many of the conventions listed above:

;; Create the syntax table for this mode.
(defvar text-mode-syntax-table
  (let ((st (make-syntax-table)))
    (modify-syntax-entry ?\" ".   " st)
    (modify-syntax-entry ?\\ ".   " st)
    ;; Add 'p' so M-c on 'hello' leads to 'Hello', not 'hello'.
    (modify-syntax-entry ?' "w p" st)
    …
    st)
  "Syntax table used while in `text-mode'.")

;; Create the keymap for this mode.
(defvar-keymap text-mode-map
  :doc "Keymap for `text-mode'.
Many other modes, such as `mail-mode' and `outline-mode', inherit all
the commands defined in this map."
  "C-M-i" #'ispell-complete-word)

Here is how the actual mode command is defined now:

(define-derived-mode text-mode nil "Text"
  "Major mode for editing text written for humans to read.
In this mode, paragraphs are delimited only by blank or white lines.
You can thus get the full benefit of adaptive filling
 (see the variable `adaptive-fill-mode').
\\{text-mode-map}
Turning on Text mode runs the normal hook `text-mode-hook'."
  (setq-local text-mode-variant t)
  (setq-local require-final-newline mode-require-final-newline))

The three Lisp modes (Lisp mode, Emacs Lisp mode, and Lisp Interaction mode) have more features than Text mode and the code is correspondingly more complicated. Here are excerpts from lisp-mode.el that illustrate how these modes are written.

Here is how the Lisp mode syntax and abbrev tables are defined:

;; Create mode-specific table variables.
(define-abbrev-table 'lisp-mode-abbrev-table ()
  "Abbrev table for Lisp mode.")

(defvar lisp-mode-syntax-table
  (let ((table (make-syntax-table lisp--mode-syntax-table)))
    (modify-syntax-entry ?\[ "_   " table)
    (modify-syntax-entry ?\] "_   " table)
    (modify-syntax-entry ?# "' 14" table)
    (modify-syntax-entry ?| "\" 23bn" table)
    table)
  "Syntax table used in `lisp-mode'.")

The three modes for Lisp share much of their code. For instance, Lisp mode and Emacs Lisp mode inherit from Lisp Data mode and Lisp Interaction Mode inherits from Emacs Lisp mode.

Amongst other things, Lisp Data mode sets up the comment-start variable to handle Lisp comments:

  (setq-local comment-start ";")
  …

Each of the different Lisp modes has a slightly different keymap. For example, Lisp mode binds C-c C-z to run-lisp, but the other Lisp modes do not. However, all Lisp modes have some commands in common. The following code sets up the common commands:

(defvar-keymap lisp-mode-shared-map
  :parent prog-mode-map
  :doc "Keymap for commands shared by all sorts of Lisp modes."
  "C-M-q" #'indent-sexp
  "DEL" #'backward-delete-char-untabify)

And here is the code to set up the keymap for Lisp mode:

(defvar-keymap lisp-mode-map
  :doc "Keymap for ordinary Lisp mode.
All commands in `lisp-mode-shared-map' are inherited by this map."
  :parent lisp-mode-shared-map
  "C-M-x" #'lisp-eval-defun
  "C-c C-z" #'run-lisp)

Finally, here is the major mode command for Lisp mode:

(define-derived-mode lisp-mode lisp-data-mode "Lisp"
  "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
Commands:
Delete converts tabs to spaces as it moves back.
Blank lines separate paragraphs.  Semicolons start comments.

\\{lisp-mode-map}
Note that `run-lisp' may be used either to start an inferior Lisp job
or to switch back to an existing one."
  (setq-local find-tag-default-function 'lisp-find-tag-default)
  (setq-local comment-start-skip
              "\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
  (setq imenu-case-fold-search t))