如何 "copy to clipboard" in vim of Bash on Windows?

How to "copy to clipboard" in vim of Bash on Windows?

我曾经使用 "+y 将文本复制到系统的剪贴板,但它在 Windows 上的 Bash 的 vim 中不起作用。

要从 Windows 10 的 Bash 中的 vim 中复制到剪贴板,请按住 Shift 并将光标拖到文本上。然后按 enter

在按下 enter 之前,选择应如下所示:

编辑:这只适用于同时适合屏幕的文本;它不能用于复制跨越许多 'screens'

的文本块

如果要使用WSL自带的vim,只能使用vim本身提供的剪贴板,也就是说只能在vim内复制粘贴。

或者,您可以尝试:

  1. 安装 VcXsrv 和 运行。
  2. export DISPLAY=localhost:0 在你的 WSL Bash.
  3. 运行 vim-gtk 或 vim-gnome(或任何其他 GUI 应用程序)并在 Linux 和 Windows 上尝试剪贴板。

因为“*y”和“+y (...) 都不起作用,替代方法如下:

将此添加到您的 .vimrc 并创建一个名为 ~/.vimbuffer

的文件
" copy (write) highlighted text to .vimbuffer
vmap <C-c> y:new ~/.vimbuffer<CR>VGp:x<CR> \| :!cat ~/.vimbuffer \| clip.exe <CR><CR>
" paste from buffer
map <C-v> :r ~/.vimbuffer<CR>

使用视觉或视觉块突出显示任何文本,然后按 ctrl-c。 使用通常的方法将复制的文本粘贴到终端外或 在正常或可视模式下使用 ctrl-v 将复制的文本粘贴到任何 vim 窗格。

Ctrl-c 抽取所选文本,用所选文本覆盖 ~/.vimbuffer,运行 UNIX 命令将数据从 ~/.vimbuffer 传输到 clip.exe.

非常感谢任何进一步的改进(例如:使命令静音)!

编辑: 命令现在可以复制任意长度的字符串,而不仅仅是整行。 旧命令:

vmap <C-c> :w! ~/.vimbuffer \| !cat ~/.vimbuffer \| clip.exe <CR><CR>

Edit2:下面的@Tropilio 在使用系统事件的评论中有一个更清晰的方法。我已经用了一年了。

如果您只关心复制完整的行,您可以使用 Vim 将文件内容通过管道传输到外部程序的功能。所以你可以做

:w !clip.exe

通过管道传输到 clip.exe。如果你需要特定的行,比如 2 到 10,你可以做

:2,10w !clip.exe

Piping buffer to external command in Vim

如果您不想设置 X 服务器,此方法将允许您使用 Windows 附带的 clip.exe 程序将所选文本复制到剪贴板。

下面的代码片段可以放在您的 .vimrc 文件中。

首先创建一个辅助函数,它将 return 当前选定的文本作为字符串。我们可以使用此函数将突出显示的文本通过管道传输到 clip.exe:

func! GetSelectedText()
    normal gv"xy
    let result = getreg("x")
    return result
endfunc

system 函数将允许我们调用本机程序并将参数传递给它们。下面的代码片段设置了两个键映射;第一行将允许 Ctrl+C 用于复制文本,第二行将允许 Ctrl +X 用于剪切文本:

noremap <C-C> :call system('clip.exe', GetSelectedText())<CR>
noremap <C-X> :call system('clip.exe', GetSelectedText())<CR>gvx

将更改保存到 .vimrc 文件后,您就可以开始了。

如果您打算在多个系统上使用 .vimrc,我建议将这些映射包装在 if 语句中以检查 clip.exe 是否确实存在:

if !has("clipboard") && executable("clip.exe")
    noremap <C-C> :call system('clip.exe', GetSelectedText())<CR>
    noremap <C-X> :call system('clip.exe', GetSelectedText())<CR>gvx
endif

如果可以直接访问系统剪贴板,以上内容还允许 Vim 忽略这些键绑定。

您可能还想在 vim 确实可以访问剪贴板时添加键绑定,如下所示:

if has("clipboard")
    vnoremap <C-X> "+x
    vnoremap <S-Del> "+x

    vnoremap <C-C> "+y
    vnoremap <C-Insert> "+y

    map <C-V>       "+gP
    map <S-Insert>      "+gP

    cmap <C-V>      <C-R>+
    cmap <S-Insert>     <C-R>+
endif

如果您在 Windows 上本地使用 Vim 或在 Linux 系统上使用 vim-gtk,这将派上用场。

结合以上信息,可以在不使用任何键绑定的情况下将简单文本从任何寄存器复制到剪贴板(在某些情况下会更方便)。例如,如果您要将最后一次抽出的文本复制到 windows 剪贴板,请输入以下命令(开始键入):

