Is there a vim command to select pasted text? - vim

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.

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 '[.

How can I pre-fill a substitute command with the result of the previous `*` search in the position where the {string} goes?

I currently use the following mapping to substitute the result of the last search pattern with a new word in the entire buffer:
nnoremap <Leader>sa :%s///g<left><left>
What I would like is to put the result of the last search pattern where the new word goes.
Example:
suppose my cursor is standing on the word "hello"
Then I press *
Then I invoke the mapping with <Leader>sa
At this point, my command line is filled with :%s///g. What I would like to have is :%s//hello/g.
I tried the mapping below, but it adds the whole word delimeters (\< and \>) which I don't want.
nnoremap <Leader>sa :%s///g<left><left><C-r>/
--- EDIT ---
After some much needed clarification, I think that the simplest approach is to use :help s/\& in the replacement part of your substitution:
nnoremap <key> :%s//&/g<left><left>
If you really need a more visually explicit method, you can trim the \< and the \>, like this:
nnoremap <key> :%s//<C-r>=substitute(#/,'\\<\\|\\>','','g')<CR>/g<left><left>
which should get you something like this:
:%s//hello/g
with the cursor after hello, ready for further editing.
--- ENDEDIT ---
In command-line mode, :help c_ctrl-r_ctrl-w inserts the word under the cursor:
nnoremap <key> :%s///g<left><left><C-r><C-w>
<cword> gets the word under the cursor, but you have to call expand and send a carriage return
nnoremap <Leader>sa :%s///g<left><left><C-r>=expand("<cword>")<CR>
One way to support visual selections and multiple words is to yank the text you want to replace then search for it with <C-r>"
nnoremap <Leader>sa :%s///g<left><left><C-r>"
You would make a visual selection, press y, then <leader>sa to replace, or /<C-r>" to search.
Edit
After reading the clarifications above, here is a different way to do (almost) the same thing:
Make a visual selection
Press *
Type cgn<C-r>"2 (e.g. change "ThisIsAVeryLongVariable" to "ThisIsAVeryLongVariable2")
Each press of . will repeat the substitution

vimscript: Get visual mode selection text in mapping

So I'm trying to have a binding that runs lvimgrep on the currently selected text.
fun! s:get_visual_selection()
let l=getline("'<")
let [line1,col1] = getpos("'<")[1:2]
let [line2,col2] = getpos("'>")[1:2]
return l[col1 - 1: col2 - 1]
endfun
vnoremap <expr> <script><leader>* ":lvimgrep /" . <SID>get_visual_selection() . "/j **/*." . expand("%:e") . " \|lopen"
The function's from the comment on the question: How to get visually selected text in VimScript
Thing is that it is behaving really weird: Most of the times the text returned by the function doesn't match the visual selection and more often than not, it is the text of the last visual selection - not the current one.
Have gone through tons of posts around getting visual selection text in vimscript but can't get it to work.
I have also tried https://stackoverflow.com/a/1534347/287085 without success (copying selection to register) - get an error when called from my binding.
The problem is that the '<,'> marks are not set until after the current selection has been left (either by executing a command on it, or through <Esc>). Here, your expression mapping makes it more complex to prepend an <Esc> to leave visual mode first, so it's easier to insert the expression with :help i_CTRL-R and the expression register =:
:vnoremap <script> <leader>* <Esc>:lvimgrep /<C-R><C-R>=<SID>get_visual_selection()<CR>/j **/*.<C-R><C-R>=expand("%:e")<CR>\|lopen
If you don't mind clobbering the default register, you could also just yank the selection:
:vnoremap <leader>* y:lvimgrep /<C-R><C-R>"/j **/*.<C-R><C-R>=expand("%:e")<CR>\|lopen

vim: how to select pasted block

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.

How to paste in a new line with vim?

