Why does Vim indent pasted code incorrectly?

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?

Asked By: elbarna

||

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.

Answered By: casey

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

Answered By: cuonglm

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.

Answered By: exussum

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) 🙂

Answered By: Erik Greenwald

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.

Answered By: zyy

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
Answered By: ali b
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.