branch: elpa/devil commit b84cd61eecbb7d1df4ae8f46c8afe59e76afdd6c Author: Susam Pal <su...@susam.net> Commit: Susam Pal <su...@susam.net>
Format .org files consistently --- CHANGES.org | 10 + LICENSE.org | 2 +- MANUAL.org | 694 +++++++++++++++++++++++++++++++++--------------------------- README.org | 50 +++-- 4 files changed, 418 insertions(+), 338 deletions(-) diff --git a/CHANGES.org b/CHANGES.org index 85a7d6322e..260c80ab9e 100644 --- a/CHANGES.org +++ b/CHANGES.org @@ -1,6 +1,9 @@ * Changelog ** 0.3.0 (2023-05-11) +:PROPERTIES: +:CUSTOM_ID: 0.3.0 +:END: *** Added @@ -15,7 +18,11 @@ - Fix spacing in documentation strings. - Remove =devil-version= and =devil-show-version=. + ** 0.2.0 (2023-05-09) +:PROPERTIES: +:CUSTOM_ID: 0.2.0 +:END: *** Added @@ -40,6 +47,9 @@ ** 0.1.0 (2023-05-07) +:PROPERTIES: +:CUSTOM_ID: 0.1.0 +:END: *** Added diff --git a/LICENSE.org b/LICENSE.org index 6cdd83ec6b..baa8cf143f 100644 --- a/LICENSE.org +++ b/LICENSE.org @@ -1,6 +1,6 @@ * The MIT License (MIT) :PROPERTIES: -:CUSTOM_ID: the-mit-license-mit +:CUSTOM_ID: the-mit-license :END: Copyright (c) 2022-2023 Susam Pal diff --git a/MANUAL.org b/MANUAL.org index 3cd3ca982b..2bdcc2b11d 100644 --- a/MANUAL.org +++ b/MANUAL.org @@ -9,109 +9,124 @@ #+texinfo: @insertcopying +Devil mode trades your comma key in exchange for a modifier-free +editing experience! 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! + +* Introduction +:PROPERTIES: +:CUSTOM_ID: introduction +:END: Devil mode intercepts our keystrokes and translates them to Emacs key -sequences according to a configurable set of translation rules. For +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][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][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! +(=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 :PROPERTIES: :CUSTOM_ID: notation :END: 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 key sequence ,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=. +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 :PROPERTIES: :CUSTOM_ID: install :END: + ** Install Interactively from MELPA :PROPERTIES: :CUSTOM_ID: install-interactively-from-melpa :END: -Devil is available via [[https://melpa.org/][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: +Devil is available via [[https://melpa.org/][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=): +1. Add the following to the Emacs initialization file (i.e., + =~/.emacs= or =~/.emacs.d/init.el= or =~/.config/emacs/init.el=): - #+begin_src sh + #+begin_src elisp (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) #+end_src -2. Start Emacs with the updated initialization file and then type these - commands: +2. Start Emacs with the updated initialization file and then type + these commands: #+begin_example - M-x package-refresh-contents RET - M-x package-install RET devil RET + M-x package-refresh-contents RET + M-x package-install RET devil RET #+end_example 3. Confirm that Devil is installed successfully with this command: #+begin_example - M-x devil-show-version RET + C-h f devil RET #+end_example 4. Enable Devil mode with this command: #+begin_example - M-x global-devil-mode RET + M-x global-devil-mode RET #+end_example 5. Type =, x , f= and watch Devil translate it to =C-x C-f= and invoke the corresponding command. ** Install Automatically from MELPA -:PROPERTIES: -:CUSTOM_ID: install-automatically-from-melpa -:END: -Here is yet another basic way to install and enable Devil using Elisp: -#+begin_example -(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) -#+end_example +Here is yet another basic way to install and enable Devil using Elisp: -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. +#+begin_src 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) +#+end_src + +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 :PROPERTIES: @@ -122,196 +137,200 @@ steps: 1. Clone Devil to your system: - #+begin_src sh - git clone https://github.com/susam/devil.git + #+begin_src shell + git clone https://github.com/susam/devil.git #+end_src 2. Add the following to your Emacs initialization: - #+begin_example - (add-to-list 'load-path "/path/to/devil/") - (require 'devil) - (global-devil-mode) - (global-set-key (kbd "C-,") 'global-devil-mode) - #+end_example + #+begin_src elisp + (add-to-list 'load-path "/path/to/devil/") + (require 'devil) + (global-devil-mode) + (global-set-key (kbd "C-,") 'global-devil-mode) + #+end_src -3. Start the Emacs editor. Devil mode should now be enabled in all - buffers. The modeline of each buffer should show the =Devil= lighter. +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 + the corresponding command. Type =C-,= to disable Devil mode. Type =C-,= again to enable it. * Use Devil - :PROPERTIES: - :CUSTOM_ID: use-devil - :END: -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: +:PROPERTIES: +:CUSTOM_ID: use-devil +:END: +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 functionality. + 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. The repeatable Devil key sequences can - be repeated by typing the last key of the Devil key sequence over and - over again. +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. +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-=. + 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. +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. +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. +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. + mark. Yes, =, z= is translated to =C-= too. -12. Similarly, type =, RET= to type a comma followed by the return key. - This is another special key. +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 +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 - :PROPERTIES: - :CUSTOM_ID: typing-commas - :END: -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. +:PROPERTIES: +:CUSTOM_ID: typing-commas +:END: +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. +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. +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 -[[#use-devil][Use Devil]]. +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 - :PROPERTIES: - :CUSTOM_ID: devil-reader - :END: +:PROPERTIES: +:CUSTOM_ID: devil-reader +:END: 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. + 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. + 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 + 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. + 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 + 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. +=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 - :PROPERTIES: - :CUSTOM_ID: translation-rules - :END: +:PROPERTIES: +:CUSTOM_ID: translation-rules +:END: 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=. + =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 + 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 + 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 + 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 - :PROPERTIES: - :CUSTOM_ID: translation-examples - :END: -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. +:PROPERTIES: +:CUSTOM_ID: translation-examples +:END: +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 | |-----------+------------+-----------------------------------| @@ -324,119 +343,160 @@ translations come later in the table. 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. +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 - :PROPERTIES: - :CUSTOM_ID: bonus-key-bindings - :END: +:PROPERTIES: +:CUSTOM_ID: bonus-key-bindings +:END: 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 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=. +- 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. +enabled globally with =global-devil-mode=. If Devil is enabled +locally with =devil-mode=, then these features are not available. * Custom Configuration Examples - :PROPERTIES: - :CUSTOM_ID: custom-configuration-examples - :END: +:PROPERTIES: +:CUSTOM_ID: custom-configuration-examples +:END: In the examples presented below, the =(require 'devil)= calls may be -omitted if Devil has been installed from MELPA. There are appropriate +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= +loaded automatically on enabling Devil mode. However, the =require= calls have been included in the examples below for the sake of completeness. ** Local Mode - :PROPERTIES: - :CUSTOM_ID: local-mode - :END: -While the section [[#use-devil][Use Devil]] shows how we enable Devil mode globally, +:PROPERTIES: +:CUSTOM_ID: local-mode +:END: +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. -#+begin_example -(require 'devil) -(add-hook 'text-mode-hook 'devil-mode) -(global-set-key (kbd "C-,") 'devil-mode) -#+end_example +#+begin_src elisp + (require 'devil) + (add-hook 'text-mode-hook 'devil-mode) + (global-set-key (kbd "C-,") 'devil-mode) +#+end_src -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. +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 - :PROPERTIES: - :CUSTOM_ID: custom-appearance - :END: +:PROPERTIES: +:CUSTOM_ID: custom-appearance +:END: The following initialization code shows how we can customise Devil to -show a Devil smiley (😈) in the modeline and the echo area. +show a Devil smiley (😈) in the modeline and in the Devil prompt. -#+begin_example -(require 'devil) -(setq devil-lighter " \U0001F608") -(setq devil-prompt "\U0001F608 %t") -(global-devil-mode) -(global-set-key (kbd "C-,") 'global-devil-mode) -#+end_example - -This is how Emacs may look if emojis are rendered correctly: +#+begin_src elisp + (require 'devil) + (setq devil-lighter " \U0001F608") + (setq devil-prompt "\U0001F608 %t") + (global-devil-mode) + (global-set-key (kbd "C-,") 'global-devil-mode) +#+end_src -[[https://i.imgur.com/oYtwnGi.png][[[https://i.imgur.com/oYtwnGi.png]]]] +** Reclaim , SPC to Set Mark +:PROPERTIES: +:CUSTOM_ID: reclaim-comma-spc-to-set-mark +:END: +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 + +#+begin_src elisp + (require 'devil) + (global-devil-mode) + (setq devil-special-keys '(("%k %k" . (lambda () (interactive) (devil-run-key "%k"))))) +#+end_src + +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 - :PROPERTIES: - :CUSTOM_ID: custom-devil-key - :END: +:PROPERTIES: +:CUSTOM_ID: custom-devil-key +:END: The following initialization code shows how we can customise Devil to use a different Devil key. -#+begin_example -(defvar devil-key "<left>") -(defvar devil-special-keys '(("%k %k" . (lambda () (interactive) (devil-run-key "%k"))))) -(require 'devil) -(global-devil-mode) -(global-set-key (kbd "C-<left>") 'global-devil-mode) -#+end_example +#+begin_src elisp + (defvar devil-key ";") + (require 'devil) + (global-devil-mode) + (global-set-key (kbd "C-;") 'global-devil-mode) +#+end_src + +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 +:PROPERTIES: +:CUSTOM_ID: yet-another-custom-devil-key +:END: +The following initialization code shows how we can customise Devil to +use yet another different Devil key. + +#+begin_src elisp + (defvar devil-key "<left>") + (defvar devil-special-keys '(("%k %k" . (lambda () (interactive) (devil-run-key "%k"))))) + (require 'devil) + (global-devil-mode) + (global-set-key (kbd "C-<left>") 'global-devil-mode) +#+end_src The above example sets the Devil key to the left arrow key, perhaps -another dubious choice for the Devil key. With this configuration, we +another dubious choice for the Devil key. With this configuration, we can use =<left> x <left> 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 =<left> <left>= to -produce the same effect as the original =<left>=. It removes the other -entries, so that =<left> SPC= is no longer reserved as a special key. -Thus =<left> SPC= can now be used to set a mark like one would normally -expect. +produce the same effect as the original =<left>=. It removes the +other entries, so that =<left> SPC= is no longer reserved as a special +key. Thus =<left> SPC= can now be used to set a mark like one would +normally expect. ** Multiple Devil Keys - :PROPERTIES: - :CUSTOM_ID: multiple-devil-keys - :END: -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: - -#+begin_example +:PROPERTIES: +:CUSTOM_ID: multiple-devil-keys +:END: +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: + +#+begin_src elisp (defvar devil-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd ",") #'devil) @@ -448,99 +508,100 @@ point and then customise it further based on your requirements: ("." . "M-"))) (require 'devil) (global-devil-mode) -#+end_example +#+end_src 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. +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. +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. * Why? - :PROPERTIES: - :CUSTOM_ID: why - :END: -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? +:PROPERTIES: +:CUSTOM_ID: why +:END: +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 +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. +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 +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 +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. +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 - :PROPERTIES: - :CUSTOM_ID: comparison-with-god-mode - :END: -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: - -#+begin_example -(global-set-key (kbd ",") #'god-execute-with-current-bindings) -#+end_example +:PROPERTIES: +:CUSTOM_ID: comparison-with-god-mode +:END: +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: + +#+begin_src elisp + (global-set-key (kbd ",") #'god-execute-with-current-bindings) +#+end_src 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-o= (delete blank lines) and =C-x o= (other window). God mode -solves this by introducing =SPC= to deactivate the modifier, e.g., -=, x o= translates to =C-x C-o= 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=. +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: @@ -548,17 +609,16 @@ 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 +- 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. +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. * Support - :PROPERTIES: - :CUSTOM_ID: support - :END: -To report bugs, suggest improvements, or ask questions, -[[https://github.com/susam/devil/issues][create issues]]. +:PROPERTIES: +:CUSTOM_ID: support +:END: +To report bugs, suggest improvements, or ask questions, [[https://github.com/susam/devil/issues][create issues]]. diff --git a/README.org b/README.org index 0a3b82572f..1e00f9c587 100644 --- a/README.org +++ b/README.org @@ -1,21 +1,23 @@ * Devil Mode -Devil mode trades your comma key in exchange for a modifier-free editing -experience! 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! +Devil mode trades your comma key in exchange for a modifier-free +editing experience! 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! Read the [[./MANUAL.org][manual]] for more details on how to use Devil. ** Channels - +:PROPERTIES: +:CUSTOM_ID: channels +:END: The author of this project hangs out at the following places online: - Website: [[https://susam.net][susam.net]] @@ -24,13 +26,21 @@ The author of this project hangs out at the following places online: - GitHub: [[https://github.com/susam][@susam]] You are welcome to subscribe to, follow, or join one or more of the -above channels to receive updates from the author or ask questions about -this project. - -** More +above channels to receive updates from the author or ask questions +about this project. -See [[https://github.com/susam/emacs4cl][Emacs4CL]], a DIY quick-starter -kit to set up Emacs for Common Lisp programming. +* Support +:PROPERTIES: +:CUSTOM_ID: support +:END: +To report bugs, suggest improvements, or ask questions, [[https://github.com/susam/devil/issues][create issues]]. -See [[https://github.com/susam/emfy][Emfy]], a DIY quick-starter kit to -set up Emacs for general purpose editing and programming. +** More +:PROPERTIES: +:CUSTOM_ID: more +:END: +See [[https://github.com/susam/emacs4cl][Emacs4CL]], a DIY quick-starter kit to set up Emacs for Common Lisp +programming. + +See [[https://github.com/susam/emfy][Emfy]], a DIY quick-starter kit to set up Emacs for general purpose +editing and programming.