从剪贴板粘贴并自动切换“:set paste”

19

当我从剪贴板粘贴东西时,它们通常(总是)有多行,在这种情况下(也仅在这种情况下),我希望触发 :set paste,否则制表符将随每一行增加而增加(大家都看到了!)。

但是,使用 :set paste 的问题在于它与 set smartindent 行为不兼容,导致光标跳转到新行的开头而不是正确的缩进位置。所以我只想在这种情况下启用它。

我使用 Mac,在 Vim 上通过 SSH 连接到 Debian 机器,因此使用 cmd + v 在插入模式下进行粘贴。


1
我认为没有理由迁移这个问题:不仅vim问题被接受为属于SO(http://meta.stackexchange.com/questions/25925/vim-questions-so-or-su),而且这是一个关于程序员文本编辑器的问题,用于执行编程时常见的任务。 - Cascabel
1
@Jefromi:在进行任何形式的文本编辑时,粘贴是很常见的,但我会承认即使与编程无关,Vim/Emacs问题也被认为是SO可以接受的。@Jonatan:我强烈建议不要使用“smartindent”。请参阅http://vim.wikia.com/wiki/Restoring_indent_after_typing_hash#Using_filetype_indentation以了解原因。 - jamessan
@jamessan:重点是,使用这种特定的格式粘贴是一项非常常见的编程任务。在其他任何地方,都不会经常粘贴缩进变化的文本块。 - Cascabel
5个回答

7

我不使用Mac电脑,但我相信这里的前缀是正确的:<D-v>应该表示cmd-v。对于插入模式:

:imap <D-v> ^O:set paste<Enter>^R+^O:set nopaste<Enter>

或者,只需这样做:
:imap <D-V> ^O"+p

^O和^R是文字形式的控制-O和控制-R,输入时可以使用^V^O(控制-V控制-O)和^V^R(控制-V控制-R)。在插入模式下,控制-O允许您执行一个命令,然后返回插入模式;在此,您可以使用它从剪贴板寄存器中粘贴内容。我测试过将其映射到不同的键后可以正常工作,所以您应该没有问题。当不在插入模式下时,无需映射任何内容;您只需使用 "+p即可。

关于 "+p ... 根据您的操作系统,您可能需要将其更改为 "*p。对于我的电脑(osx),我需要使用第二个版本。 - agbodike

3

我在我的 .vimrc 文件中有以下内容:

inoremap <S-Insert> <ESC>:setl paste<CR>gi<C-R>+<ESC>:setl nopaste<CR>gi

gi是在当前缓冲区中,以上次停止插入模式的位置开始插入模式。

更新:

Jefromi发布了一个更好的解决方案。我稍微调整了一下。

inoremap <S-Insert> <ESC>"+p`]a

它可以插入剪贴板文本,并将光标放置在其后面。

很好,但那只在Shift-Insert上有效,对吧?而且除非我搞错了,否则在我的Mac上是行不通的。 - Jonatan Littke
它可以轻松地映射到您喜欢的任何按键上,例如<F5>。 - Maxim Kim
@Jonatan Littke:我的回答展示了如何将此映射为command-v,并且如何更高效地完成它。 - Cascabel

1

你说得对,只有在需要时才应启用'paste'。它不仅影响缩进,还会影响其他方面。你可以在文档中了解到它所影响的所有内容。一个相关的选项,非常有用,可以方便地使用'paste',那就是'pastetoggle'

如果你正在使用X-forwarding和一个可以正确通信鼠标操作的终端,你也可以利用'mouse'选项。通过:set mouse=a,Vim会意识到鼠标正在做什么,因此当它通过中键鼠标单击接收到多行粘贴时,不会执行自动缩进。

即使没有鼠标功能,X-forwarding也可以帮助,因为当手动从剪贴板或选择寄存器(分别为"+"*)粘贴时,Vim会执行相同的操作。


我曾经寻求帮助,想让X-forwarding和鼠标等功能正常工作(http://superuser.com/questions/98350/vim-and-mouse-with-ssh-from-mac-to-linux),但是从未完全解决。我会研究pastetoggle,这应该可以解决问题。Vim的文档(和功能集)真的非常庞大。 - Jonatan Littke

0

这个问题可以通过Vim脚本来解决。(我讨厌Vim脚本,所以必须是一个更严重的问题才能让我自己解决它。)即使使用iTerm2的“缓慢粘贴”模式,默认情况下也会将要粘贴的数据分成16字节块,并每0.125秒发送一个块。因此,您应该能够以编程方式检测到一个16字节的“按键”块并对其进行处理。

伪代码如下:

if too_fast_too_be_human():
    set('pastemode', True)
else
    set('pastemode', False)

# where either
def too_fast_too_be_human
    char_threshold = 16
    return len(input_buffer) > char_threshold

# or
def too_fast_too_be_human
    static byte_times = []
    char_threshold = 16
    time_threshold = 0.125
    byte_times.append(now())
    while(len(byte_times) > char_threshold):
        byte_times.unshift()
    return (byte_times[-1] - byte_times[0]) < time_threshold

这种方法存在一些弱点,但对于大多数情况来说是可行的。


0

我们可以使用插入模式进行粘贴,而不会弄乱缩进。

Ctrl-r Ctrl-o Register
Ctrl-r Ctrl-o +
Ctrl-r Ctrl-o *
Ctrl-r Ctrl-o 0

CTRL-R CTRL-O {0-9a-z"%#*+/:.-=}            *i_CTRL-R_CTRL-O*
Insert the contents of a register literally and don't
auto-indent.  Does the same as pasting with the mouse
"MiddleMouse". When the register is linewise this will
insert the text above the current line, like with `P`.
Does not replace characters!
The '.' register (last inserted text) is still inserted as
typed.

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