Improved and consistent line selection with X and <a-X>

Ever since Kakoune made the x key more predictable, I missed the easier way it provided to select new lines. However, I still prefer the new x behavior.

The solution was to either xJJJJ or JJJJx. This was good because it also worked upwards, by using K instead of J.

After some tweaking, I found a couple of mappings that are so good, I think they should even be hard-coded:

map -docstring 'extend lines downwards' global normal X %{<a-:>F<ret>x}
map -docstring 'extend lines upwards' global normal <a-X> %{<a-:><a-;><a-H>Kx}

I think this configuration makes a ton of sense and matches the behavior of other commands in Kakoune, such as / to search, ? to extend, and the alt- variants to do it backwards.

What do you think?

2 Likes

I like how <a-X> works.

X seems not to extend to next line if itā€™s empty. Changing T to F fixes that -

map -docstring 'extend lines downwards' global normal X %{<a-:>F<ret>x}

Didnā€™t test much, donā€™t know if it causes other issues.

1 Like

Well spotted, thank you!
Modifying the original post, so that people donā€™t copy it by mistake.

By the way, is it normal that mappings donā€™t work with a count? I would expect to be able to do 3X to extend the selection by 3 lines.

The right-hand-side of a mapping can use the %val{count} expansion to apply the active count to whichever parts of the mapping itā€™s relevant for. Unfortunately it defaults to 0 rather than 1, but 0 is not a normal-mode command so if youā€™re just prefixing to a different normal-mode command it should be fine:

map -docstring 'cool j' global user j %{:exec "%val{count}j:echo cool!<lt>ret>"<ret>}

Test with 5<space>j.

Note: You need the :exec in the mapping so that %val{count} is not expanded until the mapping is executed, rather than when the mapping was defined.

2 Likes

Thank you! Iā€™ve submitted a PR, to see if thereā€™s interest in having this in Kakoune by default:

1 Like

This was useful after I upgraded Kakoune and my old configuration (which used the X command that seems to have disappeared) broke. In fact, I map "x" instead of "X" because I use this so much.

I was completely used to typing xx to select two lines and would have been lost without this.

I think this definition is more consistent:

map -docstring 'extend lines downwards' global normal X %{<a-:><a-L>Jx}

ā€¦not just in code similarity but also in behaviour: in the original version, pressing X selects one line but <a-X> immediately selects 2 - now both versions start with 2 lines selected (and if you want just one, well thereā€™s good olā€™ x).

Thanks for sharing.

define-command select_whole_lines_or_extend_lines_down %{
  try %{
    # At least one selection is not full, so select whole lines.
    execute-keys -draft '<a-K>\A^.*\n\z<ret>'
    execute-keys '<a-:>x'
  } catch %{
    execute-keys '<a-:>Jx'
  }
}

map -docstring 'select whole lines or extend lines down' global normal x ':select_whole_lines_or_extend_lines_down<ret>'
map -docstring 'select whole lines' global normal X x