Restoring a register after a <C-r> function call

141 Views Asked by At

I am currently writing a plugin for Vim and I would like that it restores the default register after I execute it. However, the function in question is called via a <C-r>=Myfunction()<CR> construct, which means that I need to restore it after the function return. I've tried to do this like so:

inoremap <silent> <Space> <C-r>=Myfunction()<CR>
function! Myfunction()
    let oldreg      = getreg('"')
    let oldregtype  = getregtype('"')
    let restore     = "\<ESC>:call setreg('\"','".oldreg."','".oldregtype."')\<CR>a"

    let @" = "whatever"

    return "\<ESC>yya ".restore
endfunction

As you can see, the " register is affected by the return string, so I cannot call setreg directly. Obviously this function doesn't really do anything, but the actual function I'm using is quite long. Also, I apologize if that string is a little hard to read, but I'm not really sure of any other way of accomplishing this. All in all, the function seems to work when the register contains a word, but fails whenever something with a newline is in the register. (The specific error is E115: Missing quote with respect to the oldreg argument.) I've tried to remedy this by shellescaping oldreg first; however, this results in the error E121: Undefined Variable, where the undefined variable is what was in my register. Any thoughts on what might be going wrong here?

EDIT: I found a solution. It's quite hairy, but it works perfectly so far. Here's how to apply to solution to my example code, just in case it helps anyone out there.

inoremap <silent> <Space> <C-r>=Myfunction()<CR>
function! Myfunction()
    let oldreg      = substitute(escape(getreg('"'), '\\'), '\n', '\\n', 'g')
    let oldregtype  = getregtype('"')
    let restore     = "\<ESC>:call setreg('\"',\"".oldreg."\",'".oldregtype."')\<CR>a"

    let @" = "whatever"

    return "\<ESC>yya ".restore
endfunction
2

There are 2 best solutions below

1
Luc Hermitte On BEST ANSWER

Here is a way to proceed: Vim: how to paste over without overwriting register

Since then, we have been gifted with setreg(), and I've also developed a more generic solution simplify restoration of most useful things (lh#on#exit()).

In all cases, a solution would be to return @=FunctionToExecute(), and the restoration would happen in that function.

But as others said, you may need to be more explicit about your needs as there may exist more specific solutions to address them. For instance, instead of yanking with yy or with :yank, you could simply use getline() function that would let all registers unmodified. For changing a line, there is setline(), but this would break redo and other things.

0
sidyll On

Instead of going to normal mode after you return your function, I think you should go inside it. This way, you can call setreg() normally in it. For example:

function! Myfunction()
    let oldreg      = getreg('"')
    let oldregtype  = getregtype('"')

    let @" = "whatever"

    normal! yya 

    setreg('"', oldreg, oldregtype)
endfunction