Why does Vim indent pasted code incorrectly?

68,968

Solution 1

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

Solution 2

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.

Solution 3

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.

Solution 4

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

Solution 5

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.

Share:
68,968

Related videos on Youtube

elbarna
Author by

elbarna

Updated on September 18, 2022

Comments

  • elbarna
    elbarna over 1 year

    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?

    • Eric Renouf
      Eric Renouf about 9 years
      This might be a better question for vi.stackexchange.com
    • Eric Renouf
      Eric Renouf about 9 years
      @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
    • Eric Renouf
      Eric Renouf about 9 years
      @JaredBurrows I sure hope it makes it
    • DaleHarris541
      DaleHarris541 about 9 years
      How are you triggering the paste? With the mouse?
    • elbarna
      elbarna about 9 years
      No,ctrl+v keyboard on xfce console
  • Caja
    Caja about 9 years
    I have been using Vim forever and never knew about this. Many thanks.
  • egmont
    egmont about 9 years
    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.
  • Michael Durrant
    Michael Durrant about 9 years
    I added set paste to my .vimrc so it is always on which has seemed to work for some time now. Why would I ever need to turn it off / toggle it ?
  • David Lord
    David Lord about 9 years
    That would be if you ever want to use auto indent/comment, which can be pretty useful when you're writing/editing code rather than copying it.
  • ODYodel
    ODYodel about 9 years
    @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.
  • wurtel
    wurtel about 9 years
    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.
  • exussum
    exussum about 9 years
    also check vim --version se see if it was compiled with clipboard support +xterm_clipboard should be in the output
  • cuonglm
    cuonglm about 9 years
    @wurtel: Maybe you have set clipboard with unnamed string.
  • Kos
    Kos about 9 years
    +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
  • DaleHarris541
    DaleHarris541 about 9 years
    It may be worth discussing the interaction with set mouse, which can automatically enter and leave paste mode when pasting with mouse click.
  • Random832
    Random832 about 9 years
    "+ works fine on both Windows and OSX, I use it every day. Generally the two are identical on systems that don't have X11.
  • Janac Meena
    Janac Meena over 6 years
    This doesn't work in gvim 80 on Windows 10
  • cuonglm
    cuonglm over 6 years
    @JanacMeena gvim is different.
  • Itamar Katz
    Itamar Katz almost 5 years
    After I set paste and do the paste, my tab width changes to 8 spaces, and I have to source ~/.vimrc to set it back to 4 spaces. Is there a way to avoid it?
  • Quasímodo
    Quasímodo over 3 years
    Would you please extend your answer to include insert mode paste? I for one have always used Ctrl-R +, but that also screws indentation. Ctrl-R Ctrl-O + is the correct way to go.
  • exussum
    exussum over 3 years
    Paste mode shouldnt be needed if pasting direct like this
  • Quasímodo
    Quasímodo over 3 years
    My point is: There are ways to paste in insert mode with Ctrl-R. One of those preserves indentation. If you would not like to expand on that, I'll add a separate answer, but I think information is better if it is not shattered around.
  • NeilG
    NeilG over 2 years
    I haven't tried it yet but this looks good - very short little plugin to automatically toggle paste mode when pasting in terminal: github.com/ConradIrwin/vim-bracketed-paste