How to copy all hlsearch text to clipboard in Vim - vim

file.txt
abc123
456efg
hi789j
command
:set hlsearch
/\d\+
I want to copy highlighted text bellow to clipboard (or register):
123
456
789
Just like
egrep -o '[0-9]+' file.txt
Thanks.

One can follow the below procedure.
Empty a register (for instance, "a).
qaq
or
:let #a = ''
Run the command1
:g/\d\+/norm!//e^Mv??^M"Ay
If it is necessary to append a new line character after each of the
matches, run this command instead:2
:g/\d\+/norm!//e^Ma^M^[??^Mv$"Ayu
Type ^M as Ctrl+V then Enter (or
Ctrl+M), type ^[ as
Ctrl+V then Esc (or
Ctrl+[). In order not to retype the pattern
that just have been used in search, one can press
Ctrl+R, / to automatically insert
last search pattern.
Also one can record the command to execute on matched lines (the part
following norm!) as a macro. This allows to see the actions
immediately on a sample line and to make sure they are correct. Then,
the macro can be applied using :global:
:g/\d\+/norm!#z
1 At the top level, the command is a :global executing the Ex
command norm!//e^Mv??^M"Ay on each of the lines that match the pattern
\d\+. The Ex command begins with the norm! command to execute the Normal
mode commands //e^Mv??^M"Ay. These are three commands separated by the
carriage return symbol ^M. The first one, //e, looks for the search
pattern (which is set to the pattern used in the global command) and put the
cursor to the last symbol of the match (because of the flag e, see :help
search-offset). Then v command starts Visual mode. The command ?? looks
for the last search pattern backwards (and put the cursor to the first
character of the match), thus selecting the text that match the last search
pattern. The last command, "Ay, yanks the selected text appending it to the
a register.
2 The second global command resembles the first one in outline.
At each of the matched lines, it moves cursor to the last symbol of the match
and inserts newline after that symbol. Then it puts the cursor to the start
of the match and selects (in Visual mode) everything up to the end of line
(including just inserted newline). Finally, the command appends the selected
text to the register, and undoes newline inserting.
3 One can always see the actions recorded in particular macro by
examining the contents of the corresponding register using :di z or "zp,
for example.

If your text obeys the pattern you posted you can start visual mode blockwise with Ctrl+V and select from 1 in the first line to 9 in the last line. Then you just copy to the + register, which is the system clipboard, by typing "+y.
Edit:
I have tested this new solution for the text:
abc123
456efg
hi789j
Replace all non-digit by nothing with :%s/\D//g and the result will be:
123
456
789
Copy it to the clipboard typing "+y%, then revert the changes with u and you are done.

Use this command to extract all URLs, and append to the end of file:
:let urls = [] | %s/http:[^"]*/\=add(urls, submatch(0))[-1]/g | call setline(line('$')+1, urls)

Related

How to append each line from 11-20 to each line from 1-10 in VIM

I have a file in which first 10 lines are the columns of a table and the rest 10 lines are the values of each column.
How can I use norm in VIM to append the values after each column names like this:
column1
...
column10
value1
...value10
-->
column1: value1
...
column10: value10
It is a little similar with this(Vim - Copy Nth word of each line, from line 10-100, to end of line), but I don't know how to go to line 1:10 and append the copied lines.
Any idea will be appreciated!
Fairly naive and crude way to do this, but:
:1,10norm! 10j0d$10kA: ^[p
Explanation:
1,10norm!: for lines 1 to 10, do the following (the ! means any custom mapping you have will be ignored, thanks to D. Ben Knoble for reminding of this):
10j: move down 10 lines
0d$: delete the whole line (not including newline)
10k: move back up 10 lines
A:: append (at the end of the line) ': ' (note the trailing space)
^[: input escape character, going back to normal mode. This (^[) is a single character and is inputted by typing Ctrl-v then escape, not by typing ^[.
p: paste the line deleted in step 3
Another (copy-pastable) way, (ab)using the substitute command:
:1,10s/\v(.*)\ze(.*\n){10}(.*)/\1: \3/ | 11,20d
which does:
1,10s/: for lines 1 to 10, execute the following substitution:
\v: use very-magic regex mode (see :help \v)
(.*): capture the entire current line (eg column1)
\ze: signal the end of the match. This way everything read (and captured) afterwards will not be affected (but can still be read)
(.*\n){10}: skip 10 (including current) lines, ie skip selector to 10 lines below
(.*): capture the line (eg value1)
/: end the 'select' part of the substitute command
\1: \3: replace with captured groups (eg column1: value1)
|: command separator
11,20d: delete lines 11 to 20
Use blockwise-visual mode to perform the operations.
You can enter visual block mode with Ctrl-V and it allows you to select and operate on columns. It also allows you to perform the same action on a block, which you can use to add the : to the lines with the column names.
I'll use normal Vim syntax for keystrokes in my examples, <C-v> means Ctrl-V.
Start by deleting the values into the default register, using a visual block:
11G<C-v>9j$d
Then Add the : to the column lines, also using a visual block:
1G<C-v>9j$A: <Esc>
Then add some more spaces to the first line, to ensure there's room for all the column names to fit:
A <Esc>
Finally, put the visual block at the end of the first line:
$p
It will actually put it on all lines all the way to the end.
This is slightly different from what you specified, since the values are all aligned on the same column. If you want different spacing, you can perhaps use a :s operation to fix spacing.
10:s/: */: /<cr>
Depending on where you pasted (if some column names had more trailing spaces than the first one), you might have some trailing spaces after the pasted values to fix as well, but that should be easy to do using a similar procedure.
Visual block operations are really powerful, it's a great feature to learn and keep in your "toolbox" in Vim. They're really handy with this kind of problem where thinking in "columns" makes the most sense.

Pasting with overwrite in Vim

I want to be able to paste something from the buffer (probably using p), but instead of inserting it into the text, I want to replace whatever was there before (just like the R command). I've searched Google, vim documentation, and Stack Overflow but could not find anything on the issue. I imagine that it's just a command that I don't know about. Any help would be appreciated.
That's all I need to know, but if you want to know my specific problem:
Essentially I'm just trying to create a short script for documentation headers. At the beginning of every function I put the following:
// FunctionName <><><><><><><><><><><><><><><><><><><><>
However adding all those <> gets annoying. I want to be able to place my cursor on a function name, press the F6 key and it produce the above. The problem, of course, is that function names are not constant sizes and it would make the "chain" look weird. So I just want to paste OVER a bunch of pre-made chain so that the whole thing will always be a constant number of characters. i.e.:
start with
//<><><><><><><><><><><><><><><><><><><><><><><><><><><>
Paste " FunctionName " and end with
// FunctionName <><><><><><><><><><><><><><><><><><><><>
I found a much better solution
R Enter Replace mode: Each character you type replaces an existing character, starting with the character under the cursor.
So R <ctrl-r>" will do what you want. Note there is a space before and after <ctrl-r>".
OLD ANSWER
You can do this with a macro pretty easily
qhmhA <esc>a<><esc>40.80|D`hq
qh start macro
mh set mark
A <esc> insert a space after the existing text
a<><esc> insert '<>'
40. repeat last command 40 times
80| move to column 80
D delete to the end of the line
`h jump back to mark
q end macro
The macro can then be repeated with #h. You probably want to save this to your .vimrc like so
let #h = 'mhA ^[a<>^[40.80|D`h'
Note that the ^[ are supposed to be one character entered by pressing <ctrl-V><esc>
You can use visual selection.
Vp select the whole line and overwrite with buffer
viwp select the word under cursor and overwrite with buffer content.
vi(p overwrite what is in between parenthesis.
I particularly like that it highlights what should be overwritten, which
makes it easier to verify.
You can do it with this:
:exe "normal ".strlen(#p)."x\"pP"
It deletes the right number of chars, and then paste the content of register p.
Short answer
Simply do R and <C-r>0 or the 'register' you are trying to yank. If in doubt, check :reg
Long answer
From :help i_CTRL-R:
Insert the contents of a register. Between typing CTRL-R and
the second character, '"' will be displayed to indicate that
you are expected to enter the name of a register.
The text is inserted as if you typed it, but mappings and
abbreviations are not used. If you have options like
'textwidth', 'formatoptions', or 'autoindent' set, this will
influence what will be inserted. This is different from what
happens with the "p" command and pasting with the mouse.
Special registers:
'"' the unnamed register, containing the text of
the last delete or yank
'%' the current file name
'#' the alternate file name
'*' the clipboard contents (X11: primary selection)
'+' the clipboard contents
'/' the last search pattern
':' the last command-line
'.' the last inserted text
'-' the last small (less than a line) delete
*i_CTRL-R_=*
'=' the expression register: you are prompted to
enter an expression (see |expression|)
Note that 0x80 (128 decimal) is used for
special keys. E.g., you can use this to move
the cursor up:
CTRL-R ="\<Up>"
Use CTRL-R CTRL-R to insert text literally.
When the result is a |List| the items are used
as lines. They can have line breaks inside
too.
When the result is a Float it's automatically
converted to a String.
When append() or setline() is invoked the undo
sequence will be broken.

Allign the words to the specified column in vim using commands

How I can move or shift the words in the entire file to the specified column?
For example like below:
Before :
123 ABC
112 XYZS
15925 asdf
1111 25asd
1 qwer
After :
123 ABC
112 XYZS
15925 asdf
1111 25asd
1 qwer
How it can be done using command mode?
Here the thing is we need to shift the 2nd word to the specified column
Here the specified column is 8
except for vim-plugins mentioned by others, if you were working on a linux box with column command available, you could just :
%!column -t
% could be vim ranges, e.g. visual selections etc..
Approach with built-in commands
First :substitute the whitespace with a Tab character, and then :retab to a tab stop to column 8, expanding to spaces (for your given example):
:.,.+4substitute/\s\+/\t/ | set tabstop=7 expandtab | '[,']retab
(I'm omitting the resetting of the modified options, should that matter to you.)
Approach with plugin
My AlignFromCursor plugin has commands that align text to the right of the cursor to a certain column. Combine that with a :global command that invokes this for all lines in the range, and a W motion to go to the second word in each, and you'll get:
.,.+4global/^/exe 'normal! W' | LeftAlignFromCursor 8
I use the Tabular plugin. After installing it, you run the following command:
:%Tab/\s
where \s means whitespace character
I have made two functions for this problem.
I have posted it here : https://github.com/imbichie/vim-vimrc-/blob/master/MCCB_MCCE.vim
We need to call this function in vim editor and give the Number of Occurrence of the Character or Space that you wants to move and the character inside the '' and the column number.
The number of occurrence can be from the starting of each line (MCCB function) or can be at the end of each line (MCCE function).
for the above example mentioned in the question we can use the MCCB function and the character we can use space, so the usage will be like this in the vim editor.
:1,5call MCCB(1,' ',8)
So this will move the first space (' ') to the 8th column from line number 1 to 5.

Separate lines with blank lines in Vim?

I am dealing with a block of comments like:
//this is comment 1
//this is comment 2
//this is comment 3
//this is comment 4
I would like to make it look like:
//this is comment 1
//this is comment 2
//this is comment 3
//this is comment 4
Is there a Vim shortcut to make this transformation on selected lines while staying in command mode?
You can use the :substitute command. With the cursor anywhere on the
first of the lines:
:,+3s/$/\r
This inserts an additional newline at the end of each line.
You can also use the :global command. With the cursor anywhere on
the first of the lines, run:
:,+3g//norm o
For each of the next four lines, this executes the o Normal-mode
command, adding a new blank line.
In both of the commands, the ,+3 prefix is a range for the
command, see :help range. Briefly, the comma separates the addresses
of the starting and ending lines of the range, where the current line
is used if we omit the former of the two addresses. The +3 address
refers to the line that is three lines below from the current line.
Rather than specifying a range, e.g., ,+3, for either of these
commands, you can use the V Normal-mode command to make a Visual
block across all the lines that you want. Then typing : to begin the
command will auto-fill the range specifying the visual block, and you
can then enter either of the two commands starting with s or g:
:'<,'>s/$/\r
You can use a macro:
qao<esc>jq
then use 3#a to apply the macro 3 times over the last lines.
where:
qa "Start recording a macro named a
o "Insert new line under current line
<esc> "Exit insert mode
j " Move down next line
q " end macro
Select your visual selection with V
Then run a regex replace to replace one line break with two
:s/\n/\r\r/g
One can use the command
:g/^/pu_
on the whole buffer (by default) or on a selected range of lines.
Select the lines you want with V
Then type : and s/\ze/\r

How to insert a block of white spaces starting at the cursor position in vi?

Suppose I have the piece of text below with the cursor staying at the first A currently,
AAAA
BBB
CC
D
How can I add spaces in front of each line to make it like, and it would be great if the number of columns of spaces can be specified on-the-fly, e.g., two here.
AAAA
BBB
CC
D
I would imagine there is a way to do it quickly in visual mode, but any ideas?
Currently I'm copying the first column of text in visual mode twice, and replace the entire two column to spaces, which involves > 5 keystrokes, too cumbersome.
Constraint:
Sorry that I didn't state the question clearly and might create some confusions.
The target is only part of a larger file, so it would be great if the number of rows and columns starting from the first A can be specified.
Edit:
Thank both #DeepYellow and #Johnsyweb, apparently >} and >ap are all great tips that I was not aware of, and they both could be valid answers before I clarified on the specific requirement for the answer to my question, but in any case, #luser droog 's answer stands out as the only viable answer. Thank you everyone!
I'd use :%s/^/ /
You could also specify a range of lines :10,15s/^/ /
Or a relative range :.,+5s/^/ /
Or use regular expressions for the locations :/A/,/D/>.
For copying code to paste on SO, I usually use sed from the terminal sed 's/^/ /' filename
Shortcut
I just learned a new trick for this. You enter visual mode v, select the region (with regular movement commands), then hit : which gives you this:
:'<,'>
ready for you to type just the command part of the above commands, the marks '< and '> being automatically set to the bounds of the visual selection.
To select and indent the current paragraph:
vip>
or
vip:>
followed by enter.
Edit:
As requested in the comments, you can also add spaces to the middle of a line using a regex quantifier \{n} on the any meta-character ..
:%s/^.\{14}/& /
This adds a space 14 chars from the left on each line. Of course % could be replaced by any of the above options for specifying the range of an ex command.
When on the first A, I'd go in block visual mode ctrl-v, select the lines you want to modify, press I (insert mode with capital i), and apply any changes I want for the first line. Leaving visual mode esc will apply all changes on the first line to all lines.
Probably not the most efficient on number of key-strokes, but gives you all the freedom you want before leaving visual mode. I don't like it when I have to specify by hand the line and column range in a regex command.
I'd use >}.
Where...
>: Shifts right and
}: means until the end of the paragraph
Hope this helps.
Ctrl + v (to enter in visual mode)
Use the arrow keys to select the lines
Shift + i (takes you to insert mode)
Hit space keys or whatever you want to type in front of the selected lines.
Save the changes (Use :w) and now you will see the changes in all the selected lines.
I would do like Nigu. Another solution is to use :normal:
<S-v> to enter VISUAL-LINE mode
3j or jjj or /D<CR> to select the lines
:norm I<Space><Space>, the correct range ('<,'>) being inserted automatically
:normal is probably a bit overkill for this specific case but sometimes you may want to perform a bunch of complex operations on a range of lines.
You can select the lines in visual mode, and type >. This assumes that you've set your tabs up to insert spaces, e.g.:
setl expandtab
setl shiftwidth=4
setl tabstop=4
(replace 4 with your preference in indentation)
If the lines form a paragraph, >ap in normal mode will shift the whole paragraph above and below the current position.
Let's assume you want to shift a block of code:
setup the count of spaces used by each shift command, :set shiftwidth=1, default is 8.
press Ctrl+v in appropriate place and move cursor up k or down j to select some area.
press > to shift the block and . to repeat the action until desired position (if cursor is missed, turn back with h or b).
Another thing you could try is a macro. If you do not know already, you start a macro with q and select the register to save the macro... so to save your macro in register a you would type qa in normal mode.
At the bottom there should be something that says recording. Now just do your movement as you would like.
So in this case you wanted 2 spaces in front of every line, so with your cursor already at the beginning of the first line, go into insert mode, and hit space twice. Now hit escape to go to normal mode, then down to the next line, then to the beginning of that line, and press q. This ends and saves the macro
(so that it is all in one place, this is the full list of key combinations you would do, where <esc> is when you press the escape key, and <space> is where you hit the space bar: qai<space><space><esc>j0q This saves the macro in register a )
Now to play the macro back you do # followed by the register you saved it in... so in this example #a. Now the second line will also have 2 spaces in front of them.
Macros can also run multiple times, so if I did 3#a the macro would run 3 times, and you would be done with this.
I like using macros for this like this because it is more intuitive to me, because I can do exactly what I want it to do, and just replay it multiple times.
I was looking for similar solution, and use this variation
VG:norm[N]I
N = numbers of spaces to insert.
V=Crtl-V
*** Notice *** put space immediate after I.

Resources