https://susam.github.io/devil/ Devil Mode Devil mode trades your comma key in exchange for a modifier-free editing experience in Emacs. Yes, the comma key! The key you would normally wield for punctuation in nearly every corner of text. Yes, this is twisted! It would not be called the Devil otherwise, would it? If it were any more rational, we might call it something divine, like, uh, the God mode? But alas, there is nothing divine to be found here. Welcome, instead, to the realm of the Devil! You will be granted the occasional use of the comma key for punctuation, but only if you can charm the Devil! But beware, for in this sinister domain, you must relinquish your comma key and embrace an editing experience that whispers wicked secrets into your fingertips! Table of Contents * Introduction * Notation * Install + Install Interactively from MELPA + Install Automatically from MELPA + Install from Git Source * Use Devil * Typing Commas * Devil Reader * Translation Rules * Translation Examples * Bonus Key Bindings * Custom Configuration Examples + Local Mode + Custom Appearance + Reclaim , SPC to Set Mark + Custom Devil Key + Yet Another Custom Devil Key + Multiple Devil Keys + Make All Keys Repeatable * Why? * Comparison with God Mode Introduction Devil mode intercepts our keystrokes and translates them to Emacs key sequences according to a configurable set of translation rules. For example, with the default translation rules, when we type , x , f, Devil translates it to C-x C-f. The choice of the comma key (,) to mean the control modifier key (C-) may seem outrageous. After all, the comma is a very important punctuation both in prose as well as in code. Can we really get away with using , to mean the C- modifier? It turns out, this terrible idea can be made to work without too much of a hassle. At least it works for me! It might work for you too. If it does not, Devil can be configured to use another key instead of , to mean the C- modifier. See the section Custom Devil Key for an example. A sceptical reader may rightfully ask: If , is translated to C-, how on earth are we going to insert a literal , into the text when we need to? The section Typing Commas answers this. But before we get there, we have some fundamentals to cover. Take the plunge and see what unfolds! Maybe you will like this! Maybe you will not! If you do not like this, you can always retreat to God mode, Evil mode, the vanilla key bindings, or whatever piques your fancy! Notation A quick note about the notation used in the document: The previous example shows that , x , f is translated to C-x C-f. What this really means is that the keystrokes ,x,f is translated to ctrl+x ctrl+f. We do not really type any space after the commas. The key , is directly followed by the key x. However, the key sequence notation used in this document contains spaces between each keystroke. This is consistent with how key sequences are represented in Emacs in general and how Emacs functions like key-description, describe-key, etc. represent key sequences. When we really need to type a space, it is represented as SPC. Install Install Interactively from MELPA Devil is available via MELPA. You may already have a preferred way of installing packages from MELPA. If so, install the package named devil to get Devil. For the sake of completeness, here is a very basic way of installing Devil from MELPA: 1. Add the following to the Emacs initialization file (i.e., ~ /.emacs or ~/.emacs.d/init.el or ~/.config/emacs/init.el): (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) 2. Start Emacs with the updated initialization file and then type these commands: M-x package-refresh-contents RET M-x package-install RET devil RET 3. Confirm that Devil is installed successfully with this command: C-h f devil RET 4. Enable Devil mode with this command: M-x global-devil-mode RET 5. Type , x , f and watch Devil translate it to C-x C-f and invoke the corresponding command. Install Automatically from MELPA Here is yet another basic way to install and enable Devil using Elisp: (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) (unless package-archive-contents (package-refresh-contents)) (unless (package-installed-p 'devil) (package-install 'devil)) (global-devil-mode) (global-set-key (kbd "C-,") 'global-devil-mode) Now type , x , f and watch Devil translate it to C-x C-f and invoke the corresponding command. Type C-, to disable Devil mode. Type C-, again to enable it. Install from Git Source If you prefer obtaining Devil from its Git repository, follow these steps: 1. Clone Devil to your system: git clone https://github.com/susam/devil.git 2. Add the following to your Emacs initialization: (add-to-list 'load-path "/path/to/devil/") (require 'devil) (global-devil-mode) (global-set-key (kbd "C-,") 'global-devil-mode) 3. Start the Emacs editor. Devil mode should now be enabled in all buffers. The modeline of each buffer should show the Devil lighter. 4. Type , x , f and watch Devil translate it to C-x C-f and invoke the corresponding command. Type C-, to disable Devil mode. Type C-, again to enable it. Use Devil Assuming vanilla Emacs key bindings have not been changed and Devil has not been customised, here are some examples that demonstrate how Devil may be used: 1. Type , x , f and watch Devil translate it to C-x C-f and invoke the find-file command. 2. Type , p to move up one line. 3. To move up multiple lines, type , p p p and so on. Some Devil key sequences are repeatable keys by default. The repeatable Devil key sequences can be repeated by typing the last key of the Devil key sequence over and over again. 4. Another example of a repeatable Devil key sequence is , f f f which moves the cursor word by multiple characters. A few other examples of repeatable keys are , k k k to kill lines, , / / / to undo changs, etc. Type C-h v devil-repeatable-keys RET to see the complete list of repeatable keys. 5. Type , s and watch Devil translate it to C-s and invoke incremental search. 6. Type , m s and watch Devil translate it to C-M-s and invoke regular-expression-based incremental search. Yes, m is translated to M-. 7. Type , m m x and watch Devil translate it to M-x and invoke the corresponding command. 8. Type , u , f and watch Devil translate it to C-u C-f and move the cursor forward by 4 characters. 9. Type , u u , f and the cursor moves forward by 16 characters. Devil uses its translation rules and an additional keymap to make the input key sequence behave like C-u C-u C-f which moves the cursor forward by 16 characters. 10. Type , SPC to type a comma followed by space. This is a special key sequence to make it convenient to type a comma in the text. Note that this sacrifices the use of , SPC to mean C-SPC which could have been a convenient way to set a mark. 11. Type , z SPC and watch Devil translate it to C-SPC and set a mark. Yes, , z is translated to C- too. 12. Similarly, type , RET to type a comma followed by the enter key. This is another special key. 13. Type , , to type a single comma. This special key is useful for cases when you really need to type a single literal comma. Typing Commas Devil makes the questionable choice of using the comma as its activation key. As illustrated in the previous section, typing , x , f produces the same effect as typing C-x C-f. One might naturally wonder how then we are supposed to type literal commas. Most often when we edit text, we do not really type a comma in isolation. Often we immediately follow the comma with a space or a newline. This assumption usually holds good while editing regular text. However, this assumption may not hold in some situations, like while working with code when we need to add a single comma at the end of an existing line. In scenarios where the above assumption holds good, typing , SPC inserts a comma and a space. Similarly, typing , RET inserts a comma and a newline. In scenarios, when we do need to type a single comma, type , , instead. Also, it is worth mentioning here that if all this fiddling with the comma key feels clumsy, we could always customise the Devil key to something else that feels better. We could also disable Devil mode temporarily and enable it again later with C-, as explained in section Install. Devil Reader The following points briefly describe how Devil reads Devil key sequences, translates them to Emacs key sequences, and runs commands bound to the key sequences: 1. As soon as the Devil key is typed (which is , by default), Devil wakes up and starts reading Devil key sequences. Type C-h v devil-key RET to see the current Devil key. 2. After each keystroke is read, Devil checks if the key sequence accumulated is a special key. If it is, then the special command bound to the special key is executed immediately. Note that this step is performed before any translation rules are applied to the input key sequence. This is how the Devil special key sequence , SPC inserts a comma and a space. Type C-h v devil-special-keys RET to see the list of special keys and the commands bound to them. 3. If the key sequence accumulated so far is not a special key, then Devil translates the Devil key sequence to a regular Emacs key sequence. If the regular Emacs key sequence turns out to be a complete key sequence and some command is found to be bound to it, then that command is executed immediately. This is how the Devil key sequence , x , f is translated to C-x C-f and the corresponding binding is executed. If the translated key sequence is a complete key sequence but no command is bound to it, then Devil displays a message that the key sequence is undefined. Type C-h v devil-translations RET to see the list of translation rules. 4. After successfully translating a Devil key sequence to an Emacs key sequence and executing the command bound to it, Devil checks if the key sequence is a repeatable key sequence. If it is found to be a repeatable key sequence, then Devil sets a transient map so that the command can be repeated merely by typing the last keystroke of the input key sequence. This is how , p p p moves the cursor up by three lines. Type C-h v devil-repeatable-keys RET to see the list of repeatable Devil key sequences. The variables devil-special-keys, devil-translations, and devil-repeatable-keys may contain keys or values with the string %k in them. This is a placeholder for devil-key. While applying the special keys, translation rules, or repeat rules, each %k is replaced with the actual value of devil-key before applying the rules. Translation Rules The following points provide an account of the translation rules that Devil follows in order to convert a Devil key sequence entered by the user to an Emacs key sequence: 1. The input key vector read from the user is converted to a key description (i.e., the string functions like describe-key, key-description, produce). For example, if the user types ,x,f, it is converted to , x , f. 2. Now the resulting key description is translated with simple string replacements. If any part of the string matches a key in devil-translations, then it is replaced with the corresponding value. For example, , x , f is translated to C- x C- f. Then Devil normalises the result to C-x C-f by removing superfluous spaces after the modifier keys. 3. However, if the simple string based replacement leads to an invalid Emacs key sequence, it skips the replacement that causes the resulting Emacs key sequence to become invalid. For example , m , results in C-M-C- after the simple string replacement because the default translation rules replace , with C- and m with M-. However, C-M-C- is an invalid key sequence, so the replacement of the second , to C- is skipped. Therefore, the input , m , is translated to C-M-, instead. Translation Examples By default, Devil supports a small but peculiar set of translation rules that can be used to avoid modifier keys while typing various types of key sequences. See C-h v devil-translations RET for the translation rules. Here are some examples that demonstrate the default translation rules. The obvious ones are shown first first. The more peculiar translations come later in the table. Input Translated Remarks , s C-s , is replaced with C- , m s C-M-s m is replaced with M- , z s C-SPC , z is replaced with C- too , z z C-z ditto , m m x M-x , m m is replaced with M- too , c , , C-c , , , is replaced with , Note how we cannot use , SPC to set a mark because that key sequence is already reserved as a special key sequence in devil-special-keys, so Devil translates , z to C- too, so that we can still type C-SPC using , z s and set a mark. Also, note how the translation of , m m to M- allows us to enter a key sequence that begins with the M- modifier key. Bonus Key Bindings Devil adds the following additional key bindings only when Devil is enabled globally with global-devil-mode: * Adds the Devil key to isearch-mode-map, so that Devil key sequences work in incremental search too. * Adds u to universal-argument-more to allow repeating the universal argument command C-u simply by repeating u. As mentioned before these features are available only when Devil is enabled globally with global-devil-mode. If Devil is enabled locally with devil-mode, then these features are not available. Custom Configuration Examples In the examples presented below, the (require 'devil) calls may be omitted if Devil has been installed from MELPA. There are appropriate autoloads in place in the Devil package that would ensure that it is loaded automatically on enabling Devil mode. However, the require calls have been included in the examples below for the sake of completeness. Local Mode While the section Install shows how we enable Devil mode globally, this section shows how we can enable it locally. Here is an example initialization code that enables Devil locally only in text buffers. (require 'devil) (add-hook 'text-mode-hook 'devil-mode) (global-set-key (kbd "C-,") 'devil-mode) This is not recommended though because this does not provide a seamless Devil experience. For example, with Devil enabled locally in a text buffer like this, although we can type , x , f to launch the find-file minibuffer, we cannot use Devil key sequences in the minibuffer. Further the special keymaps described in the previous section work only when Devil is enabled globally. Custom Appearance The following initialization code shows how we can customise Devil to show a Devil smiley () in the modeline and in the Devil prompt. (require 'devil) (setq devil-lighter " \U0001F608") (setq devil-prompt "\U0001F608 %t") (global-devil-mode) (global-set-key (kbd "C-,") 'global-devil-mode) Reclaim , SPC to Set Mark The default configuration for special keys reserves , SPC to insert a literal comma followed by space. This default makes it easy to type space in various contexts. However, this means that , SPC does not translate to C-SPC. Therefore , SPC cannot be used to set mark. Instead, the default translation rules offer , z SPC as a way to set mark. If you would rather set mark using , SPC and you are happy with the special key , , alone to insert a literal comma and you are okay with typing comma twice everytime you want to insert a literal comma, then the special keys (require 'devil) (global-devil-mode) (setq devil-special-keys '(("%k %k" . (lambda () (interactive) (devil-run-key "%k"))))) This reduces the number of special keys so that only , , is treated as special. All the other special key definitions (, SPC was one of them) are removed. As a result, , SPC is now translated to C-SPC. Custom Devil Key The following initialization code shows how we can customise Devil to use a different Devil key. (defvar devil-key ";") (require 'devil) (global-devil-mode) (global-set-key (kbd "C-;") 'global-devil-mode) The above example sets the Devil key to the semicolon, perhaps another dubious choice for the Devil key. With this configuration, we can use ; x ; f and have Devil translate it to C-x C-f. Yet Another Custom Devil Key The following initialization code shows how we can customise Devil to use yet another different Devil key. (defvar devil-key (kbd "")) (defvar devil-special-keys '(("%k %k" . (lambda () (interactive) (devil-run-key "%k"))))) (require 'devil) (global-devil-mode) (global-set-key (kbd "C-") 'global-devil-mode) The above example sets the Devil key to the left arrow key, perhaps another dubious choice for the Devil key. With this configuration, we can use x f and have Devil translate it to C-x C-f. Additionally, the above example defines the devil-special-keys variable to have a single entry that allows typing to produce the same effect as the original . It removes the other entries, so that SPC is no longer reserved as a special key. Thus SPC can now be used to set a mark like one would normally expect. Multiple Devil Keys While this package provides the comma (,) as the default and the only Devil key, nothing stops you from extending the mode map to support multiple Devil keys. Say, you decide that in addition to activating Devil with , which also plays the role of C-, you also want to activate Devil with . which must now play the role of M-. To achieve such a result, you could use this initialization code as a starting point and then customise it further based on your requirements: (defvar devil-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd ",") #'devil) (define-key map (kbd ".") #'devil) map)) (defvar devil-special-keys '((", ," . (lambda () (insert ","))) (". ." . (lambda () (insert "."))))) (defvar devil-translations '(("," . "C-") ("." . "M-"))) (require 'devil) (global-devil-mode) With this configuration, we can type , x , f for C-x C-f like before. But now we can also type . x for M-x. Similarly, we can type , . s for C-M-s and so on. Further, , , inserts a literal comma and . . inserts a literal dot. Note that by default Devil configures only one activation key (,) because the more activation keys we add, the more intrusive Devil becomes during regular editing tasks. Every key that we reserve for activating Devil loses its default function and then we need workarounds to somehow invoke the default function associated with that key (like repeating . twice to insert a single . in the above example). Therefore, it is a good idea to keep the number of Devil keys as small as possible. Make All Keys Repeatable By default Devil has a small list of key sequences that are considered repeatable. This list is defined in the variable devil-repeatable-keys. Type C-h v devil-repeatable-keys RET to view this list. For example, consider the repeatable key sequence %k p in this list. Assuming that the default Devil and Emacs key bindings have not been changed, this means that after we type C-p and move the cursor to the previous line, we can repeat this operation by typing p over and over again. The repetition occurs as long as the last character of the repeatable key sequence is typed over and over again. Typing any other key stops the repetition and the default behaviour of the other key is then observed. It is possible to make all key sequences repeatable by setting the variable devil-all-keys-repeatable to t. Here is an example configuration: (require 'devil) (setq devil-all-keys-repeatable t) (global-devil-mode) Now all every Devil key sequence that ends up executing an Emacs command can be repeated by merely repeating the last character of the key sequence. The list in devil-repeatable-keys is ignored. Note that only Devil key sequences that get translated to a regular Emacs key sequence and result in the execution of an Emacs command can be repeatable. The special keys defined in devil-special-keys are never repeatable. Why? Why go to the trouble of creating and using something like this? Why not just remap caps lock to ctrl like every other sane person does? Or if it is so important to avoid modifier keys, why not use something like God mode or Evil mode? Well, for one, both God mode and Evil mode are modal editing modes. Devil, on the other hand, provides a modeless editing experience of Emacs as possible. Devil mode began as a fun little tiny experiment. From the outset, it was clear that using something as crucial as the comma for specifying the modifier key is asking for trouble. However, I still wanted to see how far I could go with it. It turned out that in a matter of days, I was using it full-time for all of my Emacs usage. This experiment was partly motivated by Macbook keyboards which do not have a right ctrl key. Being a touch-typist myself, I found it inconvenient to type key combinations like C-x, C-a, C-w, C-s, etc. where both the modifier key and the modified key need to be pressed with the left hand fingers. I am not particularly fond of remapping caps lock to behave like ctrl because that still suffers from the problem that key combinations like C-x, C-a require pressing both the modifier key and the modified key with the left hand fingers. I know many people remap both their caps lock and enter to behave like ctrl. While I think that is a fine solution, I was not willing to put up with the work required to make that work seamlessly across all the various operating systems I work on. What began as a tiny whimsical experiment a few years ago turned out to be quite effective, at least to me. I like that this solution is implemented purely as Elisp and therefore does not have any external dependency. I am sharing this solution here in the form of a minor mode, just in case, there is someone out there who might find this useful too. Comparison with God Mode God mode provides a modal editing experience but Devil does not. Devil has the same underlying philosophy as that of God mode, i.e., the user should not have to learn new key bindings. However, Devil does not have a hard separation between insert mode and command mode like God mode has. Instead, Devil waits for an activation key (, by default) and as soon as it is activated, it intercepts and translates keys, runs the corresponding command, and then gets out of the way. So Devil tries to retain the modeless editing experience of vanilla Emacs as much as possible. Now it is worth mentioning that some of this modeless editing experience can be reproduced in god-mode too using its god-execute-with-current-bindings function. Here is an example: (global-set-key (kbd ",") #'god-execute-with-current-bindings) With this configuration, God mode translates , x f to C-x C-f. Similarly , g x invokes M-x and , G s invokes C-M-x. This provides a modeless editing experience in God mode too. However, this experience does not extend seamlessly to minibuffers. Devil does extend its Devil key translation to minibuffers. Further note that in God mode the ctrl modifier has sticky behaviour, i.e., the modifier remains active automatically for the entire key sequence. Therefore in the above example, we type , only once while typing , x f to invoke C-x C-f. However, this sticky behaviour implies that we need some way to disambiguate between key sequences like C-x C-f (find-file) and C-x o (set-fill-column). God mode solves this by introducing SPC to deactivate the modifier, e.g., x f translates to C-x C-f but x SPC o translates to C-x o. Devil does not treat the modifier key as sticky which leads to simpler key sequences at the cost of a little additional typing, i.e., , x , o translates to C-x C-o and , x o translates to C-x o. To summarize, there are primarily three things that Devil does differently: * Provide a modeless editing experience from the outset. * Seamlessly extend the same editing experience to minibuffer, incremental search, etc. * Translate key sequences using string replacements. This allows for arbitrary and sophisticated key translations for the adventurous. * Choose non-sticky behaviour for the modifier keys. These differences could make Devil easier to use than God mode for some people but clumsy for other people. It depends on one's tastes and preferences. --------------------------------------------------------------------- MELPA GitHub License Issues Mastodon