The arrow cluster
One of the most famous lore about vim and its derivative like kakoune is the use of h
j
k
l
as arrow keys.
This keys placement is often lauded by the users of these editors as a power-feature because the fingers barely have to move from the home-row of the keyboard.
Strangely, this kind of spatial considerations is almost unique to the h
j
k
l
cluster. Other keys tend to be placed on the keyboard according to some mnemonics related to their name.
Non exhaustive examples using the āfirst letterā:
-
w
for Word or Window -
f
for Find -
b
for Backward or Before -
n
for Next -
p
for Previous or Paste - ā¦
More extreme examples, coming from regexp notation:
-
^
for Goto first non-blank char of line -
$
for Goto end of the line
So as we can see the rules to affect a command to a key are quite arbitrary.
But letās focus back on the arrow cluster and on kakoune.
-
h
,j
,k
,l
move the selection by 1 char -
shift
+h
,j
,k
,l
extend the selection by 1 char (or line)
These 2 sets of keys above are coherent.
The discrepancy appears when the alt
modifier is involved.
Good:
-
alt
+h
,alt
+l
select to line begin / end
Less good:
-
alt
+j
Join lines (legacy from vim) -
alt
+k
Keep matching selections (in vimK
opens thekeywordprg
)
Suddenly the āspatial traitā of j
and k
are exchanged for the āmnemonic traitā.
Arguably, joining lines is a pretty common operation, but filtering selections on a regex is less common (at least in my usage of kakoune, your mileage may vary).
This got me thinking:
Should these 2 commands move somewhere else? If so, which commands should take their place?
The ctrl modifier
But before diving into these questions, we should address the elephant in the room: what about the ctrl
modifier?
Because of well-known historical reasons dating back to the prehistory of computers, terminal generate ambiguous keys for the following scenarios:
-
ctrl
+i
ātab
-
ctrl
+m
āret
More painfully related to our present discussion:
-
ctrl
+h
ābackspace
-
ctrl
+j
āret
Which means that in a regular setup, our mighty arrow cluster is amputated of the h
and j
keys when used with the ctrl
modifier.
One could argue that vim and kakoune try to minimize the use of actions involving modifiers. (a great counter example in vim world is the u
/ ctrl
+ r
combo).
I agree that commands involving 2 modifiers like shift
+ alt
+ k
are indeed cumbersome to type. But on the contrary, commands where the left ctrl
(pinky because remapped on caps-lock) and left alt
(under the thumb) is pressed
in combination with a right-handed letter (like our h
, j
, k
, l
candidates here) are quite comfortable (for my hands at least).
Therefore, what would happen if we were able to disambiguate the ctrl
+ h
and ctrl
+ j
, to claim back the arrow cluster? Along the years, attempts have been made to fix this problem, most notably libtermkey
. Kitty, also offers an interesting fullkbd
mode but kakoune CSI parser needs to be adapted to take this protocol into account (in the future maybe?). But right now, we can nevertheless use kitty to build our own āhackyā solution.
~/.config/kitty/kitty.conf
map ctrl+h send_text all \u24D7
map ctrl+i send_text all \u24D8
map ctrl+j send_text all \u24D9
map ctrl+m send_text all \u24DC
These unicode code-points have been chosen because they are rare in the wild and their representation is a circled letter like this: ā (\u24D8).
Thanks to this āhackā (which can be adapted to other terminal emulators having remapping capabilities), we can now use these chars in kakoune mapping, like I will show in the rest of this post.
Adapting the layout
Without further ado, letās discover my current experiment resuming all of the above observations. (I stress out the word experiment as itās by no means a definitive stance)
Letās free the alt
+ k
(and alt
+ K
) key, by moving it to the D
(and alt
+ D
) key. The mnemonic kind of work. Regular d
ādelete the content of selectionsā, whereas this new D
ādelete the selections themselvesā.
Letās free the alt
+ j
(and alt
+ J
) key, by moving it in place of C
(and alt
+ C
). This time the mnemonic can be āCombine linesā.
Now that they are free, letās affect them a duo of commands that are often requested in the GitHub issues. Kakoune offers the X
key to extend down, but has no equivalent to extend up.
Hopefully, many users provided dedicated commands like these ones:
define-command -hidden -params 1 extend-line-down %{
execute-keys "<a-:>%arg{1}X"
}
define-command -hidden -params 1 extend-line-up %{
execute-keys "<a-:><a-;>%arg{1}K<a-;>"
try %{
execute-keys -draft ';<a-K>\n<ret>'
execute-keys X
}
execute-keys '<a-;><a-X>'
}
So we can map alt
+ k
to extend-line-up
and alt
+ j
to extend-line-down
.
But āwhat about the C
and alt
+ C
key you sacrificed earlier?ā you may asked.
Hereās where hacking the ctrl
key becomes very handy. Because we can now map C
(copy selection to next line) to ctrl
+ j
and alt
+ C
to ctrl
+ k
!
map global normal ā 'C' -docstring 'copy selection on next line'
map global normal <c-k> '<a-C>' -docstring 'copy selection on previous line'
Iām still thinking about what would be a great choice for ctrl
+ h
and ctrl
+ l
to complement this arrow. It could be to generate arbitrary selections on the left/right of the same line. (WIP)
Conclusion
Overall it feels very natural to gain back the āspatial attributesā of h
j
k
l
with the shift
, alt
or ctrl
modifiers.
I also try to apply the same philosophy when designing user-modes
, privileging this arrow for commands having a before / after
or next / previous
behaviors.