Notes on OSC52

Table of Contents

OSC52 is a set of escape codes to tell the terminal emulator to do something.

For example, this tells the terminal emulator to put the string hello world into the system clipboard:

printf "\033]52;c;$(base64 <<< "Hello World")\007"

1. A shell function to set the clipboard

clip(){
    printf "\033]52;c;%s\007" "$(base64)"
}

which can be used by piping input into it.

Or a version that takes a string as an argument

clip(){
    printf "\033]52;c;%s\007" "$(printf "%s" "$1" | base64)"
}

Note that $(cmd) will strip a trailing newline from the output of cmd so x="$(echo "hello")" will create a variable that doesn't contain a newline even if the output of echo does contain a newline.

However, x=$(echo "hello" | base64), then the output of echo contains a newline, this newline gets base64 encoded. The base64 encoded newline does not get stripped by $(...).

So doing echo "hello" | clip will put a newline in your clipboard. So either use echo -n or printf or use the here-string form: clip <<< "hello".

2. How it works and background

The sequence is described in the XTerm Documentation. Although this is not a stadards document, many terminal emulators implement the codes described in this document.

C1 (8-Bit) Control Characters
=============================
The xterm program recognizes both 8-bit and 7-bit control characters.
It generates 7-bit controls (by default) or 8-bit if S8C1T is enabled.
The following pairs of 7-bit and 8-bit control characters are
equivalent:

ESC ]
     Operating System Command (OSC  is 0x9d).

Operating System Commands
=========================
OSC Ps ; Pt BEL

            Ps = 5 2  ⇒  Manipulate Selection Data.  These controls may
          be disabled using the allowWindowOps resource.  The parameter
          Pt is parsed as
               Pc ; Pd

          The first, Pc, may contain zero or more characters from the
          set c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 .  It is
          used to construct a list of selection parameters for
          clipboard, primary, secondary, select, or cut-buffers 0
          through 7 respectively, in the order given.  If the parameter
          is empty, xterm uses s 0 , to specify the configurable
          primary/clipboard selection and cut-buffer 0.

          The second parameter, Pd, gives the selection data.  Normally
          this is a string encoded in base64 (RFC-4648).  The data
          becomes the new selection, which is then available for pasting
          by other applications.

Where OSC is \033] and BEL is \007.

When the terminal emulator receives the byte \033, it doesn't draw that character nor the next ones on the screen until it reads a \007 byte.

What it does with the bytes it receives between those two is to read 52;c; as a string telling it what operating system command to do (52 is to set the system clipboard content, c specifies which clipboard if applicable), then read the rest of the bytes and base64 decode them and put the result in the system clipboard.

It doesn't matter if this is over SSH because it is the terminal emulator which is running locally that will process this sequence. Since it has access to the system clipboard, assuming it understands OSC52, it will set the system clipboard with the string that was provided.

Send copied text from terminal to system clipboard using OSC52.

3. TMUX

When copying text in TMUX's copy-mode, it uses OSC52 to set that text as the system clipboard. This is how a TMUX session running remotely can still set your local system clipboard.

For applications running inside TMUX who attempt to use OSC52, it is TMUX who receives the sequence. TMUX can do three things

  • Set its paste buffer to the string provided
  • Set its paste buffer and forward the OSC52 sequence to the terminal emulator thus setting the system clipboard.
  • Do nothing

This behavior is controlled with the set-clipboard option.

set -g set-clipboard on

With this setting activated, the printf command should also set the system clipboard even if run inside TMUX.

4. Integration with editors

Emacs can send a string directly to the terminal like so:

(send-string-to-terminal (concat "\033]52;c;"
                                 (base64-encode-string "Emacs has set my system clipboard")
                                 "\007"))

evaluating this block will put "Emacs has set my system clipboard"

The Emacs package Clipetty wraps the normal functions for killing text to also send the yanked text to the system clipboard using OSC52s

(use-package clipetty :ensure t
  :hook (after-init . global-clipetty-mode))

To get around the fact that TMUX's set-clipboard option may not be set to on, it does some more sophisticated things which require this option

set -ag update-environment "SSH_TTY"

to be set in ~/.tmux.conf.

5. Vim

vim-oscyank

https://github.com/ojroques/vim-oscyank?tab=readme-ov-file#terminal-support

This works by using something like this (evaluating this block from Terminal Emacs should put "clipetty OSC52" in the system clipboard if the terminal emulator supports it).

Note that in TMUX, the above code will only work if the option set-clipboard has the value on. However I think clipetty does stuff so that it works in TMUX no matter what.

The documentation shows that it has a bunch of things regarding TMUX and SSH sessions. For full support, this is needed in the TMUX configuration file.

Author: Philippe Carphin

Created: 2025-03-07 Fri 18:17

Validate