0

I’m trying to yank a range into a register while ignoring blank lines. My range is from line 10 to the end of the file.

:10,$v/./"*y

Looking at my registers in :reg I see that my text is not in the register I specified or any other register. However vim has highlighted all lines not containing a blank line including the first 9 lines.

What am I missing (besides being two bricks shy of a load?)

5
  • You're on the command line. Yanks look like y[ank] [x] where x is the register (if left out yank goes to default reg). Also, your vglobal command is skipping every line that has at least one character. That doesn't sound like your intention. :help :v, :help :yank
    – B Layer
    Mar 29, 2021 at 18:20
  • 2
    (cont) Also, if you want to use :g or :v to yank into a register you need to append to the register by using the uppercase letter not the lowercase letter. (I don't think this can be done with * register). :{range}v/{pattern}/ y X. If I'm not interpreting your need correctly please update your question with more details.
    – B Layer
    Mar 29, 2021 at 18:27
  • 10,$g/./y * yields the last paragraph into the clipboard and in the "" register. Mar 29, 2021 at 18:34
  • Without the global pattern, {range}y * works. Mar 29, 2021 at 18:36
  • Because that's a single run of yank.
    – B Layer
    Mar 29, 2021 at 18:37

2 Answers 2

2

There are problems with your :vglobal command and problems with your :y[ank].

First, :v runs against lines that aren't matched by your pattern. You are skipping all lines with at least one character.

Second, :g and :v work by running the following command for each line that they match/don't match. That means yank is running multiple times and each time it does it overwrites the register. You need to append to the register. The way you do that is by using the uppercase form of the register name, not the lower case. That also means you can't use non-letter registers like *.

Third, your yank is not correct. You're trying to yank as if you are in Normal mode. But you're on the command line. You need to use the form :y[ank] [x] where x is the name of a register.

So the actual command needs to be something like:

:{range}[gv]/{pattern}/ y [A-Z]

More specifically, based on your use case and assuming register a...

:10,$g/./ y A

Don't forget to clear register a before you run this since you're appending.

Update: Since you really want the yanked text to go into the * register there are two alternatives:

  1. After the :g command runs just do :let @* = @a.
  2. Use this :10,$g/./ yank a | let @* .= @a

The second one runs as a single :g command; each time a matched line is found it is yanked into register a and then that is appended to * using the operator .= which gives us the equivalent to let @* = @* . @a. IOW, we don't need A in this case.

4
  • Thank you!. You said, "That also means you can't use non-letter registers like *." Since my goal is to get my text into the system clipboard, does that mean I'm out of luck? Mar 29, 2021 at 18:59
  • 1
    You're welcome. After the :g command runs you can copy contents of the letter register to * with :let @* = @a, for example.
    – B Layer
    Mar 29, 2021 at 19:01
  • Actually, I think :g/…/yank A | let … updates the register for every line (iow bar is part of global, and you need exec around the global to make it not). I would write two commands if I was worried about performance lag though.
    – D. Ben Knoble
    Mar 29, 2021 at 22:37
  • It works either way but I should have left it as I had it originally: two separate commands.
    – B Layer
    Mar 30, 2021 at 1:53
1

An alternative to using :global which doesn't overwrite a lettered register is to do this with vimscript calls:

:call getline(10, '$')->filter({_, v->strlen(v)})->setreg('*')

You could take this as the basis for abstracting this into a command which copies all non-blank lines from the specified line (or current if not specified) to the end of the file to the clipboard:

function! CpNonblank(...)
    let start = a:0 > 0 ? a:1 : '.'
    call getline(start, '$')->filter({_, v->strlen(v)})->setreg('*')
endfunction
command! -nargs=? CpNonblank call CpNonblank(<args>)

So that :CpNonblank copies from the current line to the end, and :CpNonblank 10 copies from line 10 to the end.

(Meta-fact: I prototyped this in vim and then used the function to copy the file)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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