vim: how to select pasted block - vim

Is there a vim command to directly select a block of text which has just been pasted?
ps. I know about gv to reselect a block after exiting visual mode. It doesn't apply to this case.

If you want to select it just after paste (before you change anything else), use
nnoremap <expr> gV "`[".getregtype(v:register)[0]."`]"
. [ and ] marks point to start and end of the last change, v:register is set to the last register used (which is register used for the paste command unless you, for example, yank something), [0] selects only first byte of register type (it is required because for blockwise register it returns <C-v>{width}) and register type is one byte which is just the same as the keystroke you should use in normal mode to invoke visual mode.
I saw this solution somewhere on SO, you may want to search for it in order to get some alternatives.

In my case I have this map:
:nnoremap gp `[v`]
After more research I think the better solution is:
" https://vim.fandom.com/wiki/Selecting_your_pasted_text
nnoremap <expr> gp '`[' . strpart(getregtype(), 0, 1) . '`]'

I have had the following maps in my vimrc forever:
nnoremap <leader>p `[V`]
nnoremap <leader>[ `[V`]<
nnoremap <leader>] `[V`]>
They do the following:
visually select the recently pasted block
de-indent the recently pasted block
indent the recently pasted block
I probably use the indent ones even more than the selection one.

Related

Is there a way to copy a selected area up or down in vim?

