Go to the first, previous, next, last section, table of contents.


Writing Minor Modes

Minor modes are generally harder to write properly than major modes since they have to peacefully coexist with all the other minor modes which may also be enabled in a buffer.

Generally each minor mode maintains a buffer-local variable saying whether or not it's installed in the buffer. The minor mode's function usually toggles the mode on or off depending on the state of this variable.

There are two functions which must be used to install and remove a minor mode -- add-minor-mode and remove-minor-mode, see their documentation for details.

Each buffer has a keymap containing the bindings of all the minor modes enabled in the buffer (the variable minor-mode-keymap). These bindings have to be added when the mode is enabled and removed when it is disabled.

Variable: minor-mode-list
This buffer-local variable is a list of all the minor modes enabled in a buffer.

Variable: minor-mode-names
This buffer-local variable contains a list of strings, each string names one of the minor modes currently enabled in the buffer.

Variable: minor-mode-keymap
A buffer-local keymap to be used by minor-modes. This is only created the first time a minor mode calls add-minor-mode in the buffer.

Function: add-minor-mode mode name &optional no-keymap
This function installs a minor mode (the symbol mode) into the current buffer. All minor modes should call this before doing anything drastic.

name is the string to be displayed in the status line as the name of this minor mode.

When no-keymap is nil or undefined this function ensures that the minor-mode-keymap variable has a valid value in this buffer.

Function: remove-minor-mode mode name
Removes a minor mode from the current buffer, the mode and name arguments must have the same value as the arguments given to add-minor-mode when the mode was enabled.

The following code fragment is an example minor mode taken from Jade's source code.

(provide 'fill-mode)

(defvar fill-column 72
  "Position at which the text filling commands break lines.")

(defvar fill-mode-p nil)
(make-variable-buffer-local 'fill-mode-p)

;;;###autoload
(defun fill-mode ()
  "Minor mode for automatically filling lines, i.e. word-wrapping.
This makes the SPC key checks if the cursor is past the fill-column. If
so, the next line is started."
  (interactive)
  (if fill-mode-p
      (progn
        (setq fill-mode-p nil)
        (remove-minor-mode 'fill-mode "Fill")
        (unbind-keys minor-mode-keymap "SPC"))
    (add-minor-mode 'fill-mode "Fill")
    (setq fill-mode-p t)
    (bind-keys minor-mode-keymap
      "SPC" 'fill-mode-spc)))

(defun fill-mode-spc ()
  (interactive)
  (when (> (pos-col (cursor-pos)) fill-column)
    (let
        ((pos (cursor-pos)))
      (set-pos-col pos (1+ fill-column))
      (setq pos (unless (word-start pos) (forward-word -1 pos)))
      (insert "\n" pos)
      (let
          ((end (left-char 1 (copy-pos pos))))
        (when (equal (get-char end) ?\ )
          (delete-area end pos)))))
  (insert " "))


Go to the first, previous, next, last section, table of contents.