"_dd doesn't reset v:register

150 views
Skip to first unread message

Andrew

unread,
Apr 19, 2014, 9:47:14 AM4/19/14
to vim...@googlegroups.com
Given a text file with the following two lines:

first line
second line

If you now go to the second line and yank it, then go to the first line and type in

"_ddp

What I'd expect to happen is:

second line
second line

What actually happens is:

second line

The `p` doesn't do anything at all, unless you press it a second time.

After some experimentation, I figured out that the `v:register` variable is not reset after the `"_dd` operation. As a result, the following `p` uses the `_` register. This is reproducible with other registers as well. If you do anything after the `"_dd` (like move down one line with `j`), the register is reset just fine and `p` uses the default one.

The original issue that brought this to my attention is here if you'd like more context: https://github.com/AndrewRadev/whitespaste.vim/issues/2

Manuel Ortega

unread,
Apr 19, 2014, 11:06:05 AM4/19/14
to vim...@googlegroups.com
On Sat, Apr 19, 2014 at 9:47 AM, Andrew <andrey...@gmail.com> wrote:
Given a text file with the following two lines:

    first line
    second line

If you now go to the second line and yank it, then go to the first line and type in

    "_ddp

What I'd expect to happen is:

    second line
    second line

What actually happens is:

    second line

The `p` doesn't do anything at all, unless you press it a second time.


I suspect something about your setup is doing this.  When I follow your instructions, I get precisely the "expected" behavior.

-Manny 

Andrew

unread,
Apr 19, 2014, 11:41:30 AM4/19/14
to vim...@googlegroups.com
> I suspect something about your setup is doing this.  When I follow your instructions, I get precisely the "expected" behavior.

Ah, actually, that was silly of me. You wouldn't be able to reproduce it like this, since the normal `p` works just fine :/.

Instead, try:

"_dd:echo v:register<cr>

As in, just take a look at the value of `v:register` after the `"_dd` operation. For me, it's `_`, but after the operation is done, I would expect it to change to the default, usually `"`.

Also, I realize I forgot to link to my `vim --version` output: https://gist.github.com/AndrewRadev/11087768

Ingo Karkat

unread,
Apr 19, 2014, 3:08:00 PM4/19/14
to vim...@googlegroups.com
The same applies to yank commands, too. This matters for mappings and
plugins that evaluate v:register. After a command such as "_dd, the
register used by the mapping / plugin is wrong. One first has to do
another command (e.g. "hl": back-and-forth motions) to reset v:register
to the correct default.

-- regards, ingo

Christian Brabandt

unread,
Apr 28, 2014, 5:15:11 PM4/28/14
to vim...@googlegroups.com
Hi Andrew!
Can you please come up with a mapping that shows the wrong behaviour? I
might have fix, but am not sure, after applying it, mappings using
v:register still work correctly.

Best,
Christian
--
Banken sind gefährlicher als stehende Armeen
-- Thomas Jefferson

Andrew

unread,
Apr 29, 2014, 2:44:50 PM4/29/14
to vim...@googlegroups.com
Hi, Christian,

> Can you please come up with a mapping that shows the wrong behaviour?

I made this example: https://gist.github.com/AndrewRadev/11408444

It's supposed to paste some text and comment it in the process. It's kind of silly, but a realistic enough example. If you `"_dd` anything and then immediately perform a `gp`, nothing happens, since the `v:register` variable is set to `_`. If you've managed ot fix the issue, it should paste normally, from the default register.

Best Regards,
Andrew.

Christian Brabandt

unread,
Apr 29, 2014, 3:11:04 PM4/29/14
to vim...@googlegroups.com
Hi Andrew!
Thanks. I think this one fixes it:

diff --git a/src/normal.c b/src/normal.c
--- a/src/normal.c
+++ b/src/normal.c
@@ -1263,6 +1263,10 @@ getcount:
normal_end:

msg_nowait = FALSE;
+#ifdef FEAT_EVAL
+ /* reset v:register */
+ set_reg_var(0);
+#endif