I often have to paste some stuff on a new line in vim. What I usually do is:
o<Esc>p
Which inserts a new line and puts me in insertion mode, than quits insertion mode, and finally pastes.
Three keystrokes. Not very efficient. Any better ideas?
Shortly after :help p it says:
:[line]pu[t] [x] Put the text [from register x] after [line] (default
current line). This always works |linewise|, thus
this command can be used to put a yanked block as
new lines.
:[line]pu[t]! [x] Put the text [from register x] before [line]
(default current line).
Unfortunately it’s not shorter than your current solution unless you combined it with some keyboard map as suggested in a different answer. For instance, you can map it to any key (even p):
:nmap p :pu<CR>
Options:
1) Use yy to yank the whole line (including the end of line character). p will then paste the line on a new line after the current one and P (Shift-P) will paste above the current line.
2) Make a mapping: then it's only one or two keys:
:nmap ,p o<ESC>p
:nmap <F4> o<ESC>p
3) The function version of the mapping (unnecessary really, but just for completeness):
:nmap <F4> :call append(line('.'), #")<CR>
" This one may be a little better (strip the ending new-line before pasting)
:nmap <F4> :call append(line('.'), substitute(#", '\n$', '', ''))<CR>
:help let-register
:help :call
:help append()
:help line()
:help nmap
You can paste a buffer in insert mode using <C-R> followed by the name of the buffer to paste. The default buffer is ", so you would do
o<C-R>"
I found that I use <C-R>" very often and bound that to <C-F> in my vimrc:
inoremap <C-F> <C-R>"
This still uses three keystrokes, but I find it easier than Esc:
o<Alt-p>
Since you're in insert mode after hitting o, the Alt modifier will allow you to use a command as if you weren't.
Using this plugin: https://github.com/tpope/vim-unimpaired
]p pastes on the line below
[p pastes on the line above
advantages:
works on all yanked text (word, line, character, etc)
indents the pasted text to match the indentation of the text
around it
2 keystrokes instead of 3 and much "easier" strokes
fast
Personally I've nmapped Enter (CR) like this:
nmap <CR> o<Esc>k
...based on this Vim Wikia article.
This way I can make newlines directly from normal mode, and combining this with wanting to paste to a newline below I'd do:
<CR>jp
You could also skip k in the nmap above, depending on what functionality you prefer from Enter, so it would just be <CR>p.
I've also imapped jj to Esc, which would also assist in this case. Esc is way too far away from the home row for how significant it is in vim.
Not shorter than the other solutions, but I do think it feels less clunky than some of them, and it has other uses too.
If you wanted to stay in the insert mode, you can do o ctrl+o p
o – insert mode and go to the new line
ctrl+o – run a single command
like in normal mode
p – paste
It's three keystrokes but you stay in insert mode and also o ctrl+o is quite fast so I personally treat it as 2.5 keystrokes.
If you're copying a whole line then pasting a whole line, use Y to yank the line or lines, including line break, in the first place, and p to paste. You can also use V, which is visual line mode, in contrast with plain v for visual mode.
I have mapping inoremap jj <ESC>. So it is easy to insert new line with ojj and Ojj and then p.
so ojjp paste new a newline. it have one more stroke then o<esc>p but ojjp is easy for me.
I found an elegant solution to this. If you are putting the yank register in your OS's clipboard (which is great anyway), with
set clipboard+=unnamed
than you can do o<Ctl-v>.
Besides being fewer strokes, this improves on both o<Esc>p and :pu because it preserves indenting: both of the other options start you at character zero on the new line.
Caveat is that this may or may not be OS dependent. All I know is that it works on recent version of OS X, but clipboard is just one of many ways to get yank in the OS clipboard.
If you want to paste in a new line and still keep indentation, create this mapping:
nnoremap <leader>p oq<BS><Esc>p
Prerequisite: you have leader mapped and you have set autoindent in your .vimrc.
Explanation: a new line is created with 'o', 'q' is typed and then back-spaced on (to keep indentation), and 'esc' brings you back to normal mode where you finally paste.
If you also want to end in insert mode, it is possible to paste while in insert mode using CTRL-R ". https://stackoverflow.com/a/2861909/461834
Still three keystrokes, but no escape, and you save a keystroke if you want to end in insert anyway.
I use the following mapping in my Neovim config:
nnoremap <leader>p m`o<ESC>p``
nnoremap <leader>P m`O<ESC>p``
A little explanation:
m`: set a mark in the current cursor position.
o<Esc>p: create a new line below and paste the text in this line
O<Esc>P: create a new line above and paste the text in this line
``: put the cursor in the original position
See :h mark for more information about marks in Vim.
This solution only seems to apply when the block of copied text starts on a new line (as opposed to grabbing a snippet of text somewhere within a line), but you can always start your copy on the last character you want to grab, then navigate to the last character at the end of line prior to the start of your desired copy block. Then when you want to paste it, place the cursor at the end of the line under which you want your text to be pasted and hit p. If I haven't screwed up the explanation, this should provide the effect you're looking for.

Resources