将文本粘贴到vim时关闭自动缩进

1494

我正在努力学习Vim。

当我从剪贴板粘贴代码到我的文档中时,每行开头会多出额外的空格:

line
  line
    line
我知道你可以关闭自动缩进,但由于我有一些其他设置冲突或类似的问题(在我删除它们时看起来很明显,但并不重要),所以我无法使其正常工作。

当我粘贴代码时如何关闭自动缩进,但仍然让Vim在编写代码时自动缩进?这是我的.vimrc文件:

set expandtab  
set tabstop=2  
set shiftwidth=2  
set autoindent  
set smartindent  
set bg=dark  
set nowrap  

4
值得一提的是,vim 8.0.210 版本已经原生支持括号粘贴功能,因此可以避免缩进粘贴的文本。 - sh1
2
对于新文件,为了避免在vim的粘贴/非粘贴模式之间切换,您可以执行cat > mynewfile.txt,按Enter键,粘贴您的文本,再次按Enter键,然后按Ctr+D保存。文件现已创建,您可以使用vim mynewfile.txt进行编辑。 - ccpizza
翻译:猫解决方案有一个缺点:变量被更改为该变量的值。 - Sloomy
几年前这从未是一个问题...似乎默认行为已经改变,因为我总是使用非常少的vim自定义。 - Scott Stensland
27个回答

2632

更新:更好的答案在这里:https://dev59.com/4nE85IYBdhLWcg3w_Ixr#38258720

要关闭粘贴代码时的自动缩进,可以使用特殊的“粘贴”模式。

输入

:set paste

然后粘贴您的代码。请注意,工具提示中的文本现在显示为-- INSERT (paste) --

粘贴完您的代码后,请关闭粘贴模式,以便在您输入时自动缩进正常工作。

:set nopaste

然而,我总觉得那样很麻烦。这就是为什么我映射<F3>,使其可以在编辑文本时切换粘贴模式和非粘贴模式!我将其添加到.vimrc中。

set pastetoggle=<F3>

44
这并不比先执行:set noai再执行:set ai更容易。建议使用:r! cat这个命令会更短。 - Leopd
82
我认为set paste更容易,绝对是更语义化的。这比使用noai或者noautoindent 更为重要,特别是当你作为一个熟练的打字员时,输入“noai”和“paste”几乎需要同样微小的时间。 - Victor Zamanian
54
根据原始贴文中与缩进相关的设置,:set noai并不总是有效的。 :set paste 看起来是几个设置的简写方式。请注意,翻译过程中不会包括任何解释或其他内容。 - MarkHu
15
晚来的话,但 set copyindent 可以无缝地为您处理这个问题。 - Matt Ryan
37
使用:set paste命令还会禁用其他功能,例如花括号自动补全,在粘贴代码时这也是不需要的。 - Manuel Faux
显示剩余13条评论

295
为了避免粘贴时出现不良影响,需要设置一个选项:
set paste

在你的 .vimrc 文件中加入一个有用的命令:set pastetoggle=<F10> 或其他按钮,以便轻松地在粘贴和非粘贴之间切换。


13
终于!我一直在输入:set paste / :set nopaste,太傻了!谢谢。 - imwilsonxu
4
从实际角度来看,你的答案比被采纳的答案更有用。 - Lynob
10
另一个选择是在您的vimrc中添加宏:nmap <silent> <leader>p :set paste<CR>"*p:set nopaste<CR> - Chris
@Chris 的建议不错 - 单个按键序列粘贴而无缩进问题! - RichVel
如果我总是想处于粘贴模式怎么办?有没有一种永久启用的方法?这个自动缩进功能真的很烦人。 - Jari Turkia
显示剩余2条评论

151

我通常使用:r!cat,然后粘贴(shift + insert)内容,最后按下CTRL+D

无需启用和禁用,可直接使用。


我喜欢这个直接使用选项。虽然我还在学习如何在网页上阅读vim语法。你的步骤是什么意思?特别是,假设我有一些东西在系统剪贴板上,我按什么键将其粘贴到vim文档中? - jvriesem
10
如果提供关于 :r! cat 的原因和如何工作的信息,这个答案会更有帮助。 - K Erlandsson
15
:r 命令将一个文件的内容插入到当前文档中。 !cat 命令会打开标准输入流(*nix shells)。 使用 (shift + insert) 或者对于某些终端,右键单击可以将剪贴板的内容粘贴到终端中。 CTRL+D 是文件结尾符号,它会关闭 :r !cat 会话。 - Daniel
1
这真的是“直接”的吗?那么设置一个仅用于此目的的“粘贴”选项呢? @jvriesem 如果我对您对该词的理解所做的假设是正确的话,那么这不是一个“直接”的选项。 - 0xc0de
你也可以使用 :r! cat 然后 CTRL+SHIFT+V 将其粘贴到终端中(然后按 CTRL+D)。 - Paul Rougieux
最短和最简单的Ctrl+D。 - Adiii

100

如果您正在本地工作,可以使用以下按键序列从系统剪贴板粘贴:

"+p

这是一个合适的vim命令,所以不需要担心首先进入插入模式或关闭自动缩进。

当然,如果您正在远程工作(例如通过SSH控制台),那么这种方法不起作用,您应该采用其他描述的方式::set noai、插入模式、粘贴到控制台、离开插入模式、:set ai 路线。


