vim copy paste a block with different line lengths - vim

Is there a way in vim / nvim to block copy paste a set of lines with different lengths.
I want to edit the below text from:
select
date
, impression_cnt
, click_cnt
, like_cnt
from table
to:
select
date
, sum(impression_cnt) as impression_cnt
, sum(click_cnt) as click_cnt
, sum(like_cnt) as like_cnt
from table
I know I can do two separate operations using visual line mode and doing something like
:s/^/sum(
:s/$/) as
However this won't handle the column alias at end.
In VSCode you block enter multiple cursor edit mode and block copy paste the columns, and simple <C-C> and <C-V> and type out max( and ) as in the block mode.
How can I perform this operation without a complex regex that is difficult to remember?

With a single, very simple substitution, assuming the cursor is on the first line to change:
:,+2s/\w\+/sum(&) as &<CR>
The pattern, \w\+, matches one or more "keyword characters", as many as possible, it covers the column names, which are the only part of the lines that need changing,
the & in the replacement part reuses the whole match.
With a manual macro, same assumption:
:,+2norm $ciwsum(<C-v><C-R>") as <C-v><C-r>"<CR>
$ places the cursor on the last character of the line,
ciw cuts the word under the cursor to the default register and enters insert mode,
sum( is just part of the new text you type,
<C-R>" inserts the content of the default register (the <C-v> is used to insert a literal ^R which is needed in this case),
) as is the rest of the new text you type,
and then you insert the column name once again.
Bonus, with the famous "dot formula", same assumption:
$ciwsum(<C-R>") as <C-r>"<Esc>
j.
j.
See :help :range, :help s/\&, :help :normal, :help c, :help iw, :help i_ctrl-r, :help ..
How can I perform this operation without a complex regex that is difficult to remember?
Complex patterns are supposed to be composed on the fly, not remembered so that's not where the problem with complex patterns is. The problem with complex patterns is that it can take time to get them right, which can be a productivity killer.

Related

Why does changing case on words change behaviour when inside a macro?

I was changing some words to uppercase, I hit viw~ to change the case of the word from lowercase to uppercase. I moved foward a word and hit . to repeat the action on the next word and I noticed that it affected the case of some of the letters of the word ahead and on other times it would not change case of the entire word.
Here is an example done with vim -u NONE on a file with a single sentence
this is a test sentence
with my cursor at the start of the sentence, I hit
viw~
my sentence is now:
THIS is an example test sentence
I move forward by 1 word with w and hit . to repeat the action.
My sentence is now:
THIS IS An example test sentence
w.
THIS IS aN Example test sentence
w.
THIS IS aN eXAMple test sentence
w.
THIS IS aN eXAMple TEST sentence
The same behaviour happens when I instead capture the actions as a macro instead of using .
I suspect vim is just changing the case of the same number of letters as was in the first word, but why? Why does viw not work in macros?
The action was repeated on an area equivalent to the area covered by the previous command. This has nothing to do with macros.
From :help .:
Note that when repeating a command that used a Visual selection, the same SIZE
of area is used, see visual-repeat.
and from :help visual-repeat:
When repeating a Visual mode operator, the operator will be applied to the
same amount of text as the last time:
- Linewise Visual mode: The same number of lines.
- Blockwise Visual mode: The same number of lines and columns.
- Normal Visual mode within one line: The same number of characters.
- Normal Visual mode with several lines: The same number of lines, in the
last line the same number of characters as in the last line the last time.
The start of the text is the Cursor position. If the "$" command was used as
one of the last commands to extend the highlighted text, the repeating will
be applied up to the rightmost column of the longest line.
One of Vim's strengths is that you don't need to select text before doing many actions. In this case, you should use the :help g~ operator, which will be repeated with . in a more intuitive way:
g~iw
instead of:
viw~
I suspect vim is just changing the case of the same number of letters [...]
You're right. In order to do what you expect, Vim would have to remember how you created the visual selection. In your example, that was easy (iw), but you may apply multiple text objects and movements, use o to move to the other side of the selection, modify that, and so on. That would be very hard to recreate elsewhere, and to avoid inconsistent behavior, Vim consistently acts stupid and just uses the previous width of the selection when redoing with the . command.
If you want to apply an operation to a certain text object or motion, skip visual mode and instead use the corresponding motion-mapping; e.g. g~iw instead of viw~.

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.

Vim equivalent of Emacs' open-rectangle

Emacs has a function called open-rectangle, which allows you to select a rectangular region (i.e. Vim's visual block mode), then hit a key combination to fill that rectangle with spaces, pushing any existing content out to the right:
This is really useful when working with vertically-aligned columns of text. I feel like I should be able to do this easily in Vim too, using visual block + a search & replace. But I can't seem to figure out why my search & replace isn't bound to my rectangle when I try it.
:'<,'>s/\^/ /
This actually indents the whole line, instead of opening up this selected region. I've tried replacing:
:'<,'>s/\v(.*)/ \1/
But that has the same effect. How can I get my pattern to understand that I only want to replace each line in the selected block with spaces + the selected area? Simple replacements like just changing letters work, but using ^ or .* doesn't work the way I'd expect.
I am aware of the ability to hit "I" and insert some spaces the drop back into normal mode, but that is harder to judge when you're indenting by a large amount, over many lines.
How about:
yPgvr<Space>
This yanks the block and pastes it to duplicate it, then re-selects the original block and replaces it with spaces.
Another way:
Visual-block select only one column.
Hit nI<Space><Esc> with n being the number of blank columns you want.
As a variation on romainl's answer, I have this:
vnoremap <C-Space> I<Space><Esc>gv
It allows both insertion of n spaces at once via a prepended count, and iterative adding of columns by repeated application of the mapping.

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.

How to do column editing in vim?

Vim is pretty powerful when editing by line - the search/replace tools are modeled to work linewise.
But what if I want to change a particular column across all lines? For example, how can I change the 80th column in my file to a # easily?
To edit a column, follow these steps:
Stand on the beginning of the column
Press Ctrl+v, then mark across the column you want to edit.
Press Shift+i to insert text at the beginning of the column, Shift+a to append text, r to replace highlighted text, d to delete, c to change... etc.
Hit ESC when done.
I think people (me) sometimes map the column editing keys to Ctrl+Q so it won't collide with visual select line (V) or paste-text if you mapped it as such.
...I couldn't follow the steps of sa125 (facepalm) so I looked someplace else and found a simpler explanation at: https://blog.pivotal.io/labs/labs/column-edit-mode-in-vi
Ctrl+v [ and select what ever you want]
Shift+i [and write whatever...(check out ** below)]
Esc
*c without Shift can be used instead of step 2, to delete selection before insert. And also r to replace.
**!! Attention Don't be discouraged by the fact that only the first row is changed when you 'write whatever...'!!
Hope it helps!
You can use a substitution where the pattern matches a specific column (\%c):
:%s/\%80c/#/<CR>
Or you can use block-wise visual mode:
gg80|CTRL+vGr#
The 'virtualedit' option can be used to allow positioning the cursor to
positions where there is no actual character:
:set virtualedit
I may be totally off topic here, but if your idea is to avoid long lines, you could have a look at the colorcolumn option of vim 7.3.
For column-wise editing, vis.vim is really useful. You can block-select your column of interest, and manipulate it with normal commands, and even arbitrary Ex commands. From the example on that page, I have often used the pattern:
:'<,'>B s/abc/ABC/g
You can Vundle/Pathogen install vis.vim from github:
Plugin 'taku-o/vim-vis'

Resources