├── .gitignore ├── README.md └── control-mode.el /.gitignore: -------------------------------------------------------------------------------- 1 | *-autoloads.el 2 | *.elc 3 | *~ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Control Mode 2 | ============ 3 | 4 | [![License GPL 3](https://img.shields.io/badge/license-GPL_3-green.svg)](http://www.gnu.org/licenses/gpl-3.0.txt) 5 | [![MELPA](http://melpa.org/packages/control-mode-badge.svg)](http://melpa.org/#/control-mode) 6 | 7 | * [Installation](#installation) 8 | * [MELPA](#melpa) 9 | * [Manual Installation](#manual-installation) 10 | * [Setup](#setup) 11 | * [What It Does](#what-it-does) 12 | * [Examples](#examples) 13 | * [Regenerating Key Bindings](#regenerating-key-bindings) 14 | * [Tips](#tips) 15 | * [Customization](#customization) 16 | * [License](#license) 17 | 18 | Control Mode is a minor mode for Emacs that provides a “control” mode, 19 | similar in purpose to Vim's “normal” mode. Unlike the various Vim emulation 20 | modes, the key bindings in Control Mode are derived from the key bindings 21 | already setup, usually by making the control key unnecessary, 22 | e.g. C-f becomes f. This provides the power of a mode 23 | dedicated to controlling the editor without needing to learn or maintain new 24 | key bindings. 25 | 26 | Installation 27 | ------------ 28 | 29 | ### MELPA 30 | 31 | If you haven't already, add the following lines to your `.emacs.d/init.el` 32 | and restart Emacs so that you can install packages from MELPA: 33 | 34 | ```emacs-lisp 35 | (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) 36 | ``` 37 | 38 | Then do M-x package-install RET control-mode RET. 39 | 40 | ### Manual Installation 41 | 42 | Download the `control-mode.el` file and put it in your `.emacs.d` 43 | directory. Add the following lines to your `.emacs.d/init.el`: 44 | 45 | ```emacs-lisp 46 | (add-to-list 'load-path "~/.emacs.d/") 47 | (require 'control-mode) 48 | ``` 49 | 50 | ### Setup 51 | 52 | Once you have the control-mode package installed, you can add the following 53 | line to your `.emacs`: 54 | 55 | ```emacs-lisp 56 | (control-mode-default-setup) 57 | ``` 58 | 59 | This will setup C-z to turn on Control Mode globally, and 60 | C-z and z to turn it off globally. If you prefer to 61 | use it on a buffer by buffer basis, use `control-mode-localized-setup`. If 62 | you need the usual binding for `Ctrl-z` to suspend Emacs, you can use 63 | `Ctrl-x Ctrl-z` instead (`x Ctrl-z` in Control Mode). It also binds `x f` to 64 | `find-file` (or whatever you had bound to `Ctrl-x Ctrl-f`) in Control Mode 65 | if it would otherwise be bound to `set-fill-column`. 66 | 67 | If you want to run `control-mode` globally as above but want to disable it for 68 | some specific modes, add the mode to the `global-control-mode-exceptions` custom 69 | variable. 70 | 71 | What It Does 72 | ------------ 73 | 74 | Control Mode looks at every key binding you already have defined. For each 75 | binding that includes ⎈ Ctrl, it tries to rebind it without 76 | ⎈ Ctrl. It will only do this if the key binding it is replacing 77 | is unbound or bound to `self-insert-command` or `org-self-insert-command`, 78 | the Emacs commands for keys that simply enter themselves. It will also look 79 | at all bindings with ◆ Meta (⎇ Alt on most keyboards), 80 | and try to rebind those without the ◆ Meta. ⎈ Ctrl 81 | bindings take precedence over ◆ Meta bindings. 82 | 83 | An exception is made for C-m and C-i, which are 84 | usually synonyms for ↵ Enter and ↹ Tab in Emacs. They 85 | will be ignored, allowing M-m and M-i to be bound to 86 | m and i. 87 | 88 | C-M combinations also get rebound. C-M will get bound 89 | to ⎈ Ctrl if ⎈ Ctrl unbound or rebound, and to ◆ 90 | Meta if ◆ Meta was unbound or rebound. If you set the 91 | variable `control-mode-rebind-to-shift` to `t` Control Mode will also try to 92 | rebind to ⇧ Shift if that binding wouldn't already be taken over 93 | by a ⎈ Ctrl + ⇧ Shift or ◆ Meta + ⇧ 94 | Shift binding. This may interfere with the use of ⇧ Shift 95 | with movement commands to select a region however, and so is off by default. 96 | 97 | Control Mode does the right thing when a key binding includes modifiers 98 | other than ⎈ Ctrl and ◆ Meta. For example, it will 99 | rebind ⎈ Ctrl + ⇧ Shift + ⌫ Backspace to 100 | ⇧ Shift + ⌫ Backspace if ⇧ Shift + ⌫ 101 | Backspace has a key binding it is allowed to replace, and it will try 102 | to rebind ⎈ Ctrl + ◆ Meta + Super + 103 | Hyper to ⎈ Ctrl + Super + 104 | Hyper + x. 105 | 106 | Control mode will recurse into prefix keys' keymaps, for example C-x 107 | C-x becomes available as x C-x and x x. 108 | 109 | ### Examples 110 | 111 | Suppose C-f, M-f, and C-M-f are all bound 112 | to commands but f is either unbound or just types “f”. Control 113 | mode would create key bindings like so: 114 | 115 | 116 | 117 | 118 | 119 | 120 |
Original bindingAvailable in Control Mode as
C-ff
M-fM-f
C-M-fC-f, C-M-f
121 | 122 | If C-% isn't bound, but M-% and C-M-% are: 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
Original bindingAvailable in Control Mode as
M-%%
C-M-%C-%, M-%, C-M-%
132 | 133 | If M-n isn't bound, but C-n and C-M-n are: 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 |
Original bindingAvailable in Control Mode as
C-nn
C-M-nC-n, M-n, C-M-n
143 | 144 | ### Regenerating Key Bindings 145 | 146 | Control mode generates bindings separately for every combination of major 147 | mode and minor modes, and so will setup different bindings in each buffer as 148 | necessary. It is able to detect when the major mode changes and adapt to 149 | that, but there is no way for Control Mode to know if you have turned on a 150 | new minor mode. If this causes a problem, turn Control Mode off and back on 151 | again. 152 | 153 | If you change the key bindings in any of the modes or in your global keymap, 154 | you may have to tell Control Mode to regenerate its key bindings. This can 155 | be done with the `control-mode-reload-bindings` command. 156 | 157 | Tips 158 | ---- 159 | 160 | C-[ in Emacs acts like pushing ⎋ Esc or holding down 161 | ◆ Meta. In Control mode [ has this behavior. So for 162 | example, [ f will do `forward-word`. Also, all the number keys, 163 | -, and u are rebound in Control Mode to set arguments 164 | for following commands. So 3 k deletes the last three lines and 165 | u [ a jumps back four sentences. 166 | 167 | C-q, `quoted-insert`, gives you a way to insert text while in 168 | Control Mode. This becomes q, so q t q e q x q t will 169 | enter “text”. 170 | 171 | Keyboard macros in Emacs record the actual key presses used while creating 172 | them, and so a keyboard macro created in Control Mode may not work outside 173 | of Control Mode, and vice versa. You can start a keyboard macro with 174 | C-0 C-z to force it to turn Control Mode off, or C-1 175 | C-z to force it to turn Control Mode on, to prevent problems with 176 | keyboard macros being executed in the wrong mode. 177 | 178 | Customization 179 | ------------- 180 | 181 | Besides the `control-mode-rebind-to-shift` variable mentioned above, Control 182 | Mode provides a keymap and a hook you can use for customization. You can 183 | create key bindings in `control-mode-keymap` and have them available in 184 | Control Mode. These override any automatically generated key bindings. 185 | 186 | You can also use `add-hook` with `control-mode-keymap-generation-functions` 187 | to hook into the keymap generation system. Functions attached to this hook 188 | will be passed a single parameter, a keymap they can define bindings in to 189 | make them available in Control Mode. These functions will be called once for 190 | each combination of major mode and minor modes, and so let you customize 191 | Control Mode based on the other modes or key bindings that are present. 192 | 193 | You can use Emacs' customization interface to customize Control Mode: 194 | M-x customize-group control-mode RET. 195 | 196 | License 197 | ------- 198 | 199 | Copyright © 2013–2015 Stephen Marsh 200 | 201 | Distributed under GNU GPL, version 3. 202 | -------------------------------------------------------------------------------- /control-mode.el: -------------------------------------------------------------------------------- 1 | ;;; control-mode.el --- A "control" mode, similar to vim's "normal" mode 2 | 3 | ;; Copyright (C) 2013 Stephen Marsh 4 | 5 | ;; Author: Stephen Marsh 6 | ;; Version: 0.1 7 | ;; URL: https://github.com/stephendavidmarsh/control-mode 8 | ;; Keywords: convenience emulations 9 | 10 | ;; Control mode is free software; you can redistribute it and/or modify it 11 | ;; under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation; either version 3, or (at your option) 13 | ;; any later version. 14 | ;; 15 | ;; Control mode is distributed in the hope that it will be useful, but WITHOUT 16 | ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 18 | ;; License for more details. 19 | ;; 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with Control mode. If not, see . 22 | 23 | ;;; Commentary: 24 | 25 | ;; Control mode is a minor mode for Emacs that provides a 26 | ;; "control" mode, similar in purpose to vim's "normal" mode. Unlike 27 | ;; the various vim emulation modes, the key bindings in Control mode 28 | ;; are derived from the key bindings already setup, usually by making 29 | ;; the control key unnecessary, e.g. "Ctrl-f" becomes "f". This 30 | ;; provides the power of a mode dedicated to controlling the editor 31 | ;; without needing to learn or maintain new key bindings. See 32 | ;; https://github.com/stephendavidmarsh/control-mode for complete 33 | ;; documentation. 34 | 35 | ;;; Code: 36 | 37 | (defvar control-mode-overrideable-bindings '(nil self-insert-command org-self-insert-command undefined)) 38 | 39 | ;; Ignore Control-m and Control-i 40 | (defvar control-mode-ignore-events '(13 9)) 41 | 42 | ;; This can't be control-mode-map because otherwise the 43 | ;; define-minor-mode will try to install it as the minor mode keymap, 44 | ;; despite being told the minor mode doesn't have a keymap. 45 | (defvar control-mode-keymap (make-sparse-keymap)) 46 | 47 | (defvar control-mode-keymap-generation-functions) 48 | 49 | (defvar control-mode-conversion-cache) 50 | 51 | (defvar control-mode-emulation-alist nil) 52 | (make-variable-buffer-local 'control-mode-emulation-alist) 53 | 54 | (defvar control-mode-rebind-to-shift) 55 | 56 | (defvar global-control-mode-exceptions) 57 | 58 | (defun control-mode-create-alist () 59 | (setq control-mode-emulation-alist 60 | (let* ((mode-key (cons major-mode (sort (mapcar (lambda (x) (car (rassq x minor-mode-map-alist))) (current-minor-mode-maps)) 'string<))) 61 | (value (assoc mode-key control-mode-conversion-cache))) 62 | (if value (cdr value) 63 | (let ((newvalue (mapcar (lambda (x) (cons t x)) (cons (control-mode-create-hook-keymap) (cons control-mode-keymap (mapcar (lambda (k) (control-mode-get-converted-keymap-for k (make-sparse-keymap) nil)) (current-active-maps))))))) 64 | (push (cons mode-key newvalue) control-mode-conversion-cache) 65 | newvalue))))) 66 | 67 | (defun control-mode-create-hook-keymap () 68 | (let ((keymap (make-sparse-keymap))) 69 | (run-hook-with-args 'control-mode-keymap-generation-functions keymap) 70 | keymap)) 71 | 72 | (defun control-mode-get-converted-keymap-for (keymap auto-keymap prefix) 73 | ;; Namespaces? Classes? Inner functions? What's that? 74 | (cl-flet* 75 | ((add-binding (e b) (define-key auto-keymap (vector e) b)) 76 | (key-bindingv (e) (key-binding (vconcat (reverse (cons e prefix))))) 77 | (mod-modifiers (e f) (event-convert-list (append (funcall f (event-modifiers e)) (list (event-basic-type e))))) 78 | (remove-modifier (e mod) (mod-modifiers e (lambda (x) (remq mod x)))) 79 | (add-modifier (e mod) (mod-modifiers e (lambda (x) (cons mod x)))) 80 | (add-modifiers (e mod1 mod2) (mod-modifiers e (lambda (x) (cons mod2 (cons mod1 x))))) 81 | (is-mouse (mods) (or (memq 'click mods) (memq 'down mods))) 82 | (is-overrideable (b) (memq (key-bindingv b) control-mode-overrideable-bindings)) 83 | (try-to-rebind (e b) (if (not (is-overrideable e)) nil 84 | (add-binding e b) 85 | t)) 86 | (convert-keymap (e b) (if (not (keymapp b)) b 87 | (let ((new-auto-keymap (make-sparse-keymap))) 88 | (set-keymap-parent new-auto-keymap b) 89 | (control-mode-get-converted-keymap-for 90 | b new-auto-keymap (cons e prefix))))) 91 | (handle-escape-binding 92 | (event binding) 93 | (unless (memq event control-mode-ignore-events) 94 | (let ((newbinding (convert-keymap event binding)) 95 | (eventmods (event-modifiers event))) 96 | (unless (is-mouse eventmods) 97 | (if (keymapp binding) (add-binding (add-modifier event 'meta) newbinding)) 98 | (if (memq 'control eventmods) 99 | (let ((only-meta (add-modifier (remove-modifier event 'control) 'meta)) 100 | (only-shift (add-modifier (remove-modifier event 'control) 'shift))) 101 | (try-to-rebind only-meta newbinding) 102 | (try-to-rebind event newbinding) 103 | (if (and control-mode-rebind-to-shift 104 | (not (memq 'shift eventmods)) 105 | (not (key-bindingv (add-modifier only-shift 'control))) 106 | (not (key-bindingv (add-modifier only-shift 'meta)))) 107 | (try-to-rebind only-shift newbinding))) 108 | (let ((control-instead (add-modifier event 'control))) 109 | (when (and (is-overrideable event) 110 | (or (not (key-bindingv control-instead)) 111 | (memq control-instead control-mode-ignore-events))) 112 | (add-binding event newbinding) 113 | (if (not (memq control-instead control-mode-ignore-events)) 114 | (let* ((cmevent (add-modifiers event 'control 'meta)) 115 | (cmbinding (convert-keymap cmevent (key-bindingv cmevent)))) 116 | (when cmbinding 117 | (add-binding (add-modifier event 'meta) cmbinding) 118 | (add-binding control-instead cmbinding))))))))))) 119 | (handle-binding 120 | (event binding) 121 | (unless (memq event control-mode-ignore-events) 122 | (let ((eventmods (event-modifiers event))) 123 | (if (and (memq 'control eventmods) (not (is-mouse eventmods))) 124 | (if (and (eq event 27) 125 | (keymapp binding)) 126 | (progn 127 | (map-keymap (function handle-escape-binding) binding) 128 | (try-to-rebind 91 binding)) 129 | (let ((newevent (remove-modifier event 'control)) 130 | (newbinding (convert-keymap event binding))) 131 | (if (keymapp binding) (add-binding event newbinding)) 132 | (when (try-to-rebind newevent newbinding) 133 | (unless (memq 'meta eventmods) ; Here to be safe, but Meta events should be inside Escape keymap 134 | (let* ((cmevent (add-modifier event 'meta)) 135 | (cmbinding (convert-keymap cmevent (key-bindingv cmevent)))) 136 | (when cmbinding 137 | (add-binding event cmbinding)))))))))))) 138 | (map-keymap (function handle-binding) keymap) 139 | auto-keymap)) 140 | 141 | ;;;###autoload 142 | (define-minor-mode control-mode 143 | "Toggle Control mode. 144 | With a prefix argument ARG, enable Control mode if ARG 145 | is positive, and disable it otherwise. If called from Lisp, 146 | enable the mode if ARG is omitted or nil. 147 | 148 | Control mode is a global minor mode." 149 | nil " Control" nil (if control-mode (control-mode-setup) (control-mode-teardown))) 150 | 151 | ;;;###autoload 152 | (define-globalized-minor-mode global-control-mode control-mode 153 | (lambda () 154 | (unless (apply 'derived-mode-p global-control-mode-exceptions) 155 | (control-mode)))) 156 | 157 | (add-hook 'emulation-mode-map-alists 'control-mode-emulation-alist) 158 | 159 | (defun control-mode-setup () 160 | (unless (string-prefix-p " *Minibuf" (buffer-name)) 161 | (setq control-mode-emulation-alist nil) 162 | (control-mode-create-alist))) 163 | 164 | (defun control-mode-teardown () 165 | (setq control-mode-emulation-alist nil)) 166 | 167 | ;;;###autoload 168 | (defun control-mode-default-setup () 169 | (define-key control-mode-keymap (kbd "C-z") 'global-control-mode) 170 | (global-set-key (kbd "C-z") 'global-control-mode) 171 | (add-hook 'control-mode-keymap-generation-functions 172 | 'control-mode-ctrlx-hacks)) 173 | 174 | ;;;###autoload 175 | (defun control-mode-localized-setup () 176 | (define-key control-mode-keymap (kbd "C-z") 'control-mode) 177 | (global-set-key (kbd "C-z") 'control-mode) 178 | (add-hook 'control-mode-keymap-generation-functions 179 | 'control-mode-ctrlx-hacks)) 180 | 181 | (defun control-mode-ctrlx-hacks (keymap) 182 | (if (eq (key-binding (kbd "C-x f")) 'set-fill-column) 183 | (define-key keymap (kbd "x f") (lookup-key (current-global-map) (kbd "C-x C-f"))))) 184 | 185 | (defun control-mode-reload-bindings () 186 | "Force Control mode to reload all generated keybindings." 187 | (interactive) 188 | (setq control-mode-conversion-cache nil) 189 | (mapc (lambda (buf) 190 | (with-current-buffer buf 191 | (if control-mode 192 | (control-mode-setup)))) 193 | (buffer-list))) 194 | 195 | (defcustom control-mode-rebind-to-shift nil 196 | "Allow rebinding Ctrl-Alt- to Shift-" 197 | :group 'control 198 | :type '(boolean) 199 | :set (lambda (x v) 200 | (setq control-mode-rebind-to-shift v) 201 | (control-mode-reload-bindings))) 202 | 203 | (defcustom global-control-mode-exceptions '() 204 | "List of modes to exclude for `global-control-mode'." 205 | :group 'control 206 | :type '(repeat (function)) 207 | :set (lambda (x v) 208 | (setq global-control-mode-exceptions v))) 209 | 210 | (provide 'control-mode) 211 | 212 | ;;; control-mode.el ends here 213 | --------------------------------------------------------------------------------