Linux 剪貼簿・終階
我用 Linux 好多年,依然沒真正理清 Linux 下剪貼簿的用法,因為很多程式的複製貼上行為都不一樣,何況X還有兩種剪貼簿,再加上我經常跨機編輯,即 termite+ssh+tmux+neovim,這麼多程式疊加在一起,就一直不知道到底怎麼複製貼上好。這不,今天我要在遠端主機 yy 上通過 NeoVim 選中裡面的內容,複製到另一個遠端主機 103 的 NeoVim 上,亂按快捷鍵一通也沒解決。於是終於徹底下定決心搞清 Linux 以及眾多程式的剪貼簿原理,在此整理並歸檔研究結論。
原理
-
ofollow,noindex">https://wiki.archlinux.org/index.php/Clipboard
按這兩篇的說法,所謂兩種剪貼簿 Clipboard 和 Primary selection 都是X的功能。區別是前者用 Windows 那樣的複製貼上鍵 ctrl+c/ctrl+v
,後者只需選中內容,就可以在別的地方用滑鼠中鍵貼上。還有 shift+insert
能起到 ctrl+v
的作用,但這鍵太冷門了就不記了。
此外其實這兩個剪貼簿都是非同步的——只有在貼上時,才會真正觸發複製!我實踐發現,哪怕在 Gedit 主動用 ctrl+c
複製後,關掉 Gedit,在 Google Chrome 的位址列就貼上不出來任何東西了。 於是 ArchWiki 建議改用剪貼簿管理器來解決。此外為了措辭上的方便,下文假設複製貼上是同步的,比如「複製東西進剪貼簿」。
選中也不一定可以複製,除了依雲提到的,我還發現 Google Chrome 按 alt+d
選中位址列的 URL,不能複製;但滑鼠雙擊位址列全選,能複製。
簡化原則
為了解決如此複雜的剪貼簿問題,我需要設定一些簡化原則,減輕記憶負擔。
-
只用 clipboard!從此以後就當 Linux 只存在一種剪貼簿。自然不用記住選中卻無法複製的例外情況了。primary,不存在。
-
儘可能地讓所有程式的複製貼上鍵接近 vim-binding。
程式
開始整理並歸檔御用程式如何使用剪貼簿的解決方案。
御用剪貼簿互動命令・ xclip
除了用程式本身的複製貼上鍵、滑鼠選中複製與中鍵貼上行為,其實也有現成的命令,能在 Shell 裡與X剪貼簿互動。最常見的有兩個命令: ‘xclip’ vs. ‘xsel’
由於 xsel 已經兩年沒更新了,而且 GitHub 官方幫助又欽定 xclip,再加上 xclip 比 xsel 順耳許多了。我決定 xclip 作為御用剪貼簿互動命令。
xclip 預設複製進 primary,坑。
御用虛擬終端・ Terminate
https://wiki.archlinux.org/index.php/Termite
Termite 像 Vim,有兩種模式:Insert 和 Selection。
Insert 模式下,可以直接用滑鼠選中內容,但它的行為和 Vim 不一樣:仍然處於 Insert 模式!使用者可以一邊選中內容,一邊輸入內容。由於虛擬終端和 Shell 緊密相關,不能直接用 ctrl+c/ctrl+v
,只能用 ctrl+shift+c/ctrl+shift+v
代替複製貼上。
按 ctrl+shift+space
可以進入 selection 模式,行為和 Vim 一樣,不贅述。
複製會複製到X剪貼簿,我測試了下發現包括 clipboard.
由於我習慣用 Tmux,Termite 的複製貼上功能其實不重要,無需記憶。不過,我發現 Termite 的 ctrl+shift+v
在 Tmux 一樣有效 !
御用網路傳輸協議・ SSH
既然剪貼簿由X負責,那麼我們需要 SSH 能夠轉發遠端主機上的X程式到本地上,從而讓遠端主機能與本地的剪貼簿互動。信任遠端主機的話, alias ssh='ssh -Y'
即可。
實踐證明,我 SSH 到遠端主機並開啟 Tmux 後, 我可以把 clipboard 的東西通過 Termite 的 ctrl+shifht+v
貼上進該 Tmux Session 的某 pane 裡。
御用終端多路複用器・ Tmux
由於 Termite 的複製貼上直接作用於整個虛擬終端的介面上,不分 Tmux 裡的 pane,於是需要掌握 Tmux 下能在 pane 複製貼上行為。
Tmux 也有兩種模式。一是常規模式,即使用者在 pane 裡的行為和單個虛擬終端一樣;另一是 copy-mode,為能夠在 pane 下滾動歷史或複製而服務,其又有兩種 binding,一是 Emacs 另一是 Vim,預設用 Emacs binding。
我習慣 vim-like 步驟與行為,自然要重新設定為 Vim Binding: set-window-option -g mode-keys vi
。
此外 Tmux 2.4 有重新定義 Key Binding 語法,本文不考慮 Tmux 2.4 之前的舊 Key Binding 語法。
Tmux 原本進入 copy-mode 的預設 key binding 為 prefix+[
,太蠢,為保持與 Vim Binding 一致,可以直接修改: bind-key Escape copy-mode # enter copy mode (prefix Escape)
,模仿在 Vim 從 Insert 模式退出,進入 Normal 模式的行為。
再繼續改造 key bindings:
bind-key -T copy-mode-vi 'v' send-keys -X begin-selection bind-key -T copy-mode-vi 'V' send-keys -X select-line bind-key -T copy-mode-vi 'r' send-keys -X rectangle-toggle bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel "xclip -in -selection clipboard"
需要注意的是 Tmux copy mode 不支援 Vim Visual 模式 ctrl+v
那樣的 block selection,但是可以通過 r
改變 v
的 selection 行為,即從跨行 selection 和 block selection 之間轉換。 y
則是貼上進 clipboard 了。
更進一步地像 Vim 那樣能滾動瀏覽 pane 的歷史:
# scroll like vim bind-key -T copy-mode-vi f send-keys page-down bind-key -T copy-mode-vi b send-keys page-up bind-key -T copy-mode-vi d send-keys halfpage-down bind-key -T copy-mode-vi u send-keys halfpage-up
其實本來還可以加 bind-key p run "xclip -o -sel clip | tmux load-buffer - ; tmux paste-buffer"
,不過還是 ctrl+shift+v
貼上更方便,就不加了。
御用文字編輯器・ NeoVim
Vim 要有開啟 clipboard 編譯選項,才支援剪貼簿(大概)。據說 Arch Linux 的 vim 就沒開啟!只能改裝 gvim 包了。
好在 NeoVim 支援,但需要額外的依賴, help clipboard
指出:
The presence of a working clipboard tool implicitly enables the '+' and '*' registers. Nvim looks for these clipboard tools, in order of priority: - |g:clipboard| - pbcopy/pbpaste (macOS) - xsel (if $DISPLAY is set) - xclip (if $DISPLAY is set) - lemonade (for SSH) https://github.com/pocke/lemonade - doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/ - win32yank (Windows) - tmux (if $TMUX is set)
顯然裝 xclip 就行了。
Vim 預設 VISUAL 選中內容不會複製進 primary,這樣正好,畢竟 Vim 重在編輯。可以通過 shift+"+y
複製進 clipboard。
至於到底怎麼複製貼上,看 How to make vim paste from (and copy to) system’s clipboard? 就夠了。
最後,如何在 SSH 到遠端主機再 Tmux 後再開 NeoVim,如何複製貼上到本地?簡單, ssh -Y
,本地和遠端主機都裝 xclip,跟平常一樣複製貼上。