我曾经使用"+y
来复制文本到系统剪切板,但在Bash on Windows的vim中无法使用。
我曾经使用"+y
来复制文本到系统剪切板,但在Bash on Windows的vim中无法使用。
既不能使用 "*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>
编辑2: @Tropilio在下面的评论区提出了一种更简洁的方法,使用系统事件。我已经使用这种方法一年了。
:|
(冒号和竖杠字符),并且没有将内容复制到Windows剪贴板中。当.vimbuffer
中有内容时,我在vim中输入 :!cat ~/.vimbuffer \| clip.exe <cr>
,会出现以下错误:cat: '|' : no such file or directory
和 cat: clip.exe: No such file or directory
。 - user1135541:!cat ~/.vimbuffer | clip.exe <cr>
- 您不必从vim中转义|字符(使用\),只需在.vimrc文件中转义。如果仍然无法工作,请告诉我。 - davidanderle<C-c>
命令时,屏幕会闪烁几次... - Tropilioautocmd TextYankPost * call system('echo '.shellescape(join(v:event.regcontents, "\<CR>")).' | clip.exe')
这不会引起任何闪烁或延迟。 - Tropiliovim-gnome
而不是仅仅的vim
。 - ifconfig因此,即使是跨网络的问题(如Super User上的这个问题和Vi and Vim上的这个问题),都有很多答案。不幸的是,我对它们都不满意,所以来了一个不同的答案。
如果我们使用Neovim,那很容易解决。我们可以按照他们在如何从WSL使用Windows剪贴板的FAQ中的说明进行设置。本节其余内容仅为背景信息。
通过设置set clipboard=unnamedplus
,就好像我们在X11下的普通Linux系统一样,我们告诉Neovim在拷贝和粘贴时使用系统寄存器作为默认剪贴板。根据Neovim运行的位置,它选择适当的提供程序与这些系统寄存器交互。对于v0.4.3版本,如何选择提供程序可以在provider#clipboard#Executable找到。
虽然这个解决方案需要安装一个外部二进制文件win32yank.exe
,但我个人对它非常满意,因为与之相比,clip.exe
和powershell.exe [Set|Get]-Clipboard
在用户体验上都不如它。例如,clip.exe
只支持复制,但无法解决粘贴问题。而虽然Powershell的Get-Clipboard
命令允许我们从Windows剪贴板中粘贴到Vim中,但它会保留Windows的换行符,因此在粘贴后到处都是讨厌的^M
。另外,它是一个超小型的二进制文件,只需在我们的WSL distro中安装即可,不需要在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,我们仍然可以使用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')
首先将剪贴板设置为默认寄存器(@"
),因为如果像我的Ubuntu WSL发行版一样,Vim没有编译剪贴板支持,则系统寄存器可能甚至未启用。复制使用自动命令将默认寄存器传递给win32yank
,并且粘贴拦截粘贴操作以将系统剪贴板分配给默认寄存器。
这个方法是有效的,但在快速执行多个连续的复制和粘贴时会明显地出现抖动,因为我们每次都要运行一个外部程序。我们可以通过去抖动来改进复制:
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。尝试实现适当的缓存和去抖动会很麻烦!
mv /tmp/win32yank.exe ~/bin
将 .exe 重命名为 bin
并将其放置在 ~
中。您确定不是指 mv /tmp/win32yank.exe /usr/local/bin/win32yank.exe
(适用于 Ubuntu)吗? - run_the_racep
/P
命令将剪贴板内容读入寄存器。这意味着在使用这两个命令之前,您不能直接访问寄存器。特别是,i<C-R>"
不会立即起作用。这也改变了 xp
的行为方式,使其成为就地操作。 - mkjeldsenclip.exe
程序将所选文本复制到剪贴板中。以下代码片段可放置在您的.vimrc
文件中。首先创建一个助手函数,它将返回当前选择的文本作为字符串。我们可以使用此函数将突出显示的文本导入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
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
vim-gtk
,这将非常有用。:2,10w !clip.exe
.vimrc
文件中:autocmd TextYankPost * if v:event.operator ==# 'y' | call system('/mnt/c/Windows/System32/clip.exe', @0) | endif
为方便起见,如果需要,您可以通过ctrl + c
进行复制。
vmap <C-c> y
如果您想使用WSL中捆绑的vim,那么您只能使用vim本身提供的剪贴板,这意味着您只能在vim内部复制和粘贴。
或者,您可以尝试以下方法:
export DISPLAY=localhost:0
。结合上述信息,可以在不使用任何键绑定的情况下从任何寄存器复制简单文本到剪贴板(在某些情况下可能更方便)。例如,如果您想将最后一次复制的文本复制到Windows剪贴板中,请输入以下命令(开始输入):
:call system('clip.exe', '
:call system('clip.exe', 'a text from 0 register')
按下 Enter,完成!
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.
cy
、cyy
和 cY
(=剪贴板复制)分别将给定的文本对象、行、光标位置到行尾的剩余部分复制到剪贴板中,Y
将所选内容复制到剪贴板中,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
"*
寄存器对于 vim 来说非常有用。例如,要复制当前行:"*yy
(然后按 Ctrl-V 粘贴到你的浏览器 URL 字段中)。或者反过来:(例如,在复制了一个 URL 后),将其粘贴到当前的 vim 文件中:"*p
。 - Ralphvim
是一个主要由程序员使用的软件工具。它是因为这个问题与Windows有关吗? - Cornelius Roemer