Nyaatouch is a highly ergonomic dvorak modal editing scheme for emacs. It is built on the meow modal framework (hence the name), which I also help maintain. Lots of code has been upstreamed into meow to make this system possible. If you’re stumbling onto this repository and you either don’t use dvorak or would like something a little more traditional but still efficient, I’d suggest checking that project out first.
Meow is a fantastic platform to build a custom editing scheme on for several reasons
- minimal configuration (no keybindings by default!!)
- self contained, with no dependencies
- allows truly arbitrary keybindings by key macros, which gives a lot of freedom
- makes it very easy to create custom modal states
If you’re interested in more about why vanilla meow is neat, especially in contrast to something more traditional like vim or kakoune you might like this blog post I wrote.
This package pulls in some other packages I find absolutely necessary for editing programs:
- avy - jumping to places
- swiper - extremely neat incremental searcher
- smartparens - generic bracket manipulation
Nyaatouch is essentially my personal config, except when I realized that just my editing related config had grown to nearly 300 lines and resembled nothing else I know of, I decided to create a package for it.
Nyaatouch is exclusively and strongly focused on ergonomics. This means that ideas like mnemonic commands and the like totally go out the window – keys are assigned to commands based on position, comfort, and frequency.
Spatially assigned keys take strong influence from dvorak, which emphasizes alternating hands by spatially separating the vowels and consonants. In nyaatouch, this is achieved by spatially separating selections and actions on selections. This means that a wide variety of useful things can be done by a near instant hand alternation, often without even moving your hands from the home row.
For instance, deleting a word in nyaatouch is es
, which is far more
comfortable than say, diw
in either qwerty or dvorak vim. There’s also
a lot more abstraction and consistency in the notion of formalized
“things” and the alternation pattern.
Selecting inside a matched pair of parens, copying the contents,
moving a line below and then pasting is idhD
. Compare this to
vi(yp
. Unusable on dvorak!
Another key change that nyaatouch makes is to swap C-x to C-u. This is
stolen from the emacswiki, and is a genius idea. C-u is not used
nearly as often, and putting it under the pointer is super neat, for
example saving file is basically free with holding control and
pressing the hand alternating sequence us
. This is why I didn’t remap
it into the leader like I did with many other uncomfortable C-x
bindings that are still bad with this modification.
For some time, i experimented with putting the movement keys on fgcr. I think this definitely has some merits, especially with regards to consistency, but it also has two practical problems.
- Loss of alternation. With insert on j and the movement keys on top row, you lose some alternation action. After all, insert is rarely pressed with a selection active. The only reason to select something is to act on it directly.
- gc are important. in magit for instance, g is refresh and c is commit. These are nice keybindings, and I don’t want to change them.
The compromise that I use here is to put up/down back on the home row, but leave left and right, which are less used, on the top row. Now that c is free though, we can shift right to be on c, where it is slightly more comfortable.
The other compromise made for this is to move open new line up to g. Change/replace on a selection is far too essential to leave the home row in an alternation focused layout, and is therefore on n.
Meow Cheatsheet ┏━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━━━━━┓ ┃ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ { │ } │ BKSP ┃ ┃ | | | | | | | | case| | | | | ┃ ┠─┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┤ ┃ ┃ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ [ │ ] │ ┃ ┃ | ex →1| ex →2 ex →3 ex →4 ex →5 ex →6 ex →7 ex →8 ex →9 ex →0 | | ┃ ┠─────────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────┴───┬─────────┨ ┃ TAB │ " │ < │ > │ P │ Y │ F │ G │ C │ R │ L │ ? │ + │ | ┃ ┃ | ←find| ←thing thing→ ex ← open ↑ ex → undo-sel nt-dupli… +num ├┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┨ ┃ │ ' │ , │ . │ p │ y │ f │ g │ c │ r │ l │ / │ = │ ┃ ┃ | find|←thing→| [thing] join ← open ↓ → del undo nt-dupli… \ ───────────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─┬───────┴─────────┨ ┃ │ A │ O │ E │ U │ I │ D │ H │ T │ N │ S │ _ │ ┃ ┃ | | [str]| ←sym→| insert block-ex… yank ex ↓ ex ↑ rep -1 ┃ ┃ ├┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┤ ┃ ┃ │ a │ o │ e │ u │ i │ d │ h │ t │ n │ s │ - │ ┃ ┃ | line| ←str→| ←word→ ins. block save ↓ ↑ chg kill swiper ┃ ┠───────────────┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────┬───┴─────────────────┨ ┃ │ : │ Q │ J │ K │ X │ B │ M │ W │ V │ Z │ ┃ ┃ | | | | ←sym| sym→ ┃ ┃ ├┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┼┄┄┄┄┄┄┄┄┄┤ ┃ ┃ │ ; │ q │ j │ k │ x │ b │ m │ w │ v │ z │ ┃ ┃ | reverse| quit| grab| ←word| word→ paren-mo… avy-goto… quit sel repeat pop-sel ┃ ┗━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━╅─────────┴─────────┴─────────┴─────────╆━━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━┛ ┃ SPC ┃ ┃ ┃ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ NOTE: ex means this command will expand current region. ←thing→ (inner), [thing] (bounds), ←thing (begin) and thing→ (end) require a THING as input: latex -> x round -> r square -> s curly -> c string -> g symbol -> e window -> w buffer -> b paragraph -> p line -> l defun -> d sentence -> .
- 1..9
- expansion hints
- *
- toggle case with intelligent behavior. see source for details.
- ‘
- prompt for char and find forward
- “
- prompt for char and find backward
- ,
- meow’s inner of thing, selects some object without the delimiters
- .
- meow’s bounds of thing, selects some object with the delimiters
- <
- beginning of thing
- >
- end of thing
- p
- meow-join, selects from the last char of the previous line to the first char of the current line
- f
- move left
- g
- open down
- G
- open up
- c
- move right
- r
- delete one char
- FCHT
- expand selection in corresponding direction
- l
- undo
- /
- Duplicate
- ?
- Duplicate and comment the duplicated thing
- +
- add one to number under point. accepts numeric prefix arg.
- a
- select line
- o
- select inside string *
- O
- select whole string
- e
- select word
- E
- select symbol (according to symbol table)
- u
- insert AT CURSOR. This is different from meow-insert.
- U
- standard meow-insert
- i
- select block (matching parens)
- d
- yank, copy.
- D
- paste
- h
- move down
- t
- move up
- n
- change
- N
- replace
- S
- kill.
- -
- swiper (better incremental search)
- _
- subtract one from the number under point. Accepts prefix arg.
- ;
- exchange point and mark, reverse hint direction
- q
- quit
- j
- enter meow’s standard beacon state
- k
- back word
- x
- forward word
- K, X
- back and forward symbols
- b
- enter paren state
- m
- cancel selection
- w
- repeat command
- z
- pop selection marker
The parenthesis state is a custom nyaatouch state to facilitate dealing with pairs of characters. It uses smartparens as a backend for most commands.
- fgcr
- movement
- o + {s, r, c, g}
- wrap with square, round, curly, string
- O
- unwrap
- b
- slurp
- x
- barf
- k
- back barf
- j
- back slurp
- s,S
- splice forward and back
- e
- end of sexp
- a
- beginning of sexp
- G
- goto top level paren
- y, Y
- transpose, forward and back
- l
- undo
- a
- M-x (extended command)
- e
- C-x b (switch buffer)
- o
- C-h (help prefix)
- u
- C-x C-f (find file)
- h
- C-x o (other window) on my setup this is actually ace-window.
- t
- C-x 0 (close window)
- T
- C-x 1 (close every other window but this one)
- n
- C-x 3 (vert split)
- N
- C-x 2 (horiz split)
- ,
- maps to g in programs that need g like magit
- .
- maps to c in programs that need it
- l
- toggle meow using the system clipboard
- x
- selects latex objects. These can be begin/end envs, parens or dollar signs.
In the off chance you’re crazy enough to give this a shot, you can either download the file and add it to your load-path, or use this MELPA-flavor recipe:
'(nyaatouch :repo "https://github.com/eshrh/nyaatouch" :fetcher github)
You can give that list to straight-use-package or whatever other program you may use. Then, usage is just:
(require 'nyaatouch)
(turn-on-nyaatouch)
turn-off-nyaatouch
also exists and may be of interest.