In VSCode you can copy and paste selected lines of text up or down using Alt+Shift + Up or Down.
I switched to vim a few months ago, and I really miss this feature.
I found out you can move selected lines in visual mode up or down using these visual mode bindings,
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv
but it'd be great if you could copy and paste up and down as well without using yy and p because when you're done yanking, the cursor is placed at the initial position, exiting visual mode and reducing productivity.
Well, that, here, is the problem with copying and pasting random snippets from the internet without understanding what they do: they are little black boxes that one can't modify or extend at will by lack of knowledge.
Let's deconstruct the first mapping:
vnoremap J :m '>+1<CR>gv=gv
:[range]m {address} moves the lines covered by [range] to below line {address}. Here, the range is automatically injected by Vim: '<,'> which means "from the first line of the latest visual selection to its last line", and the address is '>+1, meaning "the last line of the latest visual selection + 1 line". So :'<,'>m '>+1<CR> effectively moves the selected lines below themselves,
gv reselects the latest visual selection,
= indents it,
gv reselects it again for further Js or Ks.
Now, we want a similar mapping but for copying the given lines. Maybe we can start with :help :m and scroll around?
Sure enough we find :help :copy right above :help :move, which we can try right away:
xnoremap <key> :co '>+1<CR>gv=gv
Hmm, it doesn't really work the way we want but that was rather predictable:
the address is one line below the last line of the selection,
the selection is reselected and indented, which is pointless.
We can fix the first issue by removing the +1:
xnoremap <key> :co '><CR>gv=gv
and fix the second one by selecting the copied lines instead of reselecting the latest selection:
xnoremap <key> :co '><CR>V'[=gv
See :help :copy and :help '[.

Mapping select-all, copy, paste in vim

I have the following map in my vimrc:
nnoremap <C-a> ggVG
nnoremap <C-c> "*yy (might be because I'm in visual mode here?)
nnoremap <C-v> "*p
The select-all (ctrl-a) and the paste (ctrl-p) works, but the (ctrl-c) does not work with that shortcut, though it works if I manually type in the command after doing ctrl-c.
What needs to be fixed here?
The first issue I would like to address is that your mapping for copying the text, nnoremap <C-c> "*yy, will only work in normal mode. When you select text in Vim, you enter visual mode, and the first n of nnoremap makes the mapping work in normal mode only.
You can make your mapping work by using noremap (all modes), vnoremap (visual and select mode), or xnoremap (visual mode only), like this:
vnoremap <C-c> "*y
You can find more information about mappings in the documentation.
Another thing to note is that the default function of Ctrl-c is to cancel/interrupt the current command. For example, if you enter insert mode and press Ctrl-c, you will exit insert mode and go back to normal mode. With your original mappings, it will cancel the selection (exits visual mode) without copying anything.
This works for me in Neovim but I believe it should also work in Vim as well. To yank all the content I have the following mapping in my configuration:
nnoremap <leader>ya ggVGy<C-O>
Details:
gg: go to the first line
V: select the first line
G: go to the last line
y: yank selection
<C-O>: go to the previous cursor position

Vimscript - Mapping for commenting visual blocks

I'm trying to create a mapping on Vim, that behaves like the following:
First of all I select a block of code or text using on Visual mode.
The I use this mapping to substitute the first column on each line for '#' effectively commenting each line.
Up until now I have the following:
vnoremap <Leader>c :normal! :s/^/#/<cr>
But for some reason it is not working. Nothing happens when I hit <Leader>c on a block of text. On the other hand, if I have:
vnoremap <Leader>c :normal! s/^/#/<cr>
it will for example subsitute:
The grey fox.
For
/^/#/he grey fox.
Any idea on how can I solve this issue?
:normal is an Ex command that allows to execute normal mode commands (from a custom command or function, or command-line mode in general). Your keys start off with :, so immediately switch from normal (or here: visual) mode to command-line mode. That doesn't make sense. Just define the mapping like this:
vnoremap <Leader>c :s/^/#/<cr>
The : will automatically insert '<,'> for you, and that's what you want here (to operate on all selected lines). You can also define a related normal-mode mapping that works on the current (or [count]) lines:
nnoremap <Leader>c :s/^/#/<cr>
If the highlighting disturbs you, append the :nohlsearch command:
nnoremap <Leader>c :s/^/#/<bar>nohlsearch<cr>
You can simply do:
vnoremap <leader>c :s/^/#/<cr>
The substitution command will get the range, '<,'>, automatically when in visual mode.
Note: you probably want to use xnoremap instead of vnoremap.
There is a better way
Commenting is a common problem, deceptively tricky, and already solved by many plugins. I prefer to stand on the shoulder's of giants and use a plugin. I personally use commentary.vim.

How to add a map leader mapping for visual linewise mode in vim?

I'm having some trouble making this mapping work:
if exists(":Tabularize")
"rails routes file alignment in visual mode
vmap <Leader>ar :Tabularize /'[^']*'\|=>/l1l0<CR>
endif
When I source my vimrc and then:
Select several lines with vim's Visual linewise mode (V)
Press \ar
Visual selection is lost, back to Normal mode and the text remains unchanged.
I've tested the Tabularize command and it works. I now want to map it to a leader combination but it just doesn't work through the mapping. Only if I actually input the whole command in vim's CLI.
Note: I've gone through a bunch of map leader questions but none had a solution to my particular issue.
The issue is you need to use <bar> instead of | in your mapping as | separates vim commands.
xnoremap <leader>ar :Tabularize /'[^']*'\<bar>=>/l1l0<cr>
Some other thoughts:
you should probably be using noremap unless you are using <Plug> or <SID> mappings.
You are using v mode which maps both visual mode and select mode. It is probably best to use xnoremap instead
You may be interested to know that :Tabularize will align all the neighboring lines that match your pattern with out a range
:AddTabularPattern can be used to name a pattern. Add :AddTabularPattern routes /'[^']*'\<bar>=>/l1l0 to your ~/.vim/after/plugin/tabular.vim. Now you can do :Tabularize routes

Is there a vim command to select pasted text?

I find myself often repeating the following pattern of operations.
I usually go into visual mode, select some lines or block. Then I yank them using y, and paste them using p or P. The next step is to select the pasted text, to replace a variable or function name or change indentation.
I know that I can use gvto reselect the "origin" but what I would like is a similar command to select the "destination".
:help gv mentions :
After using "p" or "P" in Visual mode the text that was put will be selected.
but it is only useful when you are replacing a selection by the content of register, not when you are inserting a whole new block.
You are looking for
`[v`]
'[ and '] are marks automatically set by vim to the start and the end of the "previously changed or yanked text". v switches to visual mode in between.
I prefer the following simple mapping to Benoit's function
nnoremap <expr> g<c-v> '`[' . strpart(getregtype(), 0, 1) . '`]'
Learn more about expression maps:
:h :map-expression
As #ZyX pointed out the strpart is not needed and can be rewritten as:
nnoremap <expr> g<c-v> '`[' . getregtype()[0] . '`]'
One of your use cases is to change indentation after pasting.
I use the following maps to achieve this:
nnoremap <leader>[ `[V`]<
nnoremap <leader>] `[V`]>
They do the following:
de-indent the recently pasted block
indent the recently pasted block
I find these very useful and well used maps.

Resources