|
| 1 | +--- |
| 2 | +date: '2026-03-13T15:00:00+01:00' |
| 3 | +draft: false |
| 4 | +title: 'Clipboard' |
| 5 | +weight: 15 |
| 6 | +--- |
| 7 | + |
| 8 | +Æsh Readline can automatically copy killed and yanked text to the system clipboard using the OSC 52 escape sequence. When enabled, any text that enters the internal kill ring (via Ctrl+K, Ctrl+W, vi `dd`, `yy`, etc.) is also written to the system clipboard, allowing you to paste it into other applications. |
| 9 | + |
| 10 | +This is a **write-only** operation — Æsh never reads from the clipboard, so there are no security concerns about exposing clipboard contents. |
| 11 | + |
| 12 | +## How It Works |
| 13 | + |
| 14 | +OSC 52 sends Base64-encoded text to the terminal, which places it on the system clipboard: |
| 15 | + |
| 16 | +| Sequence | Purpose | |
| 17 | +|----------|---------| |
| 18 | +| `ESC ] 52 ; c ; <base64> ST` | Copy text to the system clipboard | |
| 19 | + |
| 20 | +The `c` parameter selects the clipboard buffer (as opposed to the primary selection). The String Terminator (ST) can be either `ESC \` or `BEL` (`\u0007`). Æsh uses `ESC \`. |
| 21 | + |
| 22 | +On terminals that don't recognize OSC 52, the sequence is silently ignored — no visible output or errors. |
| 23 | + |
| 24 | +## Quick Start |
| 25 | + |
| 26 | +Clipboard writing is **automatic** when using the `Readline` class. If the terminal supports OSC 52, all kill/copy actions write to the system clipboard with no application code needed: |
| 27 | + |
| 28 | +```java |
| 29 | +Readline readline = new Readline(); |
| 30 | + |
| 31 | +// Clipboard integration is enabled automatically for supporting terminals. |
| 32 | +// When the user presses Ctrl+K, Ctrl+W, etc., text goes to both |
| 33 | +// the internal kill ring AND the system clipboard. |
| 34 | +readline.readline(connection, new Prompt("$ "), input -> { |
| 35 | + // handle input |
| 36 | +}); |
| 37 | +``` |
| 38 | + |
| 39 | +## Terminal Support |
| 40 | + |
| 41 | +| Terminal | Supported | |
| 42 | +|----------|-----------| |
| 43 | +| iTerm2 | Yes | |
| 44 | +| Kitty | Yes | |
| 45 | +| Ghostty | Yes | |
| 46 | +| WezTerm | Yes | |
| 47 | +| foot | Yes | |
| 48 | +| Contour | Yes | |
| 49 | +| Rio | Yes | |
| 50 | +| Warp | Yes | |
| 51 | +| Mintty | Yes | |
| 52 | +| xterm | Yes (if `allowWindowOps` is enabled) | |
| 53 | +| GNOME Terminal | Yes | |
| 54 | +| Konsole | Yes | |
| 55 | +| VS Code | Yes | |
| 56 | +| Tabby | Yes | |
| 57 | +| Hyper | Yes | |
| 58 | +| Windows Terminal | No | |
| 59 | +| Alacritty | No | |
| 60 | +| Apple Terminal | No | |
| 61 | +| ConEmu | No | |
| 62 | +| Linux Console | No | |
| 63 | + |
| 64 | +On unsupported terminals the OSC 52 sequence is never sent — the `supportsClipboard()` check prevents it. |
| 65 | + |
| 66 | +## Connection API |
| 67 | + |
| 68 | +The `Connection` interface provides methods for clipboard access: |
| 69 | + |
| 70 | +### Checking Support |
| 71 | + |
| 72 | +```java |
| 73 | +// Heuristic check based on terminal type detection |
| 74 | +boolean supported = connection.supportsClipboard(); |
| 75 | +``` |
| 76 | + |
| 77 | +This uses environment-based terminal detection via `TerminalEnvironment` and the `Device.TerminalType` enum. No terminal query is sent. |
| 78 | + |
| 79 | +### Writing to the Clipboard |
| 80 | + |
| 81 | +```java |
| 82 | +// Copy text to the system clipboard |
| 83 | +connection.writeClipboard("Hello, clipboard!"); |
| 84 | +``` |
| 85 | + |
| 86 | +The method is a no-op if the text is null/empty or the terminal doesn't support OSC 52. It returns the `Connection` for chaining: |
| 87 | + |
| 88 | +```java |
| 89 | +connection |
| 90 | + .writeClipboard("copied text") |
| 91 | + .write("Text copied to clipboard!\n"); |
| 92 | +``` |
| 93 | + |
| 94 | +## ANSI Utility Methods |
| 95 | + |
| 96 | +The `ANSI` class provides a static method for building the OSC 52 escape sequence directly: |
| 97 | + |
| 98 | +```java |
| 99 | +import org.aesh.terminal.utils.ANSI; |
| 100 | + |
| 101 | +// Build an OSC 52 sequence |
| 102 | +String seq = ANSI.buildOsc52Write("text to copy"); |
| 103 | +// Result: ESC ] 52 ; c ; dGV4dCB0byBjb3B5 ESC \ |
| 104 | + |
| 105 | +// Write it manually |
| 106 | +connection.write(seq); |
| 107 | +``` |
| 108 | + |
| 109 | +### Constants |
| 110 | + |
| 111 | +| Constant | Value | Description | |
| 112 | +|----------|-------|-------------| |
| 113 | +| `ANSI.OSC_CLIPBOARD` | `52` | OSC code for clipboard access | |
| 114 | + |
| 115 | +## Automatic Readline Integration |
| 116 | + |
| 117 | +When using the `Readline` class, clipboard writing is handled automatically through the `PasteManager`. Every call to `PasteManager.addText()` — which all kill/copy actions use — triggers a clipboard write if OSC 52 is supported. |
| 118 | + |
| 119 | +Actions that write to the clipboard: |
| 120 | + |
| 121 | +| Action | Key (Emacs) | Key (Vi) | |
| 122 | +|--------|------------|----------| |
| 123 | +| Kill to end of line | `Ctrl+K` | `D` (command mode) | |
| 124 | +| Kill to start of line | `Ctrl+U` | — | |
| 125 | +| Kill word backward | `Ctrl+W` | — | |
| 126 | +| Kill word (Unix filename rubout) | — | — | |
| 127 | +| Delete character | `Ctrl+D` | `x` | |
| 128 | +| Delete previous character | `Backspace` | `X` | |
| 129 | +| Copy line | — | `yy` | |
| 130 | +| Change action | — | `c` + motion | |
| 131 | + |
| 132 | +### Opting Out |
| 133 | + |
| 134 | +To disable automatic clipboard writing, set the `NO_CLIPBOARD` flag: |
| 135 | + |
| 136 | +```java |
| 137 | +import org.aesh.readline.ReadlineFlag; |
| 138 | + |
| 139 | +EnumMap<ReadlineFlag, Integer> flags = new EnumMap<>(ReadlineFlag.class); |
| 140 | +flags.put(ReadlineFlag.NO_CLIPBOARD, 0); |
| 141 | + |
| 142 | +readline.readline(connection, new Prompt("$ "), input -> { |
| 143 | + // handle input |
| 144 | +}, null, null, null, null, flags); |
| 145 | +``` |
| 146 | + |
| 147 | +## Manual Usage |
| 148 | + |
| 149 | +For applications that manage their own rendering (outside of `Readline`), use the `Connection` method directly: |
| 150 | + |
| 151 | +```java |
| 152 | +// Copy selected text to the system clipboard |
| 153 | +if (connection.supportsClipboard()) { |
| 154 | + connection.writeClipboard(selectedText); |
| 155 | +} |
| 156 | +``` |
| 157 | + |
| 158 | +Or build the sequence manually with the `ANSI` utility: |
| 159 | + |
| 160 | +```java |
| 161 | +String osc52 = ANSI.buildOsc52Write(selectedText); |
| 162 | +connection.write(osc52); |
| 163 | +``` |
| 164 | + |
| 165 | +## Specification |
| 166 | + |
| 167 | +The OSC 52 protocol is documented in the xterm control sequences specification: |
| 168 | + |
| 169 | +[XTerm Control Sequences — Operating System Commands](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands) |
| 170 | + |
| 171 | +## See Also |
| 172 | + |
| 173 | +- [Connection](connection) — Full `Connection` API reference |
| 174 | +- [Readline API](readline-api) — ReadlineFlag and core API reference |
| 175 | +- [Terminal Environment](terminal-environment) — Terminal type detection |
| 176 | +- [Hyperlinks](hyperlinks) — OSC 8 clickable links |
0 commit comments