:call system('clip.exe', '

现在按Ctrl+r,然后是寄存器+。它将粘贴来自指定寄存器的文本。接下来,关闭单引号和括号。该命令将如下所示:

:call system('clip.exe', 'a text from 0 register')

回车,完成!

下面是映射

  • 在正常模式下 cycyycY(=Clipboard Yank)分别复制给定的文本对象、行、其余行光标位置到剪贴板,和
  • 在视觉模式下 Y 将视觉选择复制到剪贴板,

与是否在 WSL 中启动 Vim 无关。

nnoremap                    cy                   "+y
nnoremap                    <sid>(mgu)   m`_
onoremap                    <sid>(gu)        g_
nnoremap                    <sid>(ggg)   g``
nmap         <expr>     cyy                  '<sid>(mgu)cy' . v:count1 . '<sid>(gu)' . '<sid>(ggg)'
nmap                            cY                   cy<sid>(gu)

xnoremap Y  "+y

if has('unix') && executable('clip.exe')
    " From :help map-operator
    function! SendToClip(type, ...) abort
        if a:0
            " Visual mode
            normal! gv"+y
        elseif a:type ==# 'line'
            normal! '[V']"+y
        elseif a:type ==# 'char'
            normal! `[v`]"+y
        endif

        call system('clip.exe', @+)
    endfunction

    nnoremap <silent> cy            :set operatorfunc=SendToClip<cr>g@
    xnoremap <silent> Y             :<C-U>call SendToClip(visualmode(),1)<cr>
endif

所以有很多答案,甚至是像 this one on Super User, and this one on Vi and Vim 这样的跨网络问题,不幸的是我对其中任何一个都不满意,所以这里有一个不同的答案。

Neovim

如果我们使用 Neovim,那很简单。我们可以在 How to use the Windows clipboard from WSL 下关注他们的常见问题解答。本节的其余部分只是上下文。

通过设置 set clipboard=unnamedplus 就像我们在 X11 下的常规 Linux 系统上一样,我们告诉 Neovim 在拖拽和粘贴时使用系统寄存器作为我们的默认剪贴板。根据 Neovim 在 运行 的位置,它会选择一个合适的提供程序来与这些系统寄存器进行交互。对于 v0.4.3,可以在 provider#clipboard#Executable.

找到如何选择该提供商

虽然此解决方案需要安装外部二进制文件 win32yank.exe,但我个人对此非常满意,因为 clip.exepowershell.exe [Set|Get]-Clipboard 在用户体验方面都相形见绌。比如clip.exe只支持复制,没有解决粘贴问题。虽然 Powershell Get-Clipboard cmdlet 允许我们从 Windows 剪贴板粘贴到 Vim,但它会保留 Windows 行尾,所以粘贴后到处都是讨厌的^M。此外,它是一个超小的二进制文件,只需安装在我们的 WSL 发行版中; Windows 方面什么都没有。

curl -sLo /tmp/win32yank.zip https://github.com/equalsraf/win32yank/releases/download/v0.0.4/win32yank-x64.zip
unzip -p /tmp/win32yank.zip win32yank.exe > /tmp/win32yank.exe
chmod +x /tmp/win32yank.exe
sudo mv /tmp/win32yank.exe /usr/local/bin/

Vim

如果我们只是使用常规 Vim,我们仍然可以使用 win32yank.exe,但我们必须手动实现 Neovim 通常会为我们做的事情。即,以下内容:

set clipboard=unnamed

autocmd TextYankPost * call system('win32yank.exe -i --crlf', @")

function! Paste(mode)
    let @" = system('win32yank.exe -o --lf')
    return a:mode
endfunction

map <expr> p Paste('p')
map <expr> P Paste('P')

首先将剪贴板设置为默认寄存器 (@"),因为如果 Vim 是在没有剪贴板支持的情况下编译的,就像我的默认 Ubuntu WSL 一样,系统寄存器甚至可能无法启用发行版。复制使用 autocmd 将默认寄存器传递给 win32yank,粘贴拦截粘贴以将系统剪贴板分配给默认寄存器。

这行得通,但是如果我们每次都必须 shell 快速执行几次连续的拉取和粘贴,它会明显紧张。我们可以通过消除抖动来改善猛拉:

autocmd TextYankPost * call YankDebounced()

function! Yank(timer)
    call system('win32yank.exe -i --crlf', @")
    redraw!
endfunction

let g:yank_debounce_time_ms = 500
let g:yank_debounce_timer_id = -1

function! YankDebounced()
    let l:now = localtime()
    call timer_stop(g:yank_debounce_timer_id)
    let g:yank_debounce_timer_id = timer_start(g:yank_debounce_time_ms, 'Yank')
endfunction

但这需要 Vim 8,如果您必须升级,我建议您改用 Neovim。尝试实施适当的缓存和去抖动将是一件令人头疼的事情!

vmap <silent> <leader>y :w !clip.exe<CR><CR>
"---------------------- :w !clip.exe
" The core command, thanks to Mitchell's answer.
"---------------------------------- <CR><CR>
" The first <CR> closes the command;
" the second <CR> suppresses "Press ENTER or type command to continue".
"--- :h map-silent
" This fix the flicker caused by external commands and <CR><CR>.
"------------ :h leader
" `:echo mapleader` to view your leader key.

站在巨人的肩膀上,我现在正在使用上面的解决方案。

将以下内容添加到 .vimrc

autocmd TextYankPost * if v:event.operator ==# 'y' | call system('/mnt/c/Windows/System32/clip.exe', @0) | endif

为方便起见,如果需要,您可以通过ctrl + c

添加复制
vmap <C-c> y

对我有用的是:

按住 Shift 键并使用鼠标选择您要复制的文本。然后转到主机上的任何文本编辑器并粘贴;您选择的文字应该在那里。