19

I want to have a quick way of setting the Vim 'paste' option, inserting some text, and reverting to the previous value of 'paste'.

A typical use case insert the OS clipboard content literally, regardless of any insert mode rewriting that may be active, such as automatic indentation, and without changing the state of Vim. Another use case would be to allow an OS macro feature to inject keystrokes into Vim and have them interpreted as literal text.

This obviously generalizes to other options — the general idea is to set some options but only for the duration of one trip through insert mode.

Basically I want to bind a key sequence (say _i) to a macro that does this

:set paste
i…<Esc>
:set nopaste

where by i…<Esc> I mean switch to insert mode (as with the i command) and resume the macro upon return to command mode, except that I want to end up with the 'paste' still active if it was active beforehand. How can I do this?

Note: The content of the OS clipboard is mapped to the "* register. When that works, the 'paste' option isn't very useful. The motivating scenario for this question is for those times when the conditions for "* register support are not met — Vim isn't compiled with the +xterm_clipboard feature, or it's running in a terminal such as Screen or over SSH which isolates it from the ambient X server.

2
  • 1
    I like your question (I've been there many times myself). However, isn't it easier to paste from the + or * register?
    – yo'
    Feb 4, 2015 at 19:49
  • @yo' Only when they work. Which, for my uses of Vim, is often not the case. Feb 4, 2015 at 21:02

4 Answers 4

15

Give this a try:

function! Paste_Func()
    let s:inPaste = &paste
    if !s:inPaste
        set paste
    endif

    echom s:inPaste
    augroup paste_callback
        autocmd!
        autocmd InsertLeave <buffer> call Paste_End()
    augroup END

    startinsert
endfunction

function! Paste_End()
    augroup paste_callback
        autocmd!
    augroup END
    augroup! paste_callback

    if !s:inPaste
        set nopaste
    endif
endfunction

map _i :call Paste_Func()<cr>

It stores your current paste status in the inPaste variable and sets paste if it isn't already set. Then it sets up an autocmd for when you leave insert mode, and then puts you in insert mode.

When you leave insert mode it runs the autocmd, which first removes the autocmd (so it doesn't get run when you leave insert mode any other way), and finally sets nopaste if you were not in paste mode originally.

Also, if you are using vim in a terminal, you may want to take a look at vim-bracketed-paste, which uses the bracketed paste mode feature provided by several terminal emulators to detect if you are pasting and set the mode automatically.

Edit: fixed the script

2
  • This seems on the right track (in particular, I had no idea how to “bracket” a stretch of insertion by normal world commands). Thanks. However, it isn't quite right and I don't see where the problem is: after _i, the paste option is off, even if it was on before. Feb 4, 2015 at 21:16
  • You are right! I am pretty sure I had tested that, but I must have changed something. I have updated the script in the post, see if it is working for you now.
    – Chad
    Feb 4, 2015 at 22:53
4

except that I want to end up with the 'paste' still active if it was active beforehand.

'paste' should be active for as short a time as possible. It disables a lot of functionality (including maps), because its sole purpose is to avoid misinterpreting text that is being pasted. As such, I think the quoted requirement shouldn't really be necessary.

That being said, it's actually quite easy to paste without needing to set 'paste'. If you're running gvim or have +xterm_clipboard in console vim, then you can simply use "+p to paste from the OS clipboard.

The problem of automatic indentation while paste only really happens in two scenarios. Inserting the contents of a register while in insert mode (<C-r>+) or middle-click pasting with the mouse.

Instead of inserting the contents of a register while in insert mode, pasting from the register in normal mode will avoid the reformatting issue.

If you want to middle-click paste with the mouse, then use the 'mouse' option to let Vim, instead of the terminal, handle the middle-click. Vim will then insert the contents literally instead of interpreting the incoming text as being typed.

6
  • 2
    None of this answers my question. I put in explicit requirements for a reason! Usually 'paste' is indeed not active beforehand, but I don't want to have to think about this. I often work in a Vim that doesn't have access to the X clipboard or mouse, either because my Vim build doesn't have the xterm_clipboard feature, or because I'm working in e.g. a Screen session which happens to be currently attached to an X terminal. Feb 4, 2015 at 17:30
  • @Gilles Then could you explain how you're pasting? That's relevant information to be able to provide an answer that can wrap that action with what you want to do.
    – jamessan
    Feb 4, 2015 at 17:55
  • 1
    My basic use case is to paste with the middle mouse button or with Shift+Insert. That's not really relevant though: the core of the question is how to set an option, switch to insert mode (with i, I'm not asking how to parametrize this), and restore the value of the option upon return from insert mode. Feb 4, 2015 at 18:35
  • 1
    @Gilles The core of your question as stated in this comment is much clearer to me than your original question. Thanks.
    – jamessan
    Feb 4, 2015 at 19:48
  • 1
    @Gilles It is not relevant to you, but it can be relevant to future visitors. Therefore either you can put it in the question itself ("I know I can use "*p or "+p to paste from the clipboards, but I wan't to use the system's paste abilities") and then this answer is unnecessary. Or you don't, and then I think this answer has its place here.
    – yo'
    Feb 4, 2015 at 19:51
4

Personally, I use the yo keybinding from Tim Pope's excellent vim-unimpaired plugin for exactly this reason. From his documentation:

A toggle has not been provided for 'paste' because the typical use case of wrapping of a solitary insertion is so wasteful: You toggle twice, but you only paste once (YOPO). Instead, press yo or yO to invoke |o| or |O| with 'paste' already set. Leaving insert mode sets 'nopaste' automatically.

It might be overkill to install the plugin simply for your question, but I find it provides a wealth of other useful keybindings too (more information in the README).

1

With Vim 8+ on Linux or Mac, you can now simply use the terminal's native paste (e.g. middle mouse button, ctrl+shift+V in Gnome, cmd+V on Mac) if the terminal supports bracketed paste. Do not press i for Insert Mode.

It will paste the contents of your OS clipboard, preserving the spaces and tabs without adding autoindenting. It's equivalent to the old :set paste, i, ctrl+shift+V, esc, :set nopaste method.

You don't even need the +clipboard or +xterm_clipboard vim features installed anymore. This feature is called "bracketed paste". For more details, see https://stackoverflow.com/questions/2514445/turning-off-auto-indent-when-pasting-text-into-vim/56781763#56781763

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.