Previous: Generic Modes, Up: Major Modes

23.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 text-mode-map
       (let ((map (make-sparse-keymap)))
         (define-key map "\e\t" 'ispell-complete-word)
         map)
       "Keymap for `text-mode'.
     Many other modes, such as `mail-mode', `outline-mode' and
     `indented-text-mode', inherit all the commands defined in this map.")

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'."
       (set (make-local-variable 'text-mode-variant) t)
       (set (make-local-variable 'require-final-newline)
            mode-require-final-newline)
       (set (make-local-variable 'indent-line-function) 'indent-relative))

(The last line is redundant nowadays, since indent-relative is the default value, and we'll delete it in a future version.)

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.
     (defvar lisp-mode-abbrev-table nil)
     (define-abbrev-table 'lisp-mode-abbrev-table ())
     
     (defvar lisp-mode-syntax-table
       (let ((table (copy-syntax-table emacs-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, each calls the following function to set various variables:

     (defun lisp-mode-variables (&optional syntax keywords-case-insensitive)
       (when syntax
         (set-syntax-table lisp-mode-syntax-table))
       (setq local-abbrev-table lisp-mode-abbrev-table)
       ...

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

       (make-local-variable 'comment-start)
       (setq 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 lisp-mode-shared-map
       (let ((map (make-sparse-keymap)))
         (define-key map "\e\C-q" 'indent-sexp)
         (define-key map "\177" 'backward-delete-char-untabify)
         map)
       "Keymap for commands shared by all sorts of Lisp modes.")

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

     (defvar lisp-mode-map
       (let ((map (make-sparse-keymap))
     	(menu-map (make-sparse-keymap "Lisp")))
         (set-keymap-parent map lisp-mode-shared-map)
         (define-key map "\e\C-x" 'lisp-eval-defun)
         (define-key map "\C-c\C-z" 'run-lisp)
         ...
         map)
       "Keymap for ordinary Lisp mode.
     All commands in `lisp-mode-shared-map' are inherited by this map.")

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

     (define-derived-mode lisp-mode prog-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.
     
     Entry to this mode calls the value of `lisp-mode-hook'
     if that value is non-nil."
       (lisp-mode-variables nil t)
       (set (make-local-variable 'find-tag-default-function)
            'lisp-find-tag-default)
       (set (make-local-variable 'comment-start-skip)
            "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
       (setq imenu-case-fold-search t))