Skip to content

Commit

Permalink
helix: make movement commands in normal mode never select
Browse files Browse the repository at this point in the history
Previously, doing `e` in normal mode would select everything until the
end of the current word. This differed from `e` in select mode in only
one way: the select mode bind would keep the selection on subsequent
key presses, while in normal mode, it would immediately forget the
previous selection.

Now, `w` and `e` don't select at all. This gives them a clearer
difference from select mode. `w` works with BEGINNINGS, while `e` works
with ENDS.

`e` is the most useful for going forward, since it will go
until the end of the current word. This matches the behavior seen in
Ctrl+→ in typical text editors. It's less useful going backwards, since
it matches the *end* of the previous word.

`w` is less useful for going forward, where it jumps to the beginning of
the next word. However, when going backward, it jumps to the beginning of
the current word. This matches the behavior of Ctrl+←.

These commands each have a variant with WORDS instead of words, triggered
using Alt.

In the future, we may change the way these are split. Rather than having
`e` be good for going forward, and `W` be good for going backward, we
could have the core functionality integrated into one key. But that's for
a later commit.
  • Loading branch information
llakala committed Nov 1, 2024
1 parent 9b0f8b4 commit 721eb04
Showing 1 changed file with 76 additions and 39 deletions.
115 changes: 76 additions & 39 deletions apps/cli/helix/keybinds.nix
Original file line number Diff line number Diff line change
@@ -1,62 +1,99 @@
let navigationBinds = type: # Use the same binds for both normal and select mode, but movement binds work as intended in select mode
{
# Select next word, plus extra space afterwards. Good for adding on via `w+a`
w = "${type}_next_word_start";
W = "${type}_prev_word_start";
A-w = "${type}_next_long_word_start"; # alt-w
A-W = "${type}_prev_long_word_start"; # alt-shift-w
let
moveAndDeselect = action:
if builtins.isString action then
[ action "collapse_selection" ]
else if builtins.isList action then
action ++ [ "collapse_selection" ]
else throw "Action ${action} was of type ${builtins.typeOf action}. It was expected to be a list or a string.";


sharedBinds = # Binds that should work in both normal and select mode
{
# Select next word, with no spaces selected at all. Great for replacing via `q+c`
q = "@emiw"; # Uses macros, added in unstable helix version
A-q = "@emiW";

# Select next word, plus a space prior. Good for deletion via `e+d`
e = "${type}_next_word_end";
E = "${type}_prev_word_end";
A-e = "${type}_next_long_word_end"; # alt-e
A-E = "${type}_prev_long_word_end"; # alt-shift-e

# Select next word, with no spaces selected at all. Great for replacing via `q+c`
q = "@emiw"; # Uses macros, added in unstable helix version
A-q = "@emiW";
space.x = ":toggle whitespace.render all none"; # ` x` shows whitespace

C-r = ":config-reload"; # Ctrl+r. Would ideally be :cr, but no way to make custom command aliases :(

space.x = ":toggle whitespace.render all none"; # ` x` shows whitespace

C-r = ":config-reload"; # Ctrl+r. Would ideally be :cr, but no way to make custom command aliases :(
X = "extend_line_above"; # Select line upwards

# Use system clipboard everywhere
y = "yank_to_clipboard";
p = "paste_clipboard_after";
P = "paste_clipboard_before";
R = "replace_selections_with_clipboard"; # Easier d+p

X = "extend_line_above"; # Select line upwards
# Don't yank when deleting and changing
d = "delete_selection_noyank";
c = "change_selection_noyank";

# Use system clipboard everywhere
y = "yank_to_clipboard";
p = "paste_clipboard_after";
P = "paste_clipboard_before";
R = "replace_selections_with_clipboard"; # Easier d+p
H = "goto_first_nonwhitespace";
L = "goto_line_end";

# Don't yank when deleting and changing
d = "delete_selection_noyank";
c = "change_selection_noyank";
# More ergonomic alternative to `><`
tab = "indent";
S-tab = "unindent";

H = "goto_first_nonwhitespace";
L = "goto_line_end";
up = "no_op";
down = "no_op";
left = "no_op";
right = "no_op";

# More ergonomic alternative to `><`
tab = "indent";
S-tab = "unindent";
b = "no_op";
B = "no_op";
A-b = "no_op";
A-B = "no_op";

up = "no_op";
down = "no_op";
left = "no_op";
right = "no_op";
};

};
in
{
hm.programs.helix.settings.keys =
{
# Normal and select use the same custom binds, but normal moves the selection, while select extends the selection
normal = navigationBinds "move" //
normal = sharedBinds //
{
# Beginning of next word
w = moveAndDeselect [ "move_next_word_start" "move_char_right" ];
A-w = moveAndDeselect [ "move_next_long_word_start" "move_char_right" ];

# Beginning of current word
W = moveAndDeselect "move_prev_word_start";
A-W = moveAndDeselect "move_prev_long_word_start";

# End of current word
e = moveAndDeselect "move_next_word_end";
A-e = moveAndDeselect "move_next_long_word_end";

# End of previous word
E = moveAndDeselect "move_prev_word_end";
A-E = moveAndDeselect "move_prev_long_word_end";


esc = "keep_primary_selection"; # Escape also removes cursors, like `,`
};

select = navigationBinds "extend";
select = sharedBinds //
{
# Beginning of next word
w = "extend_next_word_start";
A-w = "extend_next_long_word_start";

# Beginning of current word
W = "extend_prev_word_start";
A-W = "extend_prev_long_word_start";

# End of current word
e = "extend_next_word_end";
A-e = "extend_next_long_word_end";

# End of previous word
E = "extend_prev_word_end";
A-E = "extend_prev_long_word_end";
};

insert = # And we WILL only use normal mode for moving around
{
Expand Down

0 comments on commit 721eb04

Please sign in to comment.