/* Reset finish_op, in case it was set */
#ifdef CURSOR_SHAPE

(I hope, it doesn't have any side effect).

Best,
Christian

Andrew

unread,
Apr 29, 2014, 3:33:40 PM4/29/14
to vim...@googlegroups.com
Hi, Christian,

> Thanks. I think this one fixes it.

Yes, it seems like it does. I just applied it to my local vim and everything seems to work fine.

> (I hope, it doesn't have any side effect).

So do I :).

Thanks for the fix! I guess all that's left is to wait until it's merged.

Best Regards,
Andrew.

Bram Moolenaar

unread,
Apr 29, 2014, 5:03:41 PM4/29/14
to Christian Brabandt, vim...@googlegroups.com
Well, if one first does "add and then "_dd, it's a bit unexpected that
v:register is then '"' and not '_' or 'a'.
It's more complicated to remember the previous value, then set
v:register to '_' while the operation is being executed, then restore
the previous value.

An alternative would be to have another variable that holds the last
register that isn't the black hole register. Not sure how useful that
would be.

--
From "know your smileys":
:-* A big kiss!

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Christian Brabandt

unread,
Apr 30, 2014, 3:41:09 AM4/30/14
to vim...@googlegroups.com
Am 2014-04-29 23:03, schrieb Bram Moolenaar:
> Christian Brabandt wrote:
>
>> Hi Andrew!
>>
>> On Di, 29 Apr 2014, Andrew wrote:
>>
>> > Hi, Christian,
>> >
>> > > Can you please come up with a mapping that shows the wrong behaviour?
>> >
>> > I made this example: https://gist.github.com/AndrewRadev/11408444
>> >
>> > It's supposed to paste some text and comment it in the process. It's kind of silly, but a realistic enough example. If you `"_dd` anything and then immediately perform a `gp`, nothing happens, since the `v:register` variable is set to `_`. If you've managed ot fix the issue, it should paste normally, from the default register.
>>
>> Thanks. I think this one fixes it:
>>
>> diff --git a/src/normal.c b/src/normal.c
>> --- a/src/normal.c
>> +++ b/src/normal.c
>> @@ -1263,6 +1263,10 @@ getcount:
>> normal_end:
>>
>> msg_nowait = FALSE;
>> +#ifdef FEAT_EVAL
>> + /* reset v:register */
>> + set_reg_var(0);
>> +#endif
>>
>> /* Reset finish_op, in case it was set */
>> #ifdef CURSOR_SHAPE
>>
>> (I hope, it doesn't have any side effect).
>
> Well, if one first does "add and then "_dd, it's a bit unexpected that
> v:register is then '"' and not '_' or 'a'.

I am not sure I follow. Why would one expect v:register to hold the
register name from the previous
normal mode command?

Best,
Christian

Bram Moolenaar

unread,
Apr 30, 2014, 7:14:30 AM4/30/14
to Christian Brabandt, vim...@googlegroups.com
Because that's where the deleted text is. I know that the docs say that
the v:register variable holds the register name for the *current* normal
mode command, but it appears users writing a mapping also use it after
the normal mode command is done, to find the text that was yanked or
deleted. It would then be logical to use the black hole register if any
other delete must happen, without messing with registers. But then
v:register must also not be changed by the operation that uses the black
hole register.

I don't have a good example of where this is needed though. And perhaps
it's not too difficult to get the value of v:register before using the
black hole register, in which case the change to v:register is irrelevant.

--
hundred-and-one symptoms of being an internet addict:
92. It takes you two hours to check all 14 of your mailboxes.

Ingo Karkat

unread,
Apr 30, 2014, 8:31:26 AM4/30/14
to vim...@googlegroups.com
I find this undocumented behavior quirky and unexpected. If I do "xyy,
then :echo v:register should return ", not x. Isn't : a normal-mode
command that enters command-line mode? Also, after "x:echo v:register, I
get x, but then the next :echo v:register gives ", not x as in the yank
example.

> I don't have a good example of where this is needed though. And perhaps
> it's not too difficult to get the value of v:register before using the
> black hole register, in which case the change to v:register is irrelevant.

I haven't seen this in use, neither. A mapping should go to command-line
mode as soon as possible, and there save / use the v:register value. If
someone really needs this, a v:prevregister could still be contemplated.

Christian, thanks for the patch!

-- regards, ingo

Christian Brabandt

unread,
Apr 30, 2014, 3:00:24 PM4/30/14
to vim...@googlegroups.com
But then, v:register shouldn't be cleared after e.g. cursor movement.
Current behaviour is unreliably therefore.

> I don't have a good example of where this is needed though. And perhaps
> it's not too difficult to get the value of v:register before using the
> black hole register, in which case the change to v:register is irrelevant.

I don't know, if this would be useful.

Best,
Christian

Andrew

unread,
May 13, 2014, 1:54:02 PM5/13/14
to vim...@googlegroups.com
I think I understand the problem, or at least one problem. To give an example, vim-pasta does something like this:

exe "nmap <buffer> " . g:pasta_paste_before_mapping . " <Plug>BeforePasta"

nnoremap <silent> <Plug>BeforePasta :<C-U>call <SID>NormalPasta('P', 'O')<CR>

function! s:NormalPasta(p, o)
" ...
exe "normal! " . a:o . "\<space>\<bs>\<esc>" . v:count1 . '"' . v:register . ']p'
" ...
endfunction

With Christian's patch, it seems like this doesn't work. The plugin uses the default register regardless of how I invoke the paste mapping. If I understand what Ingo's saying, any normal-mode command, including :, should clear v:register. If this is what Christian's patch is doing, it would explain why v:register is lost in the above case. And I think it's a pretty common use case to build up a <Plug> mapping by calling a command or function. In fact, if : resets v:register, I'm not sure how it would even be possible to access that variable in order to save it.

The way I *think* it should work is: Particular operators like d, y, p "consume" a register. Once they're done, the v:register can safely be reset to the default. As Ingo says, typing "xyy should reset v:register, but typing "x: should not, since the register was just left hanging for the next operations.

At least that's how I see the "correct" functionality, but I'm starting to feel pretty confused about edge cases. Can anybody say whether my line of thinking is in the right direction?

Christian Brabandt

unread,
May 14, 2014, 3:17:15 AM5/14/14
to vim...@googlegroups.com
Hi Andrew!

On Di, 13 Mai 2014, Andrew wrote:

> With Christian's patch, it seems like this doesn't work. The plugin
> uses the default register regardless of how I invoke the paste
> mapping. If I understand what Ingo's saying, any normal-mode command,
> including :, should clear v:register. If this is what Christian's
> patch is doing, it would explain why v:register is lost in the above
> case.

Yes, that is basically what my patch does. It resets v:register when
finishing up a normal mode command. That was why I originally asked for
a reproducible example, because I feared, something like this would
happen (v:register not visible anymore in ex commands).

> And I think it's a pretty common use case to build up a <Plug> mapping
>by calling a command or function. In fact, if : resets v:register, I'm
>not sure how it would even be possible to access that variable in order
>to save it.
>
> The way I *think* it should work is: Particular operators like d, y, p "consume" a register. Once they're done, the v:register can safely be reset to the default. As Ingo says, typing "xyy should reset v:register, but typing "x: should not, since the register was just left hanging for the next operations.
>
> At least that's how I see the "correct" functionality, but I'm starting to feel pretty confused about edge cases. Can anybody say whether my line of thinking is in the right direction?

No opinion on that. If we reach some agreement on how to make it work, I
might propose another patch then.

Mit freundlichen Grüßen
Christian
--
Die Weiber ändern ihre Meinungen schwerer als die Männer, weil sie
mehr Gefühle als Schlüsse sind.
-- Jean Paul
Reply all
Reply to author
Forward
0 new messages