Here is one way to achieve what you want to do. I think another solution could be to use a macro but getting back at the right position might not always be trivial.
So once you yanked your column in visual block mode, the first step is to get back a list containing every lines.
To do that you can use :h getreg()
like this:
getreg('"', 1, 1)
The first argument '"'
describes the register you want to get, here we use the unnamed register as this is the one used by default when you yank some text. The second argument only has an effect when the first parameter is the expression register '='
which is not the case here. The third argument is used to get a list instead of a string. This command returns something like this:
['VNN3 ', 'VNN1 ', 'VNN2 ', 'STX7 ', 'CTGF ', 'RPS12 ', 'MOXD1 ', 'SLC18B1']
Now we want to get this list as a string with at least one space separating each item. We can do that with :h join()
:
join(getreg('"', 1, 1), ' ')
Now we have this:
VNN3 VNN1 VNN2 STX7 CTGF RPS12 MOXD1 SLC18B1
Let's then remove the redundant white spaces with :h substitute()
:
substitute(join(getreg('"', 1, 1), ' '), '\s\+', ' ', 'g')
Looks good:
VNN3 VNN1 VNN2 STX7 CTGF RPS12 MOXD1 SLC18B1
Finally we want to add the result of this command in the current buffer. To do so we can use the expression register :h quote=
.
In insert mode you will need to type Ctrl+r to start inserting the content of a register. Then type =
to select the expression register and write the command we used before to insert the text.
All of this is nice but it would be better to have a mapping to do all the typing for us. The following line added to your vimrc should do the trick:
nnoremap <YOUR_KEY> i<C-r>=substitute(join(getreg('"', 1, 1), ' '), '\s\+', ' ', 'g')<CR>
Now all you have to do is yank your column in visual block mode and press <YOUR_KEY>
in normal mode to get the result inserted after your cursor.
EDIT 2 as Ben pointed out in the comments, using map
to trim the strings instead of using a substitution is shorter and more elegant see the relevant doc :h map()
(There might even be a way to improve the lambda used by map
but I don't know how and don't want to spend more time on that :) ):
join(map(getreg('"', 1, 1), {_, v -> trim(v)}), ' ')
EDIT 1 Just because it's fun I tried to do it with a macro. The idea is to create a repeatable sequence of key presses to get your result.
First I did the assumption that your text looks like this:
chr6_66364 1.846 VNN3 chr6 132967948 132968077
chr6_66364 1.846 VNN1 chr6 132967948 132968077
chr6_66364 1.846 VNN2 chr6 132967948 132968077
chr6_66364 1.846 STX7 chr6 132967948 132968077
chr6_66364 1.846 CTGF chr6 132967948 132968077
chr6_66364 1.846 RPS12 chr6 132967948 132968077
chr6_66364 1.846 MOXD1 chr6 132967948 132968077
chr6_66364 1.846 SLC18B1 chr6 132967948 132968077
You should start with your cursor on the 3
of VNN3
.
Start recording a macro with qq
for example. Then press the following keys (Note ^[
is actually the escape key):
m'j02Wyiw``a ^[pm'jdd``
And when you are done press q again to stop recording the macro. Here is what you have done:
m' Create a mark we will use later to go back to the current position
j0 Go down a line and go at the beggining of the line
2W Go the the column you want to merge
yiw Copy the word in the column
`` Go back to the exact position of the mark we created in the first step
a Start insert mode
Add a litteral whitespace
^[ This is actually the Escape character to go back to normal mode
p Paste the word you yanked before
m' Set the new position of the mark.
jdd Go down one line and delete the line
`` Go back to the end of the recently pasted word
Now you can simply press @q to play back the macro and get a new line joined with every execution.
As I said at the beginning of my answer I think this is more obscure and error prone than my first solution.