Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keymap change proposal: extending lines in both directions #2130

Closed
EpocSquadron opened this issue Apr 16, 2022 · 14 comments
Closed

Keymap change proposal: extending lines in both directions #2130

EpocSquadron opened this issue Apr 16, 2022 · 14 comments
Labels
A-keymap Area: Keymap and keybindings C-discussion Category: Discussion or questions that doesn't represent real issues C-enhancement Category: Improvements

Comments

@EpocSquadron
Copy link
Contributor

EpocSquadron commented Apr 16, 2022

Context and Motivation

There have been a few discussions regarding the behavior of x in various places (#165, #1638), but it feels like maybe the community is starting to trend in a particular, actionable direction (judging by matrix discussion, new user input, and recent change in kakoune) that I would like to propose in isolation here.

Goals

  • Add upward equivalent of x (commonly requested)
  • Keep current behavior of x accessible (people seem to like it as a shortcut/cheat rather than puzzling out which textobject or tree-sitter nav would work best in a given situation)
  • Obtain consistency with how other movement commands interact with extension (general trend in keymap changes historically)

Dependencies

Proposed Change

Terminology

"At bounds" refers to when all selections have their head/cursor/selection start and anchor/selection end on the first or last character (not including the newline) of any line.

NORMAL Mode (not at bounds)

  • x = extend to line bounds, ensure cursor forward
  • X = extend to line bounds, ensure cursor reverse
  • (Optional) Alt-x = extend to line bounds, do not alter selection direction

NORMAL Mode (at bounds)

  • x = select next full line (not extending), cursor forward
  • X = select previous full line (not extending), cursor reverse
  • (Optional) Alt-x = extend to line bounds, do not alter selection direction

SELECTION Mode (not at bounds)

Same as NORMAL (not at bounds)

SELECTION Mode (at bounds)

  • x and X same as NORMAL (at bounds), but extending
  • (Optional) Alt-x = add one line above and below, do not alter selection direction

Configuration for Testing

Add this to your config.toml in combination with running from the #2117 PR in order to see 95% how this would work as described above. The caveat being that the intelligent behavior of only extending the current selections to line bounds on the first press doesn't work as intended for most invocations, as there is no detection possible without code alteration.

[keys.normal]
x = ["move_line_down", "extend_to_line_bounds"]
X = ["move_line_up", "extend_to_line_bounds"]
"A-x" = "extend_to_line_bounds"

[keys.select]
x = "extend_line"
X = "extend_line_above"
"A-x" = ["extend_line_above", "extend_line"]

See it in action

Here are some examples of the above config in action, keeping in mind the caveats.

x and X in NORMAL:

asciicast

x and X in SELECTION:

asciicast

Alt-x in NORMAL:

asciicast

Alt-x in SELECTION:

asciicast

Considerations

I think this has a lot of nice properties, such as symmetry and a good interaction with SELECTION mode. I'll add examples tomorrow that showcase them. It does however introduce the need to switch to SELECTION to reproduce the current behavior. This could also be a good thing as it builds habits that transfer to other motion commands. I also chose not to bind the current behavior of X to any key, as its existence seems more tied to its historical use in consistency while scripting kakoune than any practical use case (the functionality is available just not idempotently).


Alternative Proposal

NORMAL (at bounds)

  • x = add line below to selection (current behavior) + ensure cursor forward (current behavior?)
  • X = ensure cursor reverse, add line above
  • (Optional) Alt-x = add one line above and below, do not alter selection direction

NORMAL (not at bounds)

Same as SELECTION

SELECTION

  • x = extend to line bounds, ensure cursor forward
  • X = extend to line bounds, ensure cursor reverse
  • (Optional) Alt-x = extend to line bounds, do not alter selection direction

Considerations

x and friends never add new lines in SELECTION in this version.

This is less consistent with how other movements and SELECTION mode interact, but keeps almost the exact current behavior of x to avoid rocking the boat.

@EpocSquadron EpocSquadron added the C-enhancement Category: Improvements label Apr 16, 2022
@tmke8
Copy link

tmke8 commented Apr 16, 2022

So, x will behave differently if the cursor happens to be at the end of a line? Or what does “at bounds” mean?

EDIT: why not just let x do in SEL mode what does X currently?

@EpocSquadron
Copy link
Contributor Author

Typed this up at 3am sorry about the confusing jargon. "At bounds" means the whole line is already selected (cursor heads and anchor are at the boundaries of the line).

I thought it would be nice and consistent if x was essentially the "by line motion command", so it should advance a line in SEL as well as NOR.

@EpocSquadron
Copy link
Contributor Author

I thought of an edge case I did not cover, which is if you have two selections, one of which covers the whole line and the other of which does not. I feel like in this instance a single press of either x or X should act on the way X does currently -- expanding all selections to whole lines and ensuring cursor direction but not adding a new line to any. A subsequent press would then consistently expand all selections by one line.

@EpocSquadron
Copy link
Contributor Author

An optional extension to this could be to add alt-x (currently unbound) which would add a line above and below at the same time. It would also act as the current X until all selections were fully covering lines.

@EpocSquadron
Copy link
Contributor Author

I've edited the description to take into account clarifications and additions from conversation up to this point.

@the-mikedavis
Copy link
Member

I like the x change 👍. I would probably prefer to keep the current behavior in my own keymap because of muscle memory but I think what you describe might be a good default as it's more consistent with select mode.

The current X is useful in the scenario where you want to delete a line and don't want to think about what's on it: Xd will delete the current line no matter if it's empty or has contents. To put it another way, you don't need to care if the selection is at bounds.

x with respect to moving "up" (towards previous lines) always confuses me because there are really 4 points of control you might want to change: move up/down the bottom of the selection and move up/down the top of the selection. IMO for a complicated change like that it's better to go into selection mode, align your cursor direction with A-; and use j and k, and eventually using x to make the selection line-wise. I don't find myself wishing for an upwards x but maybe that's just me 🙃

@the-mikedavis the-mikedavis added the C-discussion Category: Discussion or questions that doesn't represent real issues label Apr 16, 2022
@EpocSquadron
Copy link
Contributor Author

The current X is useful in the scenario where you want to delete a line and don't want to think about what's on it: Xd will delete the current line no matter if it's empty or has contents. To put it another way, you don't need to care if the selection is at bounds.

This would be covered by Alt-x in my proposal.

x with respect to moving "up" (towards previous lines) always confuses me because there are really 4 points of control you might want to change: move up/down the bottom of the selection and move up/down the top of the selection. IMO for a complicated change like that it's better to go into selection mode, align your cursor direction with A-; and use j and k, and eventually using x to make the selection line-wise. I don't find myself wishing for an upwards x but maybe that's just me upside_down_face

I have been observing a lot of people in matrix make the request for moving up, but I see your perspective as well. In my view, if you want to move the bottom of the select upwards (as opposed extend to additional lines on top), that's a good use case for j/k and Alt-x in a similar vein to what you mention.

@EpocSquadron
Copy link
Contributor Author

I've updated the description to include an example keymap and asciinemas of the proposal in action for easier consideration.

@AntonioLucibello
Copy link
Contributor

AntonioLucibello commented Apr 16, 2022

Another option is to bind an eventual move_selection_up and move_selection_down to alt-k and alt-j (or alt-up and alt-down): this way you retain continuity with current behavior in that x selects lines and navigation keys move cursors, and you don't have to exit normal mode to select lines which is a very common action, arguably more than moving selections up and down.

As for mapping X to extend_line_above, I think that's a good idea, seeing as it's the same behavior as o=open_below and O=open_above

@EpocSquadron
Copy link
Contributor Author

Another option is to bind an eventual move_selection_up and move_selection_down to alt-k and alt-j (or alt-up and alt-down): this way you retain continuity with current behavior in that x selects lines and navigation keys move cursors, and you don't have to exit normal mode to select lines which is a very common action, arguably more than moving selections up and down.

Alt-j and friends are already used for selecting up and down the AST with tree-sitter (super useful btw). I was thinking that x really is a movement key that happens to also select. If you press w repeatedly, you select the next word one at a time, losing your selection to the previous as you go, unless you toggle selection mode on with v first. Similarly, moving to the next search match is n, going backwards is N and you can retain each match as a selection as you move through by toggling on selection mode with v. The behavior I've outlined is consistent with those patterns.

That said, I understand that people are used to being able to mash x repeatedly as a shortcut to selecting a bunch of lines, and that requiring v first introduces friction that doesn't currently exist. That's a trade-off I am comfortable with, but I did put forth the alternative bindings which keep x as selecting and flip it around when in selection mode.

As for mapping X to extend_line_above, I think that's a good idea, seeing as it's the same behavior as o=open_below and O=open_above

👍

@Omnikar
Copy link
Contributor

Omnikar commented Apr 17, 2022

That said, I understand that people are used to being able to mash x repeatedly as a shortcut to selecting a bunch of lines, and that requiring v first introduces friction that doesn't currently exist.

I've expressed my opinion about this before that I personally really don't like the inconvenience this introduces. The current behaviour of x makes selecting multiple lines an extremely fast action that doesn't require much thought at all and was honestly one of my favourite things about Helix when switching from Vim. I also don't see the use of the proposed new behaviour for x; that sort of behaviour makes sense for something like w because it's for movement and for selection. But with x, the movement aspect can be achieved with j and k; x is just for selecting and shouldn't require extend mode enabled to be useful.

@AntonioLucibello
Copy link
Contributor

AntonioLucibello commented Apr 17, 2022

x with respect to moving "up" (towards previous lines) always confuses me because there are really 4 points of control you might want to change: move up/down the bottom of the selection and move up/down the top of the selection.

I don't think it's confusing that extend_line_above would extend the selection upwards, as opposed to removing it from the bottom.

IMO for a complicated change like that it's better to go into selection mode, align your cursor direction with A-; and use j and k, and eventually using x to make the selection line-wise.

For more fine grained control like you're describing (ie moving upward bounds of the selection down and downward bounds up), I think it's reasonable to enter select mode.

@tmke8
Copy link

tmke8 commented Apr 18, 2022

I don't think hitting x repeatedly to select multiple lines is that nice, for mainly two reasons: 1) x is in a slightly uncomfortable position on the keyboard (compared to keys on the home row) and 2) there are already keys to move up and down: j and k.

The existing x command is a bit awkward for other reasons as well: it extends the selection even if you're not in SEL mode and it works differently on an empty line. (The first one would be fixed by OP's proposal, but not the second, I think.)

