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

text-objects do not preserve v:register for custom operators #253

Open
lacygoill opened this issue Aug 1, 2020 · 3 comments
Open

text-objects do not preserve v:register for custom operators #253

lacygoill opened this issue Aug 1, 2020 · 3 comments

Comments

@lacygoill
Copy link

lacygoill commented Aug 1, 2020

Describe the bug

A custom text-object provided by targets.vim does not preserve v:register for custom operators.

To Reproduce

Run this shell command:

vim -i NONE -Nu <(cat <<'EOF'
    set rtp-=~/.vim
    set rtp-=~/.vim/after
    set rtp^=/path/to/targets.vim
    nno <expr> <c-b> Op()
    fu Op(...)
        if !a:0
            let &opfunc = 'Op'
            return 'g@'
        endif
        echom v:register
    endfu
    call setline(1, "'inside quotes'")
    au VimEnter * call feedkeys('"a' .. "\<c-b>i'", 'xt')
EOF
)

You'll need to replace /path/to/targets.vim with the path to your plugin's local installation.

" is echo'ed (run :mess if you missed it).

Expected behavior

a is echo'ed, because the custom operator mapped to <C-b> was prefixed by "a.

Environment

  • targets.vim version: 8d6ff29
  • Vim version: 8.2 Included patches: 1-1333
  • OS: Ubuntu 16.04.6 LTS
  • Terminal: XTerm(358)

Additional context

This breaks a custom operator which needs to read or write into v:register, when the latter is different than ".


I don't know how targets.vim implements its text-objects including i', but for the current issue, let's assume that it could be grossly simplified like this:

xno i' :<c-u>norm! T'vt'<cr>
ono i' :norm vi'<cr>

If this assumption is correct, you can reproduce the issue with this other minimal example, which doesn't require targets.vim:

xno i' :<c-u>norm! T'vt'<cr>
ono i' :norm vi'<cr>
nno <expr> <c-b> Op()
fu Op(...)
    if !a:0
        let &opfunc = 'Op'
        return 'g@'
    endif
    echom v:register
endfu
call setline(1, "'inside quotes'")
au VimEnter * call feedkeys('"a' .. "\<c-b>i'", 'xt')

Notice how – again – Vim echo'es " instead of a. That's because when the :ono mapping is expanded, :norm is executed, and the latter resets v:register to ".


One solution is to make the text-object pass v:register to the opfunc manually:

xno i' :<c-u>norm! T'vt'<cr>
ono i' :norm vi'"<c-r>=v:register<cr><cr>
                ^-------------------^

Example:

xno i' :<c-u>norm! T'vt'<cr>
ono i' :norm vi'"<c-r>=v:register<cr><cr>
nno <expr> <c-b> Op()
fu Op(...)
    if !a:0
        let &opfunc = 'Op'
        return 'g@'
    endif
    echom v:register
endfu
call setline(1, "'inside quotes'")
au VimEnter * call feedkeys('"a' .. "\<c-b>i'", 'xt')

For more info, see this question on vi.stackexchange.com, and this Vim issue.

Btw, if you agree with this analysis, I think it would help if you could leave a comment on the aforementioned issue report, explaining that you currently need to find work arounds; whereas if it was fixed directly in Vim, it would automatically fix your plugin and probably many others. Right now, the issue didn't get much traction; it has not even been mentioned in Vim's todo list.

@lacygoill lacygoill changed the title text-objects reset v:register to " text-objects do not preserve v:register for custom operators Aug 1, 2020
@wellle
Copy link
Owner

wellle commented Aug 11, 2020

@lacygoill: Thank you for your thorough analysis! I'm happy to see that you're trying to implement a custom text object with targets.vim. Would you mind sharing what you are planning to add? I'm just curious.

I'm currently finishing up work for wellle/context.vim#40 and will try to get back to this issue afterwards.

@lacygoill
Copy link
Author

For now, I'm not trying to implement any custom text-object. I'm just using the default text-objects provided by targets.vim. They work fine with builtin operators (like c, d, y, ...). They also work fine with custom operators which don't care about v:register. The issue is with custom operators which do care about it.

I found this issue while I was using a custom dr operator (implemented here), which deletes a text-object and replaces it with the contents of the unnamed register, or with the contents of an arbitrary register, without altering the yank register "0. I had some text in the "a register, and wanted to replace the text inside quotes with the latter; so, I pressed "adri'. The result was unexpected; instead of replacing the text inside quotes with the contents of "a, Vim replaced it with "".

I fixed the issue by saving v:register in a global variable, before invoking the opfunc, so that the latter can inspect it, and reliably determine which register was used before targets.vim reset it to "". But it's a hack that theoretically must be replicated for each custom operator which cares about v:register . It would be better if it was fixed in targets.vim. And it would be even better, if it was fixed in Vim. I've already reported the issue on Vim's bug tracker, but it hasn't been fixed yet, and I doubt it will be anytime soon. So, the next best place to report the issue is here.

@wellle
Copy link
Owner

wellle commented Aug 11, 2020

Thanks, understood 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants