153

In Vim, if I paste this script:

#!/bin/sh
VAR=1
while ((VAR <  10))
    do
        echo "VAR1 is now $VAR"
        ((VAR = VAR +2))
    done
    echo "finish"

I get these strange results:

#!/bin/sh
#VAR=1
#while ((VAR <  10))
#       do
#                       echo "VAR1 is now $VAR"
#                                       ((VAR = VAR +2))
#                                               done
#                                                       echo "finish"
#                                                       

Hash signs (#) and tabs have appeared. Why?

6
  • 32
    This might be a better question for vi.stackexchange.com Commented Apr 28, 2015 at 18:10
  • @EricRenouf why? (honest question) Commented Apr 29, 2015 at 4:48
  • 3
    @qix my thought was this is a question about how vim works, which is a common tool to be used on *nix, but *nix isn't a requirement for using vim Commented Apr 29, 2015 at 10:23
  • 1
    @JaredBurrows I sure hope it makes it Commented Apr 29, 2015 at 10:24
  • 1
    How are you triggering the paste? With the mouse?
    – Ben Voigt
    Commented Apr 29, 2015 at 16:00

6 Answers 6

185

There're two reasons:

For pasting in vim while auto-indent is enabled, you must change to paste mode by typing:

:set paste

Then you can change to insert mode and paste your code. After pasting is done, type:

:set nopaste

to turn off paste mode. Since this is a common and frequent action, vim offers toggling paste mode:

set pastetoggle=<F2>

You can change F2 to whatever key you want, and now you can turn pasting on and off easily.


To turn off auto-insert of comments, you can add these lines to your vimrc:

augroup auto_comment
    au!
    au FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o
augroup END

vim also provides a pasting register for you to paste text from the system clipboard. You can use "*p or "+p depending on your system. On a system without X11, such as OSX or Windows, you have to use the * register. On an X11 system, like Linux, you can use both.

Further reading

13
  • 2
    I have been using Vim forever and never knew about this. Many thanks.
    – Caja
    Commented Apr 28, 2015 at 19:06
  • Most modern graphical terminal emulators support a feature called "bracketed paste mode". Vim can ask the terminal to enable this mode, which, in turn, will surround pasted text with certain escape sequences. Vim can recognize this and turn off wrapping/indenting for the duration of the paste. Long story stort: pasting will "work as expected". I'm not a vim user, but a quick websearch will sure tell you how to configure this mode.
    – egmont
    Commented Apr 28, 2015 at 19:10
  • 2
    @MichaelDurrant set paste should never be in your vimrc. It disables or resets a lot of things, including insert mode mappings, command line mappings, abbreviations, textwidth, wrapmargin, autoindent, smartindent, softtabstop, formatoptions, indentexpr, and a couple of others. :h paste has the whole list. Most people use some or all of these things and wonder why there settings are ignored.
    – FDinoff
    Commented Apr 29, 2015 at 3:44
  • 5
    I usually use :r!cat to paste verbatim. Commented Apr 29, 2015 at 13:59
  • 1
    It may be worth discussing the interaction with set mouse, which can automatically enter and leave paste mode when pasting with mouse click.
    – Ben Voigt
    Commented Apr 29, 2015 at 16:01
40

Use the vim paste. What you want is to paste what is on the clipboard buffer "+p

This selects the + and pastes it in place.

If you're using Linux, * is the X/middle-click buffer (the last selected text).

Then vim knows it's a paste.

Otherwise vim thinks you have typed the keys being pasted and does its own auto-indentation (on top of your copied indentation) all the way to the end of the paste.

As a note for this to work over SSH you need to set the option for your clipboard to be shared -Y

See man ssh for more details.

8
  • It looks like this only works for the graphical vim (gvim); vim running in a terminal emulator pastes the last deleted text with "*p, not the current selection.
    – wurtel
    Commented Apr 29, 2015 at 7:18
  • I dont use gvim, only the terminal vim. what is your mouse setting ? my mouse setting is c. Not sure how it works when the mouse selection is allowed. set mouse?
    – exussum
    Commented Apr 29, 2015 at 7:28
  • 2
    also check vim --version se see if it was compiled with clipboard support +xterm_clipboard should be in the output
    – exussum
    Commented Apr 29, 2015 at 7:31
  • @wurtel: Maybe you have set clipboard with unnamed string.
    – cuonglm
    Commented Apr 29, 2015 at 9:10
  • +1, my vimrc has set clipboard=unnamedplus so that yanking and pasting uses system clipboard (register +) by default. Works for me (xubuntu) for both vim and gvim
    – Kos
    Commented Apr 29, 2015 at 14:19
9

The tabs were inserted because you have autoindent turned on and you can disable that behavior by turning off autoindent (:set noai) before you paste into terminal.

The commented lines are produced by auto commenting and can be disabled by turning that off.

Alternative to those you should get the desired behavior using the toggles :set paste, pasting your formatted code and :set nopaste to restore normal behavior.

3

When you paste, you send a stream of characters. VIM has features that alter this stream to make life easier for humans. :set paste is a workaround disable all stream alterations, can be re-enabled with :set nopaste. This all goes back to the one true editor, ed(1) :)

2

The reason has been explained very well by the other posters. Here I would like to provide a solution which handles the situation automatically.

With the following in your ~\.vimrc

let &t_SI .= "\<Esc>[?2004h"
let &t_EI .= "\<Esc>[?2004l"

inoremap <special> <expr> <Esc>[200~ XTermPasteBegin()

function! XTermPasteBegin()
  set pastetoggle=<Esc>[201~
  set paste
  return ""
endfunction

you can paste freely without worrying about the auto-indentions.

If you work in tmux, then you have to write instead the following

function! WrapForTmux(s)
  if !exists('$TMUX')
    return a:s
  endif

  let tmux_start = "\<Esc>Ptmux;"
  let tmux_end = "\<Esc>\\"

  return tmux_start . substitute(a:s, "\<Esc>", "\<Esc>\<Esc>", 'g') . tmux_end
endfunction

let &t_SI .= WrapForTmux("\<Esc>[?2004h")
let &t_EI .= WrapForTmux("\<Esc>[?2004l")

function! XTermPasteBegin()
  set pastetoggle=<Esc>[201~
  set paste
  return ""
endfunction

inoremap <special> <expr> <Esc>[200~ XTermPasteBegin()

The source is Coderwall if you would like to read more.

If you work in screen the equivalent wrap-function is:

function! WrapForScreen(s)
  if exists('$TMUX') || match($TERM, "screen")==-1
    return a:s
  endif

  let screen_start = "\<Esc>P"
  let screen_end = "\<Esc>\\"

  return screen_start . a:s . screen_end
endfunction

Found in stapelberg's .vimrc.

1

Not sure from when, but as in vim9 there is a new value for 'clipboard' option, called unnamedplus. If you are in a graphical environment (and not in a tty or a ssh session), you can paste the content of the system clipboard into the buffer using just p. Also you are able to yank to the system clipboard with y. This will not cause any weird indentation.

So you can put this in your .vimrc:

set clipboard=unnamedplus

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .