Undo a paste without undoing previous typing - vim

In vim I frequently end up undoing more than I want to after a messed up paste from the system clipboard. Is there a better way?
To reproduce:
Open iTerm # or terminal
vi # open vim
i # enter insert mode
type some stuff
Cmd-V # paste the contents of the OS X clipboard
The paste is a mess because I haven't :set paste. So
Esc # enter command mode
u # undo
but that undoes my typing as well as my paste.
Is there a different undo I can use? Apart from remembering to :set paste before pasting is there a better way to do this in general?

This is not the answer you're looking for, but you really should stop using vim as a non-modal editor. If you want to paste then return to normal mode and use vim's paste commands.
Assuming that you have a vim version with clipboard access this should do the trick "+p. You can also facilitate this by setting your unnamed register to be the + (or *) register, such that pasting from clipboard becomes a simple p.
The following question has a great answer that includes all this information How to make vim paste from (and copy to) system's clipboard?.

I'm not sure there's anything you can do after the fact, but one solution is to hit Ctrl-G u in insert mode just before you paste. This breaks the undo block into two separate blocks - so the paste will be remembered as a separate undoable action.
Granted if you have to remember to do this, you might as well just use :set paste instead - but on the upside it's fewer keystrokes and you don't have to go to command mode first.

Take a look at this plugin, it can auto run :set paste! when you use Cmd-V(or Ctrl-V) to paste some text. And leave paste mode when you finished.

The following mappings create an additional undo point (via :help i_CTRL-G_u) before pasting in insert mode. This way, you can undo the paste separately.
inoremap <C-r> <C-g>u<C-r>
inoremap <C-v> <C-g>u<C-v>

Actually the solution is you have to go to command mode(e.g. Esc) first and re-enter the insert mode, but it only works if I type manually but it seems "randomly" stop working if I test it in ~/.vimrc. Google doesn't help at all.
I spends a lot of time try to fix this issue and I just figure out the reason in my case:
Don't map the paste key same with the terminal existing paste key
e.g. Ctrl+Shift+V will paste in my Konsole terminal, but if I assign this key <C-S-v> in ~/.vimrc, the "undo for only single paste instead of multiple pastes" will not working.
In my case, I have to use <C-v> instead of <C-S-v>:
inoremap <C-v> <Esc>"+pi<Esc>i<Right><Right>
Your case may difference, but the point is same: don't assign the same paste key conflicts with existing terminal emulator key.
I've 100% proved this conclusion by set my terminal paste key to Ctrl+V and now <C-v> stop working but <C-S-v> working.
Note also that the vim is too sensitive and strange. I figure out I have to use i and then 2 Right keys manually to make it works in the correct cursor position, that's means I have to put i and 2 Right keys in the ~/.vimrc too. Your case might difference, but the point is same, ensure the keys+order in ~/.vimrc 100% match with what you type manually.

Related

Vim-commands pasted from clipboard inserts commands instead of executing them

For quick execution of some commands I want to type them somewhere, then paste them into vim for execution. A while (some years or 10 years ago) this worked. Nowadays, vim enters insert mode and my commands get inserted into my file. I know that I can have macros for that, but for quick repetition of some commands this was very useful. Couldnt find anything about it, coz when asking for vim and paste only answers related to :set paste etc show up. Example of pasted text:
/foo
yy?bar
p/foo
j
Should, when pasted in command mode, search for the next foo, yank the line, search backwards for next bar, then paste the yanked foo-line, then go behind that foo-line.
Again, to make it clear: I dont want to know about workarounds (makros, scripts, and so on), I want to know how to disable (temporarily) vim from distinguishing between text typed with keyboard and text pasted.
This is the result of "bracketed paste mode". See :help xterm-bracketed-paste.
Disable "bracketed paste mode" by clearing 't_BE':
set t_BE=
If your Vim has been compiled with clipboard support then you can just leave 't_BE' as is and instead execute clipboard as a register via #* or #+ which will probably be more "idiomatic" way to handle such use case.
For more informations see :h #.
I had this same problem...
I have LARGE files of vim commands that I use to bulk reformatting hundreds of plain text files. That is I would: paste commands, next file, paste commands, next file, and in so doing edit hundreds of files, with the given set of vim commands, in just a minute or so...
Then it all suddenly stopped working because Bracketed Paste mode was added... (part of patch 8.0.0238 I believe).
However I still liked the added ability to paste text when in insert mode, without vim auto-indent making a mess of the inserted text, so did not want to lose that either...
My solution, was to disable paste while in normal or command modes,
while leaving brackets paste as in for insert mode...
nmap <PasteStart> <NOP>
nmap <PasteEnd> <NOP>
cmap <PasteStart> <NOP>
cmap <PasteEnd> <NOP>

