2

I want to create a function like this:

function Foo()
    copy something from buffer into a register
    do something
    restore register
endfunction

Foo must have no side effect, every register should remain the same after you call it, how should i do it?

Attempt

unnamed register

function Foo()
    let [regText, regType] = [getreg('"'), getregtype('"')]
    norm! y{motion}
    do something
    call setreg('"', regText, regType)
endfunction

side effect:

  • register 0 was changed
  • if 'clipboard' includes unnamed or unnamedplus, regster * or + was also changed.
  • if " point to other register before calling Foo, it stopped pointing to it after the calling.

named register

function Foo()
    let [regText, regType] = [getreg('a'), getregtype('a')]
    norm! "ay{motion}
    do something
    call setreg('a', regText, regType)
endfunction

side effect:

  • " now point to a.

explicit unnamed register

function Foo()
    let [regText, regType] = [getreg('"'), getregtype('"')]
    norm! ""y{motion}
    do something
    call setreg('"', regText, regType)
endfunction

side effect:

  • if " point to other register before calling Foo, it stopped pointing to it after the calling.
  • update register 0 was changed.
  • Why do you want to both copy a value in a register and restore the register to the original value in the same function? Would copying the in a variable work instead? – padawin May 17 at 14:29
  • It's convenient to copy something from buffer into a register first. – dedowsdi May 17 at 14:36
  • ok, and the issue here is that "ay{motion} sets in the " (unnamed register) as well as a? – padawin May 17 at 14:38
  • No, it set " point to a, check :h quotequote. – dedowsdi May 17 at 23:19
1

You've identified most of the issues - I think the best one can do is using the unnamed register, saving its contents and type, and temporarily resetting 'clipboard' and :help cpo-y for yanks. I don't think it's possible to avoid the aliasing of register 0, but as these numbered registers are ephemeral and therefore rarely used, it's not so bad.

Here's the implementation of ingo#register#KeepRegisterExecuteOrFunc() from my ingo-library plugin.

function! ingo#register#KeepRegisterExecuteOrFunc( Action, ... )
"******************************************************************************
"* PURPOSE:
"   Commands in the executed a:Action do not modify the default register.
"* ASSUMPTIONS / PRECONDITIONS:
"   None.
"* EFFECTS / POSTCONDITIONS:
"   None.
"* INPUTS:
"   a:Action    Either a Funcref or Ex commands to be :executed.
"   a:arguments Value(s) to be passed to the a:Action Funcref (but not the
"       Ex commands).
"* RETURN VALUES:
"   Result of evaluating a:Action, for Ex commands you need to use :return.
"******************************************************************************
    let l:save_clipboard = &clipboard
    set clipboard= " Avoid clobbering the selection and clipboard registers.
    if stridx(&cpoptions, 'y') != -1
        let l:save_cpoptions = &cpoptions
        set cpoptions-=y
    endif
    let l:save_reg = getreg('"')
    let l:save_regmode = getregtype('"')
    try
        return call('ingo#actions#ExecuteOrFunc', [a:Action] + a:000)
    finally
        call setreg('"', l:save_reg, l:save_regmode)
        if exists('l:save_cpoptions')
            let &cpoptions = l:save_cpoptions
        endif
        let &clipboard = l:save_clipboard
    endtry
endfunction

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.