So, my suggestion would be to go all in on extend_to_line_bounds (currently mapped to X by default) and to map this command to x. We would then have:

  • xd to delete one line (also works on empty lines!), compare to dd in vim
  • vjjxd to delete 3 lines, compare to Vjjd in vim

To make that last one even shorter, we could map D (currently unmapped I think) to be equivalent to xd, so that we'd have

  • vjjD to delete 3 lines

You could also map C to be equivalent to xc and use X for adding a cursor below (which is currently mapped to C):

  • vjjC to delete 3 lines and enter insert mode

Y also seems to be unmapped, so it can be used for xy.

EDIT: to try it out

[keys.normal]
"x" = "extend_to_line_bounds"
"X" = "copy_selection_on_next_line"
"D" = ["extend_to_line_bounds", "delete_selection"]
"C" = ["extend_to_line_bounds", "change_selection"]
"Y" = ["extend_to_line_bounds", "yank"]
[keys.select]
"x" = "extend_to_line_bounds"
"X" = "copy_selection_on_next_line"
"D" = ["extend_to_line_bounds", "delete_selection"]
"C" = ["extend_to_line_bounds", "change_selection"]
"Y" = ["extend_to_line_bounds", "yank"]

@EpocSquadron
Copy link
Contributor Author

Closing as this never gained traction and there are arguably too many users nowadays for fundamental changes like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-keymap Area: Keymap and keybindings C-discussion Category: Discussion or questions that doesn't represent real issues C-enhancement Category: Improvements
Projects
None yet
Development

No branches or pull requests

5 participants