summaryrefslogtreecommitdiff
path: root/support/emacs-modes/minor-map.el
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/emacs-modes/minor-map.el
Initial commit
Diffstat (limited to 'support/emacs-modes/minor-map.el')
-rw-r--r--support/emacs-modes/minor-map.el126
1 files changed, 126 insertions, 0 deletions
diff --git a/support/emacs-modes/minor-map.el b/support/emacs-modes/minor-map.el
new file mode 100644
index 0000000000..543bd4bb0c
--- /dev/null
+++ b/support/emacs-modes/minor-map.el
@@ -0,0 +1,126 @@
+;; Minor mode keymap for Emacs
+
+;; Use minor-set-key to set a key in the minor keymap for a given
+;; minor mode.
+;;
+;; Use unbind-minor-mode to remove all key definitions for a given
+;; minor mode.
+
+;; COPYLEFT
+
+;; Created 1987 by Per Abrahamsen at University of Aalborg, Denmark.
+;; Updated 1991 by Per Abrahamsen at University of Aalborg, Denmark.
+;; This file is not part of GNU emacs (Yet... ;-)
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; this file, this includes the right to remove this message.
+
+;; HOW MINOR-MAP WORKS!
+
+;; GNU Emacs minor modes may not change the keymap. This is why modes
+;; like outline-mode and indented-text-mode are major modes.
+;; Minor modes could of cause just change the local key binding on entry,
+;; and then restore it on exit. But this will fail, if some other
+;; minor mode changes the keybinding meanwhile.
+;;
+;; The idea behind minor-map is to keep a list of which minor mode has
+;; what binding for a particular key. The list is sorted
+;; chronologically, with the most recently enabled minor mode first,
+;; and the major mode last. The key will always be bound according to
+;; the head of the list, that is, the last enabled minor mode. When a
+;; minor mode is disabled, it will be removed from the list, and if it
+;; was at the head of the list the key will be bound according to the
+;; next entry in the list.
+;;
+;; When a minor mode is enabled, it should bind all its keys with
+;; minor-set-key, and, when disabled, unbound them with
+;; unbind-minor-mode.
+;;
+;; The minor mode keymaps are contained in a local variable
+;; minor-keymap, described in the documentation of make-minor-keymap.
+
+;; RESTRICTIONS
+
+;; The minor maps might fail, if the major mode (or the user) change
+;; the local key bindings after the first call to minor-set-key.
+;;
+;; Minor maps should support shared keymaps for prefix keys.
+
+;; DOES MINOR-MAP WORK?
+
+;; Please report any bug reports (or a formal proof of correctness) to
+;; abraham@iesd.auc.dk
+
+(provide 'minor-map)
+
+(make-variable-buffer-local 'minor-keymap) ;Documentation?
+(setq-default minor-keymap nil)
+
+(make-variable-buffer-local 'minor-local-keymap)
+(setq-default minor-local-keymap nil)
+
+(defun make-minor-keymap ()
+ "Construct a keymap for minor modes if none exists.
+
+The keymap is an alist of (KEY . MODE-LIST) where MODE-LIST is a list
+of (NAME . COMMAND).
+
+Each KEY represents an entry to the alist. If a key sequence have no
+entry, it mean that the KEY is bound to the default value in the
+major mode map.
+
+NAME identify a minor mode, that have bound KEY to COMMAND.
+The head of MODE-LIST represent the newest, and currently active,
+binding. The NAME of the tail is the major-mode, and COMMAND is
+the default binding. The MODE-LIST always contains at least the
+major-mode entry.
+
+Initially the alist is nil."
+
+ ;Try to make keymap buffer-local, *not* mode-local
+ (if (current-local-map)
+ (setq minor-local-keymap (copy-keymap (current-local-map)))
+ (setq minor-local-keymap (make-sparse-keymap)))
+ (use-local-map minor-local-keymap))
+
+(defun minor-set-key (key command name)
+ "Bind KEY to COMMAND in the minor keymap used by the minor mode NAME.
+NAME is a symbol that must identify the minor mode."
+
+ (if (null minor-local-keymap)
+ (make-minor-keymap))
+ (let ((map-entry (assoc key minor-keymap)))
+ (if (null map-entry)
+ (progn
+ (setq map-entry (list key
+ (cons major-mode
+ (local-key-binding key))))
+ (setq minor-keymap (cons map-entry
+ minor-keymap))))
+ (rplacd map-entry (cons (cons name command)
+ (cdr map-entry))))
+ (local-set-key key command))
+
+(defun unbind-minor-mode (name)
+ "Remove all references to minor mode NAME from the minor keymap.
+Key bindings will be updated to reflect the new content of the minor
+keymap."
+
+ (mapcar 'unbind-minor-entry minor-keymap))
+
+(defun unbind-minor-entry (entry)
+ "Remove any references to a minor mode from ENTRY. ENTRY have the
+form (KEY . MODE-LIST) where MODE-LIST is a list of (NAME . COMMAND).
+NAME is compared with the value of the variable \"name\", and the
+conscell is removed if equal. If the first entry in MODE-LIST is
+removed, KEY is rebound to the COMMAND of the next cell."
+
+ (let ((current (cdr entry))
+ (previous entry))
+ (if (eq name (car (car current)))
+ (local-set-key (car entry) (cdr (car (cdr current)))))
+ (while current
+ (if (eq name (car (car current)))
+ (rplacd previous (cdr current))
+ (setq previous current))
+ (setq current (cdr current)))))