Elisp: How to Write a Toggle/Cycle Command
This page is a tutorial on how to write a command to toggle something.
Here's a example to toggle background color.
(defun xah-toggle-background-color () "Toggle background color between seashell and honeydew. URL `http://ergoemacs.org/emacs/elisp_toggle_command.html' Version 2015-12-17" (interactive) ;; use a property “state”. Value is t or nil (if (get 'xah-toggle-background-color 'state) (progn (set-background-color "seashell") (put 'xah-toggle-background-color 'state nil)) (progn (set-background-color "honeydew") (put 'xah-toggle-background-color 'state t))))
The gist to toggle, is to have a variable that we can set as current state.
But usually, we don't want to use a global variable.
The trick here, is to create a property for the function. In Emacs lisp, each symbol can have one or more properties. A property is basically a variable, but associated with the symbol only. 〔►see Elisp: Lisp Symbol〕
Here, we create a property named “state”. The value is
Cycle Among States
You can create a command that cycle between many states.
Here's a example.
(defun xah-cycle-background-color (@n) "Cycle background color among a preset list. If `universal-argument' is called first, cycle n steps. Default is 1 step. URL `http://ergoemacs.org/emacs/elisp_toggle_command.html' Version 2015-12-17" (interactive "p") ;; uses a property “state”. Value is a integer. (let* ( ($values ["cornsilk" "pale green" "pale turquoise" "thistle" "seashell" "honeydew"]) ($index-before (if (get 'xah-cycle-background-color 'state) (get 'xah-cycle-background-color 'state) 0)) ($index-after (% (+ $index-before (length $values) @n) (length $values))) ($next-value (aref $values $index-after))) (put 'xah-cycle-background-color 'state $index-after) (set-background-color $next-value) (message "background color changed to %s" $next-value)))
Here, we create a property named “state”. The value is a integer.
In the function body, we have a variable that is the list of possible values. The property “state”, is used as index to this list.
Each time the command is called, we check current state, then, use modular arithmetic over the length of states list to get the next value (integer/index). Then, we set the value, as well update the state.
To create your own cycle something command, simply change the value list to what you want.