I'm using vim and I'd like to copy the first word for a range of consecutive lines. The only thing that I could think of is :4,32yw (for lines 4-32), but it didn't work. Any help is appreciated in advance, thanks!

2 Answers

1
Community On

You can do it, but it might be a little bit more complicated than using a simple command as you did.

What you tried to run, is normal mode commands as execute commands. That won't work as you did it. Commands in the normal mode (like pressing yw) won't work es ex-commands.


To run the normal mode commands in the ex-command mode, you should use the normal command (for more information, you can see :help normal). However, even if you would change you command to use the normal mode command (something like :4,32 normal yw) it would still not work, since this would run for every line, each time running over the previous yanked value.

You can do the desired action, using a vim register that would append the word in each loop (for more info about registers you can read :help registers).


To do it, you should change the command to be something like :3,32 normal ^"Ayw.

To break down this command:

  • : - enter ex-command mode.
  • 3,32 - The range to run the command over.
  • normal - The actual command to run.
  • ^ - Go to the start of the line.
  • "A - Run the yank into the a register, appending the data to the previously saved data in it.
  • yw - Yank the current word.

Later, to print the copied values, you should use "ap (in the normal mode) at the desired location.

Drawbacks

Note that the command inserts the new word into the registers, ignoring the first value of the register. It means that if the register wasn't empty once you run this command, all the words would be appended to the current value of the register.

To clear the previous value of the register, you can run the command:

:let @a=''

before running you yank command.

Automation

In case you want to do it many times, you might want to use a simple function that would do it all for you, instead make you run both commands every time.


A simple function that would do this:

function! CopyFirst(first_line, second_line, register)
    execute "let @" . a:register. "=''"
    execute a:first_line . "," . a:second_line . "normal ^\"" . toupper(a:register) . "yw"
endfunction

Usage:

:call Copyfirst(3, 32, 'a')
"ap
0
Sergio On

This function uses a function range (more info of this feature in :help func-range):

" Get the first word of the line for a given range of lines
function! GetFirstWord() range
    let @a=""
    execute a:firstline.",".a:lastline."g/.*/y A"
    echo split(substitute(@a," *\\(\\w\\+\\).\\{-}\\n","\\1 ","g"))
endfunction

The first line cleans register a. Second line yanks the lines inside the range into register a. The last line prints a List with the first words of each line. Sample input file:

some sample
   text abc
   123 456
function
yy xx

Sample calling and output:

:2,4call GetFirstWord()
['text', '123', 'function']