How to use different registers in Vim to copy/paste from/to OS clipboard -- how exactly?

I've read this How to make vim paste from (and copy to) system's clipboard? and I know what the hotkeys are. But I'm unable to execute any of those commands. For example, what exactly should I press to call
"* or "+? In which mode also? I've tried different things and none of them worked.
I am assuming you've double-checked that :echo has('clipboard') returns 1. If it returns 0, you're out of luck since vim isn't compiled with access to the system clipboard.
If you have clipboard powers, then yanking and pasting inside of vim is done with pressing just the letter y and the letter p, in normal mode. Start doing this first, to confirm that you can yank and paste inside of vim. For instance, yank a line: yy and paste it p.
Next, confirm that you can yank inside of vim to the system clipboard with "*y. (That means pressing the double-quote (shift-'), then an asterix (shift-8), then the letter y, all in quick-ish succession. Toggle over to another app and paste with the regular control-V. (You may be able to look at the bottom left of status line to see what you are literally typing, which might help).
If that works, then the clipboard functionality is "good to go." If it doesn't you might need to tweak your .vimrc to get things working. Try setting the clipboard to unnamed: set clipboard=unnamed and retest step 3 again.

Why does Vim always manage to clip off at least a couple of characters when copying and pasting?

Vim always manages to clip off at least of couple of characters when I copy something from a text file, such as a public rsa key for example.
Generally, I open a text file in my computer, highlight the text, copy it to my clipboard. I go into my terminal (with Vim already open) and then:
i (for insert)
ctrl+shift+v
Am I doing something wrong?
I've double checked, and triple checked, this, and I am absolutely sure that I highlighted all of the text that I needed to copy. Other times it works fine. There does not seem to be any consistency in regards to when it happens.
Anyone experience this?
This usually happens because something in the pasted text triggers a key mapping unexpectedly. This is what paste mode is for.
Do this before pasting:
:set paste
And turn it off after:
:set nopaste
This can be annoying to type frequently, so there is a way to map it to a key combination. I use ,p for this, and have this in my .vimrc:
set pastetoggle=,p
(Yes, I use an actual comma here, not <Leader>. That's because <Leader> won't work here, as this isn't technically a mapping.)
This is a toggle, so you can use it to turn the mode on and off. It works in both normal mode and insert mode.
You do want to turn it off after the paste. Since paste mode disables your insert mappings, you don't want to leave it on all the time.
You can read more about the paste option with :help 'paste.
The annoyance of toggling to and form paste mode can be avoided by using "+p or "*p. (You're putting the quoteplus register).
More often than not, I prefer "+P, since this leaves my cursor at the end of properly formatted put. see :help quoteplus for details. So the whole workflow is:
outside of vim: copy to clipboard
inside of vim: "+P

Quickest way to paste block of text into the vi editor from an external source

For instance, copying a configuration section from a web page and then pasting it into a .conf file that you have open in vi.
Enter insert mode (Type i)
Type: Ctrl + Shift + v
Or if you use the system register, you can paste without being in insert mode:
"*p
This will paste the system's clipboard at the point of the cursor. No insert mode needed.
The real answer:
:set paste
Enter Insert Mode: hit i
Paste: Command + v or Control + v
ESC
:set nopaste
One thing to bear in mind: Sometimes Vim auto-indents text. This is mostly fine, but sometimes it messes up text that you paste into a document.
If your indentations are awry, remove the pasted text, type :set paste, paste the text in again, and when you're done, type :set nopaste.
The easiest way is just to copy the text and just right click where you want to paste it in Vim in INSERT mode.
If you are using gVim, hit Ctrl + R and then either * or + in insert mode. It will paste the last copied text.
Ctrl-V/ Apple-V? Just make sure you're in insert mode in vi (i)
Use your systems paste shortcut key while in Insert mode, or if your source is in another file, you can type :r <fileName>, and it will be pasted at the current location of your cursor.
The easiest way on *nix is by selecting it with the mouse and pasting it in Vim with a middle click, after having put vi in insert mode.
The middle click could be a both left-right key if you're using a touchpad.
The quickest way is to paste it using whatever paste key your system uses (e.g. ⌘-v for Macs, Ctrl-V for Windows, etc.) in insert mode.
Some terminals require you to use Shift-Ctrl-V. However you are able to paste onto the command-line is how you should paste into Vim. However, this can cause some problems with indentation, which is where :set paste comes in. The fastest way to get in and out of this is to set a pastetoggle (see :help pastetoggle). For example, I use
set pastetoggle=<leader>p
The reason to use a pastetoggle instead of a mapping is because if you set a mapping insert mode, it will read it literally when in paste mode. Thus if you :set paste, go into insert mode, and type in any imap the mapping will not be completed, but instead the literal characters will be inserted. With pastetoggle you can get around that since it's a built-in feature.
As others have said, if you're in insert mode, you can also use <C-r>*, but why? Your normal pasting flow is most likely better. Understanding the * register and <C-r> is an important skill however. You can read more about them at :help registers and :help i_CTRL-R. You could also use "*p, but if you're faster at typing that than your normal paste I'm impressed.
Of course you could map that to something else, but again... why? You should get used to quickly getting into insert mode with i, I, a, A, o, O, s, S, c, and C so that you can be precise.

Pasting from the clipboard and automatically toggling ":set paste"

When I paste things from the clipboard, they're normally (always) multilined, and in those cases (and those cases only), I'd like :set paste to be triggered, since otherwise the tabbing will increase with each line (you've all seen it!).
Though the problem with :set paste is that it doesn't behave well with set smartindent, causing the cursor to jump to the beginning of a new line instead of at the correct indent. So I'd like to enable it for this instance only.
I'm using Mac, sshing to a Debian machine with Vim, and thus pasting in Insert mode using cmd + v.
I don't use a mac, but I believe I have the prefix right here: <D-v> should mean cmd-v. For insert mode:
:imap <D-v> ^O:set paste<Enter>^R+^O:set nopaste<Enter>
or really, just do this:
:imap <D-V> ^O"+p
The ^O and ^R are literal control-O and control-R, which you can type with ^V^O (control-v control-o) and ^V^R (control-v control-r). Control-O in insert mode allows you to execute one command then return to insert mode; here you can use it to put from the clipboard register.
This worked for me when I tested them mapped to a different key, so you should be all set.
There's no need to map anything when not in insert mode; you can just use "+p.
I have the following in my .vimrc:
inoremap <S-Insert> <ESC>:setl paste<CR>gi<C-R>+<ESC>:setl nopaste<CR>gi
gi is to start insert mode in the same position as where insert mode was stopped last time in the current buffer.
Update:
Jefromi posted a better solution. I have tinkered it a bit
inoremap <S-Insert> <ESC>"+p`]a
It inserts clipboard text and places the cursor right after it.
You're right in that you should only enable 'paste' when you need it. It does more than just affect indenting. You can read everything that it affects in its documentation. A related option that is very useful to ease the use of 'paste' is 'pastetoggle'.
If you were using X-forwarding and a terminal that can properly communicate mouse actions, you could also take advantage of the 'mouse' option. With :set mouse=a, Vim is made aware of what the mouse is doing and therefore won't perform automatic indentation when it receives a multi-line paste via a middle-button mouse click.
Even without the mouse capability, X-forwarding could help because Vim will do the same thing when manually pasting from the clipboard or selection registers ("+ and "* respectively).
This ought to be solvable with a Vim script. (I hate Vim scripting, so it would have to be a much more serious infliction to cause me to solve it myself.) Even with iTerm2's "paste slowly" mode, the default is to break the data to be pasted into 16 byte chunks and send one every 0.125 seconds. Therefore, you should be able to programmatically detect a 16 byte chunk of "keystrokes" and do something about it.
In pseudocode that would look like:
if too_fast_too_be_human():
set('pastemode', True)
else
set('pastemode', False)
# where either
def too_fast_too_be_human
char_threshold = 16
return len(input_buffer) > char_threshold
# or
def too_fast_too_be_human
static byte_times = []
char_threshold = 16
time_threshold = 0.125
byte_times.append(now())
while(len(byte_times) > char_threshold):
byte_times.unshift()
return (byte_times[-1] - byte_times[0]) < time_threshold
There are weaknesses to that, but it would work for most cases.
We can paste (insert mode) without messing up indentation using
Ctrl-r Ctrl-o Register
Ctrl-r Ctrl-o +
Ctrl-r Ctrl-o *
Ctrl-r Ctrl-o 0
CTRL-R CTRL-O {0-9a-z"%#*+/:.-=} *i_CTRL-R_CTRL-O*
Insert the contents of a register literally and don't
auto-indent. Does the same as pasting with the mouse
"MiddleMouse". When the register is linewise this will
insert the text above the current line, like with `P`.
Does not replace characters!
The '.' register (last inserted text) is still inserted as
typed.

Resources