Recently, a friend asked how to copy the contents of vim on the server to the local clipboard without using the mouse. To be honest, I always select and copy directly with the mouse. But since my friend asked, I had to do some research. I really found a solution that doesn’t use the mouse. This method can not only copy the contents of vim to the local clipboard, but also to the local tmux clipboard, very convenient. Today, I’ll share it with you.
I introduced command line escape characters (ANSI Escape Sequences) in Colorful Terminal. Escape characters start with 0x1b
and are followed by a byte with a value in the range @A-Z[\]^_
, with different letters indicating different meanings. The one I introduced in the previous article is 0x1b[
, called Control Sequence Introducer, abbreviated as CSI
. With CSI
you can display bold, italic, and underline characters at the command line, as well as different colors, and even simple animations. To copy content today, you need to use 0xeb]
, called Operating System Command, abbreviated OSC
. The complete OSC
command is as follows.
OSC | Description | Status | Format |
---|---|---|---|
0 | Set window title | Only window title | ESC ] 0 ; [title] \a |
2 | Set window title | Converted to 0 | |
4 | Set/read color palette | Supported | ESC ] 4 ; index1;rgb1;…;indexN;rgbN \a |
9 | iTerm2 notifications | Supported | ESC ] 9 ; [message] \a |
10 | Set foreground color | Supported | ESC ] 10 ; [X11 color spec] \a |
11 | Set background color | Supported | ESC ] 11 ; [X11 color spec] \a |
50 | Set the cursor shape | Supported | ESC ] 50 ; CursorShape=[0 |
52 | Clipboard operations | Only “c” | ESC ] 52 ; c ; [base64 data] \a |
777 | urxvt modules | Only “notify” | ESC ] 777 ; notify ; [title] ; [body] \a |
One of the copy commands looks like this.
|
|
It starts with OSC
, which is 0x1b[
, followed by a semicolon; then the number 52
, which indicates the operation of the clipboard; then a semicolon connected to a letter c
, which indicates copying (currently the only one), followed by a semicolon; then the content being copied, which needs to be converted to base64 encoding; and finally the ringing symbol (bel). The copy feature requires terminal software support . That is, if the terminal software supports it, when it receives the 0x1b[52;c;aGVsbG8=\a
character, it will not display it directly on the terminal, but will copy the hello
to the system clipboard.
Not all terminal emulators support the copy command (OSC52), and I found a list of supported ones from the web at
Terminal | OSC52 support |
---|---|
Alacritty | yes |
GNOME Terminal (and other VTE-based terminals) | not yet |
hterm (Chromebook) | yes |
iTerm2 | yes |
kitty | yes |
screen | yes |
tmux | yes |
Windows Terminal | yes |
rxvt | yes (to be confirmed) |
urxvt | yes (with a script, see here) |
foot | yes |
wezterm | yes |
I’m using iTerm2, and it’s not supported by default. You need to check Applications in terminal may access clipboard under Preferences -> General -> Selection. After opening, execute the following command.
|
|
Then you can paste hello
by pressing the system’s paste shortcut ⌘ + v
.
So how can I combine the OSC52 command with vim? I looked up vim-oscyank from this article). Because of the need to support windows platform and neovim, oscyank is rather complicated. But the core of oscyank is also the OSC52 command. If you don’t want to tinker with it, you can just use this plugin, but it is perfectly possible to implement a simpler version ourselves.
First we need to get the copied contents of vim, which can be done with the event TextYankPost
. We can add this line to vimrc.
|
|
When we copy or delete content in vim we see the following output.
|
|
The copied content can be extracted by the key regcontents
. This is a list, with each element corresponding to one line of content. The next step is to convert the copied content into OSC52 commands to be sent to the terminal software, and the code is simple.
Here we first change autocmd
to call the Copy
function we wrote. Note that v:event
is a global variable that can be accessed directly in Copy
. Then use \n
to concatenate the contents to be copied, and then use system
to call the system base64
command to finish the encoding (you can also use plain viml to implement the base64 function, it’s too complicated). Finally, splice the OSC52 command. Here \e
is 0xeb
and \x07
is \a
. Finally, send the instruction to the terminal via charsend
. The terminal will write the copied content to the system clipboard when it receives it.
charsend
seems to be a neovim-specific command, but to support vim, you need the following code (from oscyank 😇).
Wait, after all that, does this replication have anything to do with ssh? What about copying content from remote vim to local via ssh?
Actually, that’s already been said. Because ssh sends all the output of the remote vim (including the OSC52 command) to the local terminal for processing. As long as the local terminal supports the OSC52 command, it will copy the corresponding content to the local system clipboard 💯
One final note on using tmux. As soon as tmux is turned on, whether on the local or remote machine, the replication feature mentioned earlier will be disabled. I’ve looked up a lot of information on the web and it says that in addition to setting set -g set-clipboard on
, you have to update the Ms
configuration via terminal-overrides
. Maybe it’s a tmux version problem, but I’ve experimented with the latest tmux and found that I only need to add set -g set-clipboard on
. There is no problem to start tmux locally or remotely, or both. Another benefit of having set-clipboard
turned on is that you can use the clipboard with vim and tmux. In other words, you can use the tmux shortcut to paste what you copied in vim, which is very delicious!
That’s all there is to this article. To summarize, you can copy by sending OSC52 commands to the terminal emulation software. This way you can cross ssh sessions and achieve the effect of remote copying. This way you can also interoperate the clipboard between vim and tmux, which is very convenient. However, while convenient, this solution essentially uses command-line escape sequences and relies on terminal emulation software. If you are interested, it is also recommended to play with other OSC commands (for example, OSC9 can control iTerm2 to send system notifications, etc.).