12
我很久以前写过这个答案。如今我使用“:set paste”和“:set nopaste”,因为尽管它们更长,但更容易记住,而且我不必每次都查找! - thomasrutter
6
在一些嵌入式系统中(主要基于busybox),可能没有实现:set paste,因此应该使用:set noai代替。 - jcarballo
当你需要复制大量文本时,使用+寄存器不是更快吗? - pedromanoel
1
@pedromanoel 这只适用于本地工作。例如,如果您从本地复制了某些内容并想将其粘贴到位于SSH会话中的vim中,则无法访问vim。 - thomasrutter
1
@thomasrutter 但我将其映射到 <leader>p.. 非常有用! - Dane
显示剩余2条评论

83

虽然使用paste/nopaste/pastetoggle设置粘贴模式是完全可以的,但在粘贴之前仍需要手动启用粘贴模式,粘贴后再禁用粘贴模式。作为一个懒人,以下是我迄今为止找到的最佳解决方案,它会在你粘贴时自动切换粘贴模式。

Here's a little trick that uses terminal's bracketed paste mode to automatically set/unset Vim's paste mode when you paste. Put 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

Now you can paste without explicitly turning paste mode on/off - it is handled automatically for you.

来源: Coderwall

注意: 这个解决方案在WSL(Windows 10子系统Linux)中不适用。如果有人有WSL的解决方案,请更新此答案或在评论中添加。

Tmux 如果使用tmux,则需要双重转义声明。这段代码也在Coderwall中。


这很棒。不过有一件事...每次粘贴时,我都会在每个粘贴的开头得到一个“0”(零)字符。有什么提示吗? - Julius Š.
4
如果您够懒,并将上述代码复制粘贴到您的 .vimrc 文件中,请注意 XTermPasteBegin() 函数的缩进。 - k1133
3
我很好奇这是如何工作的,于是我搜索了“Paste Bracketing”,并找到了 https://gitlab.com/gnachman/iterm2/-/wikis/Paste-Bracketing,其中解释了`t_SI`和`t_EI`变量是如何启用和禁用“粘贴括号”的。当“粘贴括号”被打开时,粘贴的文本前缀为`esc[200~`,后缀为`esc[201~`。 - PatS
不幸的是,这种映射会延迟从插入模式切换到正常模式约半秒钟。有没有办法减少这种延迟? - Take
将此保存在我的~/.vimrc中后,我使用vi打开文件进行粘贴,但是我应该首先输入什么命令?我应该输入哪些qwerty键来输入该命令? ESC + [2004h会导致“不是编辑器命令”的结果。 - Wassadamo
显示剩余2条评论

40

苹果电脑用户可以通过直接从剪贴板读取来避免自动格式化:

:r !pbpaste

3
回答:这是一个很棒的回答。但是当我执行此操作时,它会隐藏文档(看起来好像我又回到了命令行界面),但文本已经复制到了剪贴板上。它会提示我按回车键,因此我就按了,然后回到我的文档,但没有任何更改。发生了什么事,我该如何按照你的指示进行操作? - jvriesem
如果您只键入“:.!pbpaste”,则应通过将当前行替换为粘贴缓冲区的输出来工作。一般来说,vim允许您将当前文件中的数据传输到另一个程序并用命令的输出替换文本。因此,“:1,3!pbpaste”将您文件的前三行替换为粘贴缓冲区。我使用“:.!ppjson”来获取非常长(未格式化的JSON字符串)并将其格式化,并用格式化的等效项替换长字符串。ppjson只是运行“python -m json.tool”的bash脚本。 - PatS
在Linux上,使用xsel --clipboard代替pbpaste可以实现相同的功能。 - Soren Bjornstad

20

这里有一个帖子,由某人找出了如何将粘贴事件重新映射为自动开启和关闭粘贴模式。在MacOSX上的tmux/iTerm中对我有效。


1
谢谢你的提示。我也找到了一个插件,其中该人已经捆绑了类似的功能- https://dev59.com/4nE85IYBdhLWcg3w_Ixr#36512548。 - studgeek
当我从剪贴板插入一段文本时,似乎会导致一连串的“eeeeeee”。 - John Jiang

20

我刚在我的 .vimrc 文件中添加了 set clipboard=unnamed。这会将默认的粘贴缓冲区映射到 X 的剪贴板。

因此,如果我在终端中标记一小段文本,我可以简单地按下 p 将其粘贴到 vim 中。同样,我可以在 vim 中复制东西(例如使用 YY 复制当前行到缓冲区),然后在任何窗口中使用鼠标中键粘贴它。

我认为这非常方便。


1
在我看来,这是最好的答案,无需切换F11键(vim默认预配置)。这适用于macOS系统,我不知道其他系统。 - LightMan

19

我是一名Python用户,有时会将内容复制粘贴到Vim中。(我从Mac切换到了Windows WSL),这是其中一个困扰我的故障之一。

如果您在script.py上进行了操作,然后执行vi script.py,Vi会检测到它是一个Python脚本并试图提供帮助,自动缩进、插入额外的缩进等。如果您没有告诉它这是一个Python脚本,它就不会发生。

但是,如果这已经在发生,那么当您粘贴已经完全缩进的代码时,默认的自动缩进可能会成为噩梦(如下所示的倾斜梯形)。

我尝试了三个选项,以下是结果

set paste        # works perfect 
set noai         # still introduced extra whitespace
set noautoindent # still introduced extra whitespace

输入图像描述 输入图像描述


同舟共济 - 你最终是设置了键盘快捷方式还是使用了插件或其他可行的选项?还是就这样忍受着呢 :) - aadibajpai
2
@aadibajpai 我在我的.vimrc文件中加入了set pastetoggle=<F2>,这样按下F2键就可以切换粘贴功能的开启和关闭。 - Stephen C

17

将以下内容添加到您的~/.vimrc文件中,然后在粘贴之前和之后仅需按下F2即可:

set pastetoggle=<F2>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接