10

Is there a way to 'pipe' text from a register to an another register or set of registers? For example, move "q to registers "1 through "5.

I often wish to create slightly different versions of the same macro, so it is useful to be able to copy a 'template' macro to several registers and then modify each of them in place.

To give a practical example, here is the problem that prompted this question for me.

I need to turn the following line from a hardware description language into many repeated blocks,

RAM64(in=in, load=load0, address=address[0..5], out=out1);

to

RAM64(in=in, load=load1, address=address[0..5], out=out2);
RAM64(in=in, load=load2, address=address[0..5], out=out3);
RAM64(in=in, load=load3, address=address[0..5], out=out4);
RAM64(in=in, load=load4, address=address[0..5], out=out5);

I have a macro which performs this, using the increment function, yypW^At)^A which I stored in register "a.

Sometimes, I need the pattern of incrementing to be slightly different, such as

RAM512(in=in, load=load1, address=address[0..8], out=out2);
RAM512(in=in, load=load2, address=address[0..8], out=out4);
RAM512(in=in, load=load3, address=address[0..8], out=out6);
RAM512(in=in, load=load4, address=address[0..8], out=out8);

where the macro in register "b would be yypW^At)^A^A.

I want a register to do this, but for each increment from 1-5. The register "a could (somehow) be copied to registers b through e. Then I would paste each register into the buffer, make the required modification (add more terms, change the character that follows the t motion etc) and yank the modified expression back into the register. Ideally this last step could even be included in the command(s) to copy the registers

This saves me from repeating all of the characters in the macro that do NOT require changing. For my example it may be trivial, but I can foresee times when it might be very helpful to do what I am asking.

  • 5
    As an aside, I wouldn't recommend using the numbered registers. The only "safe" registers are the alphabetic registers. All other registers are automatically set by Vim. – jamessan Feb 3 '15 at 21:23
7

Macros are just text.

Open a new empty buffer and put your macro there. You can duplicate the lines, change one thing here and something else elsewhere then yank a line and use it right away with @".

No need to pollute your registers, especially the number registers which serve an entirely different purpose.

-- edit --

Your question is easier to understand now that you added some explanation.

As it turns out, you only need to change your initial recording to achieve your goal, without playing with registers as if they were variables:

:let i = 1                     " define variable i
qa                             " start recording in register a
yy                             " yank the line
p                              " paste it
W                              " move to next WORD
<C-v><C-a>                     " increment number
t)                             " jump to the other number to increment
:norm <C-r>=i<CR><C-v><C-a>    " increment the number by i
q                              " stop recording

To create 5 copies of the current line with the last number incremented by 2:

:let i = 2|norm 5@a

or 12 copies, with the last number incremented by 23:

:let i = 23|norm 12@a
  • Agreed about the numeric registers—but what if you want to use this in a command, and you need registers that start the same but become different? – wchargin Feb 3 '15 at 21:30
  • @WChargin, please explain. – romainl Feb 3 '15 at 21:31
  • As in, perhaps I want to do something with rotated copies of a string, so if abcde is in @q, then I want @x="bcdea", @y="abcde", and @z="eabcd". I might start by letting @x, @y, and @z all equal to @q and then modifying them as needed. Obviously, I just made this up, but it seems like there might be some cases where something similar might be useful. – wchargin Feb 3 '15 at 21:34
  • 2
    @Kit, I'm a bit concerned by the lack of practical example in your question which immediately makes it smell like XY. I'm almost certain you are misusing registers so I'd love to read an explanation of what you are trying to do. – romainl Feb 3 '15 at 21:42
  • 1
    @Kit, that's one of the many problems with XY problem qustions. The most upvoted answer is a high-quality direct answer to your question but ultimately useless in the context of your real problem while my less upvoted answer is an actual solution to your underlying problem. Both answers are correct but they answer different questions which makes it hard for you to decide. If it was me, I would accept the answer that addresses my core issue… but that's just me. – romainl Feb 5 '15 at 7:38
6

Using getreg and setreg

To copy from q to registers 15:

let src=getreg('q', 1)
for i in range(1, 5)
    call setreg(i, src)
endfor

To copy to a more general list:

let src=getreg('q', 1)
for i in ['a', 'c', 'e']
    call setreg(i, src)
endfor

Using execute

To copy from q to registers 15:

for i in range(1, 5)
   execute 'let @' . i . '=@a'
endfor

To copy to a more general list:

for i in ['a', 'c', 'e']
    execute 'let @' . i . '=@a'
endfor

Explanation. The command let can be used as let @x=@y, which copies register y to register x. Essentially, we're just constructing these commands in a loop (changing the value of x in the above form) and executeing them.

  • 1
    There's no need to use :exe here. The getreg() and setreg() functions would be cleaner. – jamessan Feb 3 '15 at 21:38
  • @jamessan Nice suggestion, thanks—am I using these correctly? – wchargin Feb 3 '15 at 21:48
  • I've edited it to add the optional second argument to getreg() since that returns the contents of the register rather than a possible evaluation of it. – jamessan Feb 3 '15 at 21:53
1

To directly answer the question, if you want to quickly and easily copy the contents of one register to another, you can put the following in your .vimrc. You can then execute <leader>rcab to copy the contents of register a to register b. As an example I chose <leader>rc to stand for 'register copy'

function! s:CopyRegister()
    let sourceReg = nr2char(getchar())

    if sourceReg !~# '\v^[a-z0-9]'
        echo "Invalid register given: " . sourceReg
        return
    endif

    let destinationReg = nr2char(getchar())

    if destinationReg !~# '\v^[a-z0-9]'
        echo "Invalid register given: " . destinationReg
        return
    endif

    call setreg(destinationReg, getreg(sourceReg, 1))
    echo "Replaced register '". destinationReg ."' with contents of register '". sourceReg ."'"
endfunction

" rc = register copy
nnoremap <leader>rc :call <sid>CopyRegister()<cr>
  • 1
    I'd recommend getreg(sourceReg, 1). – jamessan Feb 3 '15 at 21:45
  • Ah yeah, true. Fixed. – Steve Vermeulen Feb 3 '15 at 21:48

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.