Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Remove yank behavior of c and d #3001

Closed
samholmes opened this issue Jul 7, 2022 · 19 comments
Closed

Remove yank behavior of c and d #3001

samholmes opened this issue Jul 7, 2022 · 19 comments
Labels
A-keymap Area: Keymap and keybindings C-discussion Category: Discussion or questions that doesn't represent real issues

Comments

@samholmes
Copy link

I think Vim made a mistake by letting c and d pollute the default register by "yanking" the contents of the change or deletion. I'll make a short case as to why I think Helix should make a bold decision to not do this like vim (and maybe even kak).

Why not?

The reason why d and c should not also yank is simple, because you can yank before d and c easily with y. You cannot as easily "prevent yank" without knowing about registers and particularly the black-hole register "_; so you're left with "_d or "_c which is too often a use-case to make it not the default behavior. The times when you want to yank before a modification is easily opt-in with yd and yc. Simply put, the answer why the default behavior should be inverted: it's the correct UX.

Note, in View mode, y does not remove the selection like it does in vim. This positions Helix to be able to even consider the correct behavior.

With the correct default behavior in place, users can edit happily knowing that when they copy something to their default register many modifications back in their history, they will not accidentally overwrite the default register with d and c. The foot-gun has been holstered.

How do we migrate?

Some users (vim and kak alike) will not expect this change and will perhaps not like to modify their habit. However, this could easily be mitigated with a config to change the default behavior back (which is what user's do already). If a user doesn't like the position Helix makes, they can modify the behavior or change their habits.

Please.

@the-mikedavis the-mikedavis added C-discussion Category: Discussion or questions that doesn't represent real issues A-keymap Area: Keymap and keybindings labels Jul 7, 2022
@the-mikedavis
Copy link
Member

This is currently implemented in the delete_selection_noyank (A-d) and change_selection_noyank (A-c). You can switch the keybinds in your config.toml:

# ~/.config/helix/config.toml
[keys.normal]
A-d = "delete_selection"
d = "delete_selection_noyank"
A-c = "change_selection"
c = "change_selection_noyank"

I'm not sure it makes sense for this to be the default keymap though - yd or yc is the same number of keystrokes as A-d or A-c so if anything it would make sense to remove the A-d and A-c keybinds. Without anything to replace those keybinds I'm not sure it makes much sense to reclaim them. Plus in my experience, if you're running around a code-base selecting lines/blocks/etc and deleting them with d and then placing something new with y, you might be better off using R which doesn't affect the yank register.

On the other hand I agree with your reasoning:

you can yank before d and c easily with y.

@samholmes
Copy link
Author

@the-mikedavis A-d being Alt+d or Option+d on macOS, does not appear to delete without yank.

To the point about R: Yes, R is best for replacing text with the last yanked text. But the point isn't about using d or c to replace text; rather the point is that if you're doing d or c to insert some text, and then later you chose to use R or p to replace/paste what was yanked, then you'd be remise to find what you thought was in the register has been hijacked by your insert operation. If we instead make yank more explicit with y, then you no longer have to feel uneasy about accidentally overwriting your register as you operate on your file. The reason why I think yank should always be explicit, is because registers have no history and are subject volatile. From a UX perspective, we must treat yank with respect, we must make it an explicit action to yank with y.

As for keystroke count: yd is more than d because it does more than d. There is no need for A-d anymore. If one really wished for less keystrokes, then x is suitable for the job, but then we'd need a key for line-selection. By introducing x as a shorter version of yd we open a can of worms because now why not a shorter yc? Maybe it's best to be conservative here and let yd remain yd for the sake of all that is good.

@EpocSquadron
Copy link
Contributor

I for one would actually be in favor of this change. One thing I think helix does well is being discoverable and obvious, and the more I think on things the more I realize that key bindings that do conditional logic or do more than one thing make things a little less obvious and discoverable.

@samholmes
Copy link
Author

I for one would actually be in favor of this change. One thing I think helix does well is being discoverable and obvious, and the more I think on things the more I realize that key bindings that do conditional logic or do more than one thing make things a little less obvious and discoverable.

I couldn't agree more. I think the challenge with modal editing has always been a UX challenge. The primary UX mis-step has not been communicating the mode to the user. The mode that you're in should be obvious and not require any user memory (I shouldn't need to remember that I entered insert mode before leaving my desk to go to the restroom, for example). Furthermore, learning curve should compound over-time. If I learn that y yanks text, and d deletes text, I should be able to use that knowledge to cleverly compose those actions into "cut". I argue that any action that is composable should remain a composition, and the atomic actions (those which cannot be composed) deserve their own single-key binding. This is a loose goal with maybe some exceptions.

@danyspin97
Copy link
Contributor

@the-mikedavis A-d being Alt+d or Option+d on macOS, does not appear to delete without yank.

It works for me. If they don't work for you (via the the keybindings or the command palette) please open a bug. I'd consider them functional to continue the discussion forward.

Why not swapping A-c and A-d with c and d respectively? So users can still have a command that yanks and can use it when they need it. Also it makes sense to have the keybind with less keystrokes to do the most simple action.

@the-mikedavis
Copy link
Member

It seems like that's a macos specific problem you could fix in terminal emulator: #2280

Swapping A-c and A-d could work but then it's the same number of key-presses as yc and yd, so we might as well just remove the current c and d mappings.

I'd like to try this out in my config for a bit but it seems like a reasonable change to me in theory

@samholmes
Copy link
Author

samholmes commented Jul 13, 2022

I'm using Kitty (terminal app) and it doesn't register the Option key as Alt

I set max_os_opt_as_alt yes in my kitty.conf but still no fix.

EDIT: Never mind, it seems to have worked.

@danyspin97
Copy link
Contributor

danyspin97 commented Jul 14, 2022

Swapping A-c and A-d could work but then it's the same number of key-presses as yc and yd, so we might as well just remove the current c and d mappings.

Except that now there is a delay for simple yank (y) and new composable commands unfamiliar to anyone. If they take the same keystrokes, then A-c and A-d seems better to me.

@EpocSquadron
Copy link
Contributor

There would be no delay for yank, it would simply be sequential.

@danyspin97
Copy link
Contributor

There would be no delay for yank, it would simply be sequential.

There would be a small timer after y to let you type the next character of the command (either c or d) and in case you don't, it will assume that it's just yank action. It's a small delay it's not the end of the world, but it's something to consider.

@EpocSquadron
Copy link
Contributor

It wouldn't need to care what comes next, any which way it yanks, what comes after is entirely separate.

@the-mikedavis
Copy link
Member

No the yank and delete/change would be separate commands executed independently but in sequence - there wouldn't be any need to have a delay. So if you would want to delete/change without yank, you would form a selection and then hit d/c. If you wanted to yank first, you would just hit y in between making the selection and deleting/changing which is the current behavior of y

@the-mikedavis the-mikedavis changed the title Gone with the register pollution please Remove yank behavior of c and d Jul 15, 2022
@amfaber
Copy link

amfaber commented Dec 10, 2022

As someone trying to get into an editor like vim or helix, the fact that deleting a section overwrites my buffer was one of the worst design design decisions about vim to me. I am happy that there is an explicit command for not copying in helix and that I can simply swap the keybindings. I fully agree that this should be the default behavior.

Another approach could be to keep the copying behavior of c and d, but to yank into some designated register which isn't the default one?

@lukasjuhrich
Copy link

Why not implement a yank-stack? I see this as the more powerful solution in contrast to the mentioned compromises… unless I am totally blind to some disadvantages.

Basic idea

  • c/d/… don't overwrite anything, but push to a stack (next/…top/next/…)
  • Pasting, as usual, inserts the last yanked word, i.e. the top of the stack (…→blah blah |top| blurb)
  • An additional command (e.g. A p) lets you “cycle” through the stack by replacing the region of the last paste with the next element of the stack (…→blah blah |next| blurb). (note: This leaves the yank-stack unchanged).
  • Executing any other action causes this „replacement“-mode to be left and the currently visible replacement is inserted

Benefits

  • You don't have the cognitive load of choosing a register (even if you can internalize this into your muscle memory, choosing a register like a is still somewhat of an unnecessary choice one is forced to make)
  • Putting deletions onto the stack is now not „polluting“, because earlier ones are cheap to access. This allows to have the default operations push onto the stack, which means that I don't have to remember to „delete with yank“: Indeed, the editor gives me the guarantee to „delete first worry later“, and when I worry later, the yank-stack has my back.

Editing Performance

For the sake of discussion, let A-p be the chosen keybinding for the cycle operation.

  1. Typing something like p A-p A-p … is fairly primitive and after a few times of doing that, does not require any mental effort.
  2. With everything pushed and nothing lost, an implicit advantage is that at no point in editing I have to make a conscious choice of whether to use a yanking or non-yanking delete command; neither do I have to „plan“ a bunch of editing actions ahead with a specific thing I want to paste in mind.

I'm not sure what the best keybinding for the cycling command would be. Perhaps A-p/A-P? Perhaps p/P? This would add context-dependence, but could work, because pasting twice could be done via 2p anyway; however in that context it might be a good idea to let ESC exit the „cycling-mode“.

Learnability

The concept is not trivial, but completely clear once you understood it. So:

  1. Teaching this is just a matter of putting this into the tutorial.
  2. One could think about making this discoverable on one's own by giving the user some sort of hint (say greyed out in the command line) that, directly after pasting, they're in the “past-cyclable mode“ and have the opportunity to paste „earlier“ items from their stack. However, that might get annoying fast since you only need to see this hint once and then never again because you know of the existence of the mechanic.

Implementation complexity

After pasting, helix has to remember the selection and the position in the stack as part of the „cycling state”. This has to be cleaned up after „leaving“ that mode, i.e. doing something other than pasting.

Anecdotal testimony

As someone having used emacs for quite a few years – first vanilla, then with vim keybindings – and various IDEs with vim keybindings, this is the one big feature which for me was painfully missing in vim. Rectifying this in helix could be a great opportunity.

@sadamczyk
Copy link

@lukasjuhrich That might work okay for smaller chunks of code, but if I just cut out a single line of code and afterwards cleaned up (=deleted) a bunch of bigger blocks of code (think 20-100+ lines), I will now have to insert/cycle through these big chunks of code (that I don't actually care about anymore) just to get to the yanked content I actually wanted in the first place.

I think that's going to feel very confusing and disorienting to be honest.

@sadamczyk
Copy link

I'm 100% for removing yank from c and d.

A very common pattern for me is the following:

  • Select some code
  • Cut = yank + delete
  • Cleanup the code surrounding the hole left by the previous cut. For example operators that now aren't needed anymore (&&/||, arithmetic op., concatenation etc.). if-blocks, loops, functions. Cleaning up variables or arguments that aren't needed anymore, formatting etc.etc. A lot of the time there tend to be "loose ends" that need to be dealt with after a cut, where I very specifically don't want to "save" any of the things I am deleting.

In my personal experience pure deletions (= no yank) happen way more frequently as an action than cuts. A lot of the time I'll delete just a few characters here and there. I really don't need to be able to paste that whitespace, or the character x, just because I fixed a typo somewhere. While cutting something is in my experience done much more rarely and deliberately, which is why yd/yc seems fine for this.

That's why just deleting should be the quickest keypress d/c and should either not yank at all or maybe put them in a "less accessible" delete-register as @amfaber suggested. Having to specify a separate register each time for this much more common action, just so I don't clobber my default register with junk, is just backwards IMO.

@casperin
Copy link

casperin commented Jan 2, 2024

Fwiw I took the (on July 7 2022) suggested keybindings and stuck it in my config. Re-found it today (after a year and something) and thought I'd chip in to say that it just feels less surprising. I have one machine that I rarely ssh into where I forgot to add it, and every time I get hit by suddenly having junk in my register. And every time I have a moment of confusion.

I'm a big fan of this editor and I hardly change any default settings. But this change is staying in my config if this change request doesn't make it.

@gyreas
Copy link

gyreas commented Jan 2, 2024

Tldr: 100% in favour.

Well, I just discovered that behaviour even exist, which is fuelled by my recent coding spree. I find yank before change/delete more natural since their function is in their names. Also, as mentioned above, the contents of registers are volatile, making them even more so by yank during change/delete is not user friendly per se.

Alt-d is a very obscure thing, I've probably only ever used it handful of times (or at all) throughout 2023.

@cotneit
Copy link
Contributor

cotneit commented Feb 22, 2024

There's an issue #6900 for emacs kill-ring proposed in #3001 (comment)

I think it would definitely make yanking c and d less frustrating, especially if it's implemented like #6900 (comment) suggests (with search).

I don't have a strong opinion here since I'm still getting used to modal editing, but one thing I miss from VS Code is how easy it is to move lines up and down #2245. Currently xdp is the best alternative to that, removing yank from d would turn it into xydp, which isn't a huge deal but does add up for his particular usecase since it already feels more involved than it needs to be.

@helix-editor helix-editor locked and limited conversation to collaborators Apr 12, 2024
@pascalkuthe pascalkuthe converted this issue into discussion #10361 Apr 12, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
A-keymap Area: Keymap and keybindings C-discussion Category: Discussion or questions that doesn't represent real issues
Projects
None yet
Development

No branches or pull requests

10 participants