Emacs: How to Turn a Minor Mode on/off/toggle?

Buy Xah Emacs Tutorial. Master emacs benefits for life.
, , …,

This page is a tutorial on how to turn a emacs mode on, off, or toggle.

When setting a variable that takes {true, false}, use {t, nil}, like this:

(setq make-backup-files nil)

When calling a mode function, use 1 or 0, like this:

(global-linum-mode 1)

Global vs Local Minor Modes

Some minor mode has a command for turning it on/off globally, while others do not. For example, there's linum-mode for toggling it in current buffer, and global-linum-mode for global toggle.

But there's auto-fill-mode but no “global-auto-fill-mode”. The best thing is to call describe-function and or describe-variable to see their inline docs.

If you want to turn a minor mode globally but it doesn't have a global toggle, you have to write a hook. For example, see: Emacs: Avoid Lambda in Hook

Current State of a Mode

Typically, if a mode has a command named “xyz-mode”, it also has a variable of the same name “xyz-mode”. Its value is t if the mode is on, else nil. You can check this variable for the mode's on/off state.

If you want to turn on/off a mode, call the function, not set the variable. For example:

(global-linum-mode 1) ; GOOD

(setq global-linum-mode t) ; WRONG!
(setq global-linum-mode 1) ; WRONG!

If you also need to check if a mode (package) is loaded, see: Emacs Lisp: Check If a {function, variable, feature} is Defined/Loaded

Writing a Toggle Mode Command

If the mode doesn't have a toggle command, you can write your own.

Here's a example of a command to toggle.

(defun xah-toggle-line-spacing ()
  "Toggle line spacing between no extra space to extra half line height."
  (interactive)
  (if (null line-spacing)
      (setq line-spacing 0.5) ; add 0.5 height between lines
    (setq line-spacing nil)   ; no extra heigh between lines
    )
  (redraw-frame (selected-frame)))

If it's something that does not have a variable that indicates the current state, you can write your own.

(defun xah-cycle-font-2 (φn)
  "Change font in current window between 2 fonts."
  (interactive "p")
  ;; this function sets a property “state”. It is a integer. Possible values are 0 to length of ξ-font-list
  (let (
        (ξ-font-list '("DejaVu Sans Mono-10" "DejaVu Sans-10"))
        ξfontToUse
        ξstateBefore
        ξstateAfter)

    (setq ξstateBefore (if (get 'xah-cycle-font-2 'state) (get 'xah-cycle-font-2 'state) 0))
    (setq ξstateAfter (% (+ ξstateBefore (length ξ-font-list) φn) (length ξ-font-list)))
    (put 'xah-cycle-font-2 'state ξstateAfter)

    (setq ξfontToUse (nth ξstateAfter ξ-font-list))
    (set-frame-parameter nil 'font ξfontToUse)
    (message "Font set to: %s" ξfontToUse)))

Emacs 23.2 Changes

There are changes since emacs 23.2. However, the advice given above applies to any emacs version.

Before emacs 23.2, when a minor mode function is called in lisp code, no argument such as (auto-fill-mode) will toggle the mode. But people usually put that in their emacs init, thinking that it'll always turn it on.

After emacs 23.x, a mode command without any argument used in emacs lisp code will always turn it on.

Though, there might still be some minor mode having the old behavior. (call describe-function to check.)

Here's historical note about this change, by Stefan Monnier (one of the current emacs maintainer) in a post in comp.emacs on (Source groups.google.com) , this behavior may change in future emacs because it is too confusing. “t” will always turn it on, “nil” turns it off always. For toggling, i'm guessing there'll be extra function with “toggle” in the name, ⁖ toggle-read-only, toggle-case-fold-search, toggle-debug-on-error, toggle-text-mode-auto-fill, toggle-truncate-lines, …

(thanks to YOO for correction on (auto-fill-mode t).)

bug#6611

Like it?
Buy Xah Emacs Tutorial
or share
blog comments powered by Disqus