maxbrunsfeld / vim-yankstack

A lightweight implementation of emacs's kill-ring for vim
437 stars 29 forks source link

Option to preserve default/native Vim paste over behavior #11

Open jeetsukumaran opened 12 years ago

jeetsukumaran commented 12 years ago

With native Vim, pasting on a visual selection/word/etc., then the entity being pasted over gets placed in the default register.

Thus, for example, given:

apple grape cucumber

by default, yanking "apple", then selecting "grape" and pasting will result in "grape" being placed in the default register; the next paste operation will put "grape".

Is there a way to preserve this with YankStack? Right now, with the above example, "apple" remains in the default register, and subsequent pastes put "apple". I would like for "grape" to be put by default (pushing "apple" one step down in the stack).

maxbrunsfeld commented 12 years ago

Yeah, we can definitely add an option for this; yankstack actually used to behave this way. Let me explain what my problem was with it, and maybe you can help me decide what the behavior should be.

Suppose, in your example, I yanked 'apple', then yanked 'grape', then highlighted 'cucumber' and pasted. The text now reads:

apple grape grape

With yankstack's current behavior, the contents of the stack are:

'cucumber' is on the bottom of the stack. Because the yankstack wraps around, I can cycle back to 'cucumber' by pressing alt-shift-p (substitute_newer_paste). Or if I want an older yank, I can cycle to 'apple' by pressing alt-p (`substitute_older_paste).

With your proposed option turned on, how would the stack look? Maybe like this:

This has the advantage of keeping vim's default behavior when overwriting text in visual mode. But now, if I press either alt-p or alt-shift-p to cycle the yanks, the behavior is less intuitive. If I now substitute_older_paste, 'grape' moves to the top of the stack, and is pasted. But 'grape' was already the thing that was pasted! Also, if I substitute_newer_paste, then one of the older yanks moves to the top of the stack, not 'cucumber'.

Let me know if this explanation makes sense, and what your thoughts are.

maxbrunsfeld commented 12 years ago

Perhaps I should emphasize that currently, the top of the yankstack is synonymous with the default register. This is so that when you paste, you are always pasting the top item in the yankstack.

jeetsukumaran commented 12 years ago

Hi,

I think that your suggested idea for how the stack should look with the Vim-style yank/paste makes sense, i.e.

This still agrees with the idea that the top of the yankstack is synonymous with the default register: pasting by default results in "cucumber" in either case.

For the substitute_older_paste behavior you describe: it actually is intuitive to me in "native Vim-style paste mode". The older paste was "grape", and that would be what I expect to see come out when I want to hop back to the previous entry in the stack. Perhaps in my mind, I read substitute_older_paste as cycle_stack_up, or something like that, which would be neutral with regards to yankstack paste mode: it moves each of the stack items up by one, and puts the top item at the bottom of the stack. Would this view of the command apply well in both yankstack modes (i.e. Vim-style pasting and non-Vim style pasting)?

Same goes for substitute_newer_paste: this would be like cycle_stack_down, where each item moves down the stack by one, and the bottom item moves to the top of the stack. Thus I would then expect "coconut" to move to the top of the stack. "cucumber" would be the second item in the stack, then "grape", etc.. The last item on the stack would be "papaya". Again, would this behavior and view be consistent across both types of paste modes?

maxbrunsfeld commented 12 years ago

Yes, your interpretation of the command is right, no matter which mode we're talking about: substitute_older_paste is like cycling the stack up, and substitute_newer_paste is like cycling the stack down.

I just want to make sure you see the weirdness that I'm referring to though:

Again, suppose you just selected 'cucumber' and pasted, replacing it with 'grape', and the stack looks like what you have above. Now, when you press alt-p to "cycle the stack up", nothing happens to the buffer! It still says 'grape', because 'grape' was the second item in the stack, so it moved up to the top of the stack and got pasted again.

Cycling the stack downward is slightly weird too: the first time you do it, you get 'coconut'. Then if you cycle back upward, you get 'cucumber'. But before you cycled at all, you had grape! So cycling the stack up and then down again puts you in a different state then when you first pasted.

In summary, if we preserve vim's default pasting behavior in visual mode, we temporarily lose the correspondence between the top of the yankstack and the item being pasted. I still like the idea of adding the option. I just wanted to make sure to communicate the drawbacks that I'm seeing.

jeetsukumaran commented 12 years ago

Ok, I see what you mean. I guess it can be a little confusing if you are not familiar with the mechanics of what is going on. I think most users will just hit alt-p/alt-shift-p to cycle till they get the register they want. And perhaps if you add a short paragraph in the docs under the 'vim-paste-mode' section (maybe even just extracting your explanation from this thread), it will reduce any confusion.

Alternatively, the only way I can think of out of this would be if the replaced text does not get added to the stack until after the paste is complete. Thus, when selecting cucumber and pasting, the stack remains unchanged. alt-p will cycle the stack up to "apple" and cycling down and back up again will still get "grape". Only when the paste is complete is "cucumber" added to the stack. I'm not sure if the infrastructure allows for this to be done easily.

idbrii commented 11 years ago

Alternatively, the only way I can think of out of this would be if the replaced text does not get added to the stack until after the paste is complete

I think this solution gives the behavior closer to what I expect to happen.

I switched from yankring to yankstack because I wanted something that works exactly like vim except that I had access to recently yanked items. So I would want yankstack to only change what's put when I start cycling with <C-n>. Theoretically, that would ensure that macros, :normal scripts, etc would all work as expected, but while editing I could recall past yanks. (I wouldn't expect yankstack to even work in macros. If I want to save specific text in a repeatable way, I use a named register.)

(Yankstack does this in many ways, so thanks for the awesome plugin!)

maxbrunsfeld commented 11 years ago

@pydave - Do you think that the problem being discussed here is the same as the one you identified in issue #19? Now that multiple people have brought it up, I think it deserves to at least be an option in yankstack. I would definitely merge a pull request that added it, and when I get some time, I may add it myself. Thanks for the feedback.

aleprovencio commented 11 years ago

This is probably another new issue, but just for the record, I've noticed that when clipboard gets unnamedplus included the behavior described changes as well.

maxbrunsfeld commented 11 years ago

@aleprovencio I've opened another issue for that (#20). I hadn't even heard of unnamedplus!

idbrii commented 11 years ago

@maxbrunsfeld no, #19 is an inconsistency between macros and live editing: It happens even if you put from a named register, so the default paste behavior is irrelevant.