Skip to content

Commit dcb48e9

Browse files
committed
Added documentation for OSC 52 clipboard support
1 parent 6d8b740 commit dcb48e9

4 files changed

Lines changed: 194 additions & 0 deletions

File tree

content/docs/readline/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Think of it this way: Æsh is built **on top of** Æsh Readline. Æsh provides t
4949
- **[Device Attributes](device-attributes)** - DA1/DA2 terminal capability queries
5050
- **[Terminal Images](terminal-images)** - Sixel, Kitty, and iTerm2 inline image support
5151
- **[Hyperlinks](hyperlinks)** - Clickable OSC 8 hyperlinks in terminal output
52+
- **[Clipboard](clipboard)** - Automatic system clipboard integration via OSC 52
5253

5354
## Architecture
5455

content/docs/readline/clipboard.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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

content/docs/readline/connection.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,19 @@ Device device = connection.device();
582582
ImageProtocol protocol = device.getImageProtocol();
583583
```
584584

585+
## Clipboard (OSC 52)
586+
587+
Copy text to the system clipboard using OSC 52. This is a write-only operation. See [Clipboard](clipboard) for full documentation.
588+
589+
```java
590+
// Check support (heuristic, no query sent)
591+
if (connection.supportsClipboard()) {
592+
connection.writeClipboard("text to copy");
593+
}
594+
```
595+
596+
Clipboard writing is automatically managed by `Readline` for supporting terminals. Use the `ReadlineFlag.NO_CLIPBOARD` flag to opt out.
597+
585598
## Color Capabilities
586599

587600
Get terminal color information:

content/docs/readline/readline-api.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ Control readline behavior with flags:
191191
| Flag | Description |
192192
|------|-------------|
193193
| `NO_PROMPT_REDRAW_ON_INTR` | Don't redraw prompt after interrupt (Ctrl-C) |
194+
| `NO_SYNCHRONIZED_OUTPUT` | Disable automatic synchronized output (Mode 2026) |
195+
| `NO_GRAPHEME_CLUSTER_MODE` | Disable automatic grapheme cluster segmentation (Mode 2027) |
196+
| `NO_SHELL_INTEGRATION` | Disable OSC 133 shell integration sequences |
197+
| `NO_CLIPBOARD` | Disable automatic clipboard writes via OSC 52 |
194198

195199
```java
196200
EnumMap<ReadlineFlag, Integer> flags = new EnumMap<>(ReadlineFlag.class);

0 commit comments

Comments
 (0)