#+title:                Devil Mode
#+author:               Susam Pal
#+email:                susam@susam.net
#+language:             en
#+options:              ':t toc:nil author:t email:t num:t
#+texinfo_dir_category: Emacs misc features
#+texinfo_dir_title:    Devil: (devil-mode)
#+texinfo_dir_desc:     Minor mode for Devil-like command entering

#+texinfo: @insertcopying

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.

* 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
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
: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 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:
Devil is available via [[https://elpa.nongnu.org/nongnu/devil.html][NonGNU ELPA]] and [[https://melpa.org/#/devil][MELPA]].  You may already have a
preferred way of installing packages from ELPA/MELPA.  If so, install
the package named =devil= to get Devil.  If you have Emacs 28.1 or a
more recent version, it has NonGNU ELPA enabled by default, so you can
install Devil quite easily with =M-x package-install RET devil RET=
without having to perform any further steps.  However, for the sake of
completeness, a few very different and basic ways of installing Devil
are presented in the next few subsections.

** Install Interactively from MELPA
:PROPERTIES:
:CUSTOM_ID: install-interactively-from-melpa
:END:
To install the latest version of Devil from MELPA, perform the
following steps:

1. Add the following to the Emacs initialization file (i.e.,
   =~/.emacs= or =~/.emacs.d/init.el= or =~/.config/emacs/init.el=):

   #+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.  Then type these
   commands:

   #+begin_example
     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
     C-h f devil RET
   #+end_example

4. Enable Devil mode with this command:

   #+begin_example
     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

Here is yet another basic way to install and enable Devil using Elisp:

#+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:
:CUSTOM_ID: install-from-git-source
:END:
If you prefer obtaining Devil from its Git repository, follow these
steps:

1. Clone Devil to your system:

   #+begin_src shell
     git clone https://github.com/susam/devil.git
   #+end_src

2. Add the following to your Emacs initialization:

   #+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.

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
: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= 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 changes, etc.  Type =C-h v devil-repeatable-keys RET= to
   see the complete list of repeatable keys.  If you want all Devil
   key sequences to be repeatable, see the section [[*Make All Keys
   Repeatable]] to find out how to do this.

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.  See the section
    [[*Reclaim , SPC to Set Mark]] if you do not want to make this
    sacrifice.

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.

14. Type =, h , k= to invoke =devil-describe-key=.  This is a special
    key that invokes the Devil variant of =describe-key= included in
    vanilla Emacs.  When the key input prompt appears, type the Devil
    key sequence =, x , f= and Devil will display the documentation of
    the function invoked by this Devil key sequence.  Note: The key
    sequence =, h k= translates to =C-h k= and invokes the vanilla
    =describe=key=.  It is the Devil key sequence =, h , k= that
    invokes =devil-describe-key=.

* 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.

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 where we do need to type a single comma, type =, ,=
instead.

Note that you could also type a single comma with =, q ,= which
translates to =C-q ,= and inserts a literal comma.  The Emacs key
sequence =C-q= invokes the command =quoted-insert= which inserts the
next input character.  The =, ,= special key sequence is probably
easier to type than this.

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
: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.

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 Mechanism
:PROPERTIES:
:CUSTOM_ID: translation-mechanism
:END:
The following points provide an account of the translation mechanism
that Devil uses 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 (like the string produced by functions like
   =describe-key= and =key-description=).  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 the stray
   spaces after the modifier keys.

3. If the simple string based replacement discussed in the previous
   point 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.

4. Finally, Devil looks for key chords in the key sequence that
   contain both the =C-= modifier and an uppercase letter.  If such a
   key chord occurs, then it replaces the uppercase letter with its
   shifted form, e.g., =, m V= first translates to =C-M-V= according
   to the previous points and then the result is translated to
   =C-M-S-v= according to this point.

* Default Translation Rules
:PROPERTIES:
:CUSTOM_ID: default-translation-rules
: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.  The
more peculiar translations come later in the table.  The concluding
paragraph of this subsection offers a guide on how to gradually and
gently adopt these key sequences into your daily routine.

| Input       | Translated | Remarks                           |
|-------------+------------+-----------------------------------|
| =, s=       | =C-s=      | =,= is replaced with =C-=         |
| =, m s=     | =C-M-s=    | =m= is replaced with =M-=         |
| =, m m x=   | =M-x=      | =, m m= is replaced with =M-= too |
| =, [ x=     | =C-[ x=    | equivalent to =M-x=               |
| =, c , ,=   | =C-c ,=    | =, ,= is replaced with =,=        |
| =, c m m=   | =C-c m=    | =m m= is replaced with =m=        |
| =, z SPC=   | =C-SPC=    | =, z= is replaced with =C-= too   |
| =, z z=     | =C-z=      | ditto                             |
| =, z ,=     | =C-,=      | ditto                             |
| =, c m z m= | =C-c M-m=  | =m z= is replaced with =M-= too   |
| =, m z m=   | =C-M-m=    | ditto                             |

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=.
In order to conveniently set a mark, Devil translates =, z= to =C-=
too, so that we can type =, z SPC= and have Devil translate it to
=C-SPC=.

Also, note how the translation of =, m m= to =M-= allows us to enter a
key sequence that begins with the =M-= modifier key.  Additionally,
consider that =, [= is yet another way to type a key sequence that
contains =M-= because =, [= translates to =C-[= and =C-[ <key>= is
equivalent to =ESC <key>= which in turn is equivalent to =M-<key>=.

The default translation examples presented in the table above look
weirder and weirder as we go down the table.  But the default
translation rules are not as arbitrary as they might initially appear
to be.  The default translation rules are arranged in such a way that
overall, we get the following effect:

- In a Devil key sequence, we see that the special character =,=
  translates to =C-= and similarly =m= translates to =M-= according to
  the default translation rules.

- If we really want the Devil key sequence to translate to an actual
  =,= or =m=, then we need to double type the special character, i.e.,
  in a Devil key sequence, we see that =, ,= translates to =,= and =m
  m= translates to =m=.  Doubling the special character serves as an
  escape mechanism to avoid the special meaning of the character and
  get the literal form of the character instead.

- Now since =, ,= translates to =,= we need another escape mechanism
  to type =C-,=.  Putting =z= in between serves as this escape
  mechanism, i.e., within a Devil key sequence =, z ,= translates to
  =C-,= and similarly =m z m= translates to =M-m=.

Here is a gentle guide to adopting these key sequences: For beginners
using Devil, it is not necessary to memorize all of them right away.
Understanding that =,= translates to =C-= and =m= translates to =M-=
is sufficient to begin.  Subsequently, learning that =, m m= too
translates to =M-= unlocks several more key sequences like =, m m x=
(=M-x=), =, m m f= (=M-f=), etc.  As you encounter more key sequences
that are not covered by these initial rules, revisit the above table
to pick up new translation rules and adopt them in your day-to-day
usage of Devil.

* Describe Devil Key
:PROPERTIES:
:CUSTOM_ID: devil-describe-key
:END:
Devil offers a command named =devil-describe-key= that can be used to
describe a Devil key sequence.  It works similarly to the
=describe-key= command of vanilla Emacs that can be invoked with =C-h
k=.  The =devil-describe-key= command can be invoked with the special
key sequence =, h , k=.  Type =, h , k= and a prompt appears to read a
key sequence.  Type any Devil key sequence, say, =, x , f= and Devil
immediately shows the documentation for the function invoked by this
key sequence.

Note that =, x , f= (=devil-describe-key=) can also be used to look up
documentation for vanilla Emacs key sequences like =C-x C-f=.

Also note that the Devil key sequence is =, h k= is still free to
invoke =C-h k= (=describe-key= of vanilla Emacs).

* Bonus Key Bindings
: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 =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
: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 a package archive like ELPA
or 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
: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_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.

** Custom Appearance
: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 in the Devil prompt.

#+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

** Reclaim , SPC to Set Mark
:PROPERTIES:
:CUSTOM_ID: reclaim-comma-space-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
comma 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
typing the special key =, ,= to insert a literal comma, then use the
following configuration:

#+begin_src elisp
  (require 'devil)
  (global-devil-mode)
  (global-set-key (kbd "C-,") 'global-devil-mode)
  (assoc-delete-all "%k SPC" devil-special-keys)
#+end_src

This removes the special key =, SPC= from =devil-special-keys= so that
it is now free to be translated to =C-SPC= and invoke =set-mark-command=.

** Custom Devil Key
:PROPERTIES:
:CUSTOM_ID: custom-devil-key
:END:
The following initialization code shows how we can customise Devil to
use a different Devil key.

#+begin_src elisp
  (require 'devil)
  (global-devil-mode)
  (global-set-key (kbd "C-;") 'global-devil-mode)
  (devil-set-key (kbd ";"))
#+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
  (require 'devil)
  (global-devil-mode)
  (global-set-key (kbd "C-<left>") 'global-devil-mode)
  (devil-set-key (kbd "<left>"))
  (dolist (key '("%k SPC" "%k RET" "%k <return>"))
    (assoc-delete-all key devil-special-keys))
#+end_src

The above example sets the Devil key to the left arrow key.  With this
configuration, we can use =<left> x <left> f= and have Devil translate
it to =C-x C-f=.  We can type the special key =<left> <left>= to
produce the same effect as the original =<left>=.

The above example removes some special keys that are no longer useful.
In particular, =<left> SPC= is no longer reserved as a special key, so
we can use it now to set a mark.

** 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_src elisp
  (require 'devil)
  (global-devil-mode)
  (define-key devil-mode-map (kbd ".") #'devil)
  (add-to-list 'devil-special-keys `(". ." . ,(devil-key-executor ".")))
  (setq devil-translations '((", z" . "C-")
                             (". z" . "M-")
                             (", ," . ",")
                             (". ." . ".")
                             ("," . "C-")
                             ("." . "M-")))
#+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.  Also =, ,= inserts a literal
comma and =. .= inserts a literal dot.  Further we can type =, z ,= to
get =C-,= and =. z .= to get =M-.=.

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
:PROPERTIES:
:CUSTOM_ID: make-all-keys-repeatable
:END:
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 again.  The repetition occurs as long as the
last character of the repeatable key sequence is typed 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:

#+begin_src elisp
  (require 'devil)
  (setq devil-all-keys-repeatable t)
  (global-devil-mode)
#+end_src

Now 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?
: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, retains the non-modal editing experience of
Emacs as much 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 =ctrl= key on the right side of the keyboard.  Being a
touch-typist myself, I found it inconvenient to type key combinations
like =C-x=, =C-s=, =C-r=, =C-d=, =C=f=, =C-w=, =C-a=, =C-e=,
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 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 non-modal editing experience of vanilla
Emacs as much as possible.

Now it is worth mentioning that some of this non-modal 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 non-modal 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 f=
(=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 f= translates to =C-x f=.  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 , f= translates to =C-x C-f= and =, x f=
translates to =C-x f=.

To summarize, there are primarily three things that Devil does
differently:

- Provide a non-modal 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.

* Frequently Asked Questions
:PROPERTIES:
:CUSTOM_ID: frequently-asked-questions
:END:
01. Why was the comma (=,=) chosen as the default Devil key?  Isn't
    the semicolon (=;=) a better choice since it belongs to the home
    row?

    Opinions vary.  As the author and maintainer of this minor mode, I
    made a choice to use the comma as the default Devil key.
    Although, the semicolon belongs to the home row on most keyboards
    and the comma does not, I find the vertical movement to reach the
    comma key with the long finger more convenient than the horizontal
    movement necessary to reach the semicolon with the little finger.

    As a touch typist, my fingers rest on the eight home row keys when
    idle.  The horizontal movement necessary to type the semicolon
    leads to a significant angular movement of the wrist.  Curling my
    long finger to reach the comma key helps me avoid this wrist
    strain.  If you do not like this default, it is quite easy to
    customise the Devil key to be the semicolon or any other key of
    your choice.  See the section [[*Custom Devil Key]] to learn how to do
    this.

02. I am happy with typing =, ,= every time, I need to type a comma.
    Can I free up =, SPC= to invoke =set-mark-command=?

    Yes, this can be done by removing the special key =, SPC= from
    =devil-special-keys=.  See the section [[*Reclaim , SPC to Set Mark]]
    to find out how to do this.

03. Can I make the Devil key sticky, i.e., can I type =, x f= instead
    of =, x , f= to invoke =C-x C-f=?

    Devil does not support sticky keys.  Say, Devil were to translate
    =, x f= to =C-x C-f=, how then would you invoke =C-x f=?  We need
    some way to disambiguate between =C-x C-f= and =C-x f=.  Different
    tools take different approaches to disambiguate the two key
    sequences.  For example, god-mode translates =x f= to =C-x C-f=
    and =x SPC f= to =C-x f=.  That is, God-mode treats the =C-=
    modifier as sticky by default but when we want to make it
    non-sticky, we need to type =SPC= in god-mode.

    Devil treats the Devil key as non-sticky, so that there is no need
    for additional peculiar rules to switch between sticky and
    non-sticky behaviour to disambiguate key sequences like =C-x C-f=
    and =C-x f=.  With Devil =, x , f= translates to =C-x C-f= and
    similarly =, x f= translates to =C-x f=.  The translation rules
    are simpler at the cost of a little additional typing.  In most
    cases, Devil requires typing an additional comma that one might
    have avoided if the comma were sticky.  This little additional
    typing becomes muscle memory in no time.

04. Are there some things that are easier to do with Devil than
    god-mode?

    Devil is not necessarily easier than god-mode.  It is different.
    Preferences vary, so some may find Devil easier to use while some
    others may find god-mode easier to use.  See the section
    [[*Comparison with God Mode]] for more details on the differences
    between the two modes.

* Conclusion
:PROPERTIES:
:CUSTOM_ID: conclusion
:END:
Devil is a minor mode to translate key sequences.  Devil utilizes this
translation capability to provide a modifier-free editing experience
and it does so without resorting to modal-editing.  Devil retains the
non-modal editing of vanilla Emacs as much as possible.  This mode was
written as a quirky experiment to make it easier to use Emacs with
only one =ctrl= key.  However, the resulting mode turned out to be
quite convenient to use, in general.  You might find Devil
comfortable.  Or you might find Devil to be a terrible idea.  It is
also possible that you might find Devil useful but intrusive.  In such
cases, there are plenty of customisable options that you can modify to
configure Devil according to your preferences.  If you need any help
or if you find any issues, please create an issue at
[[https://github.com/susam/devil/issues]].
