diff --git a/.gitignore b/.gitignore
index f1bd836..ea63c1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,6 @@ dev.termherd.lock
# Per-directory tool caches the impeccable skill drops beside the sources it
# reads; they reappear on every run, so ignore rather than clean repeatedly.
.impeccable/
+
+# Serena MCP tool state (local)
+.serena/
diff --git a/AGENTS.md b/AGENTS.md
index 997e738..12d5d3e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -149,17 +149,17 @@ into its `mcpServers` at spawn (loopback, per-session token) — so it can read
and drive the workspace it runs in. This is the richer sibling of the capture
dump above: same `WorkspaceSnapshot` model, live instead of a file.
-**Settled.** Sixteen tools: `list_sessions` + `snapshot`
+**Settled.** Seventeen tools: `list_sessions` + `snapshot`
(perception), `open_session` / `split_pane` / `focus_pane` / `rename_tab` /
`close_pane` / `run_in_session` / `mouse_in_session` (action),
`wait_for_status` + `read_terminal` (synchronisation), `screenshot` (pixels),
`press_keys` + `run_action` (the app's own keyboard), `add_repo` +
`forget_repo` (membership — what the sidebar *contains*, as against what the
-window draws). The loop they exist to
-serve is **act → wait → observe**: `run_in_session` returns immediately, so
-synchronise with `wait_for_status` and then `read_terminal`. Do **not** poll
-`snapshot` in a loop — it races the transition you are watching for, which is
-why the wait rung exists.
+window draws), and `prompt_in_session` (the loop below, composed). The loop
+they exist to serve is **act → wait → observe**: `run_in_session` returns
+immediately, so synchronise with `wait_for_status` and then `read_terminal`.
+Do **not** poll `snapshot` in a loop — it races the transition you are
+watching for, which is why the wait rung exists.
**That loop did not run until #236, and now does.** Every session used to sit
on `starting`, so `wait_for_status` only ever settled by timing out. Two
diff --git a/README.md b/README.md
index 281bb2f..2235d7c 100644
--- a/README.md
+++ b/README.md
@@ -69,17 +69,22 @@ one for your platform:
`.AppImage`, `chmod +x` it, and run it directly.
Prefer a bare command-line binary? The same releases carry one-line installers
-that drop `termherd` into your Cargo bin directory:
+that drop `termherd` into your Cargo bin directory. Every release so far is a
+**pre-release**, which GitHub's `/releases/latest/` shortcut skips, so name the
+tag — the newest one is at the top of the
+[Releases](https://github.com/Termherd/termherd/releases) page:
```bash
# macOS / Linux
+TAG=v0.1.0-prerelease.4
curl --proto '=https' --tlsv1.2 -LsSf \
- https://github.com/Termherd/termherd/releases/latest/download/termherd-installer.sh | sh
+ "https://github.com/Termherd/termherd/releases/download/$TAG/termherd-app-installer.sh" | sh
```
```powershell
# Windows
-powershell -c "irm https://github.com/Termherd/termherd/releases/latest/download/termherd-installer.ps1 | iex"
+$Tag = "v0.1.0-prerelease.4"
+irm "https://github.com/Termherd/termherd/releases/download/$Tag/termherd-app-installer.ps1" | iex
```
### Verify a Linux download
@@ -89,12 +94,15 @@ Linux release binaries carry a sigstore *keyless* build-provenance attestation
in the public Rekor transparency log). Verify a download with the `gh` CLI:
```bash
-gh attestation verify termherd-x86_64-unknown-linux-gnu.tar.xz \
+gh attestation verify termherd-app-x86_64-unknown-linux-gnu.tar.xz \
--repo Termherd/termherd
```
A successful check proves both integrity and that the artifact was built by
-this repository's CI. A `SHA256SUMS` file is also attached to each release.
+this repository's CI. The attestation and its `SHA256SUMS` file come from a
+signing step added after `v0.1.0-prerelease.4`, so that pre-release has
+neither — only per-file `.sha256` checksums and a combined `sha256.sum`, which
+every release carries.
## Run from source
@@ -133,6 +141,9 @@ you want and strip the comments (the real file is strict JSON). In short:
- `open` — the editor command a Ctrl/Cmd-clicked file path opens in, with
`{path}` / `{line}` / `{col}` templates (default: the OS default handler,
which cannot honour a line number).
+- `mcp` — `allow_claude_nesting`: whether `prompt_in_session` may prompt
+ another *Claude* session over the live bridge (default `false`; a shell is
+ never gated).
- `keys` — keyboard overrides, one chord or a list per action; the full
action vocabulary and its default chords are listed in the template.
@@ -180,17 +191,16 @@ where those keys produce `&`, `é`, … without Shift.
Dragging with the mouse selects, and the wheel scrolls back through history.
The two classic terminal clipboard gestures are off until you ask for them:
`terminal.copy_on_select` makes a drag release (or a double-click) copy
-outright, and `terminal.paste_on_right_click` makes a right-click paste into
-the pane under the pointer. Left off, the copy chord reads whatever is
-highlighted on screen. A full-screen program that reads the mouse — Claude
-Code's `/diff` and `/resume`, vim, lazygit, less — owns it while it runs:
-clicks, drags and the wheel go to the program, nothing is selected or pasted
-locally, and Shift+drag takes the mouse back for a selection. The
-copy chord does nothing in such a pane unless a Shift selection
+outright, and `terminal.paste_on_right_click` makes a right-click paste into the
+pane under the pointer. Left off, the copy chord copies the terminal's current
+selection, even one scrolled out of view. A full-screen program that reads the
+mouse — Claude Code's `/diff` and `/resume`, vim, lazygit, less — owns it while
+it runs: clicks, drags and the wheel go to the program, nothing is selected or
+pasted locally, and Shift+drag takes the mouse back for a selection.
+The copy chord does nothing in such a pane unless a Shift selection
exists, so a program's own clipboard write (Claude Code copies a drag on
-release) is never overwritten. In
-the sidebar, click a project or session to open it; a tab's `×` also closes
-it. Hovering a tab shows the session's fuller
+release) is never overwritten. In the sidebar, click a project or session to
+open it; a tab's `×` also closes it. Hovering a tab shows the session's fuller
description (the same card the sidebar shows). **+ Add a repo** puts a
repository in the sidebar before it has any session — or drop its folder on the
window, which does the same thing (a dropped *file* is ignored).
@@ -234,6 +244,7 @@ nothing to configure. It exposes the running workspace:
| `press_keys` · `run_action` | drive termherd's own interface — chords through the live keymap, or actions by name |
| `mouse_in_session` | a mouse event at a cell of a terminal — forwarded to a program reading the mouse, else the terminal's own selection |
| `add_repo` · `forget_repo` | put a repository in the sidebar before it has any session, and drop that addition |
+| `prompt_in_session` | type, wait and read in one round trip — prompting another Claude session is opt-in |
The loop that makes it useful is **act → wait → observe**: `run_in_session`,
then `wait_for_status`, then `read_terminal`. Sessions are addressed by a
@@ -252,13 +263,12 @@ app on one it cannot answer; a sidebar rename used to be the exception
rename — those go through a widget callback no synthesised event reaches
([#246]).
-Five follow-ups remain: a composed prompt→wait→read in one round trip
-([#196]), `enter` on the renames ([#246]), a doc editor that discards unsaved
-edits when it closes ([#248]), reaching the bridge from outside a session
-termherd spawned — the launcher cannot drive it today ([#267]) — and the
-pointer at TermHerd's own interface ([#301]): it reaches a session's terminal,
-and through it a program reading the mouse, but not yet the sidebar, tabs or
-gutters.
+Four follow-ups remain: `enter` on the renames ([#246]), a doc editor that
+discards unsaved edits when it closes ([#248]), reaching the bridge from
+outside a session termherd spawned — the launcher cannot drive it today
+([#267]) — and the pointer at TermHerd's own interface ([#301]): it reaches a
+session's terminal, and through it a program reading the mouse, but not yet
+the sidebar, tabs or gutters.
### The stdio server (manual)
@@ -284,7 +294,6 @@ It speaks JSON-RPC over stdio. Register it with Claude Code by adding it to your
Build the binary with `cargo build -p termherd-mcp` (it lands in `target/`).
[#90]: https://github.com/Termherd/termherd/issues/90
-[#196]: https://github.com/Termherd/termherd/issues/196
[#237]: https://github.com/Termherd/termherd/issues/237
[#246]: https://github.com/Termherd/termherd/issues/246
[#248]: https://github.com/Termherd/termherd/issues/248
diff --git a/crates/app/src/shell/view/sidebar.rs b/crates/app/src/shell/view/sidebar.rs
index 0ad5c91..05c78d8 100644
--- a/crates/app/src/shell/view/sidebar.rs
+++ b/crates/app/src/shell/view/sidebar.rs
@@ -116,7 +116,7 @@ impl Shell {
}
// A handle to collapse the sidebar, mirroring the one that
// restores it from the main pane.
- let hide = button(text("◀ Masquer le panneau").size(11))
+ let hide = button(text(strings::SIDEBAR_HIDE).size(11))
.on_press(Message::ToggleSidebar)
.style(button::text)
.padding(0);
diff --git a/crates/app/src/strings.rs b/crates/app/src/strings.rs
index 7167bd8..557eb06 100644
--- a/crates/app/src/strings.rs
+++ b/crates/app/src/strings.rs
@@ -17,6 +17,7 @@ pub const RENAME_PLACEHOLDER: &str = "title…";
pub const SIDEBAR_LAUNCH_SHELL: &str = "Open a shell here";
pub const SIDEBAR_LAUNCH_CLAUDE: &str = "Start a fresh Claude session";
pub const SIDEBAR_SHOW_LESS: &str = "show less";
+pub const SIDEBAR_HIDE: &str = "◀ Hide";
pub const SIDEBAR_ADD_REPO: &str = "+ Add a repo";
pub const SIDEBAR_ADD_REPO_HINT: &str = "Pick a folder, or drop one on the window";
pub const SIDEBAR_FORGET_REPO: &str = "Remove this repo from the sidebar";
diff --git a/docs/book.toml b/docs/book.toml
index 5ed7b60..1efa68e 100644
--- a/docs/book.toml
+++ b/docs/book.toml
@@ -7,8 +7,9 @@ src = "src"
[build]
build-dir = "book"
-# A link to a page that does not exist must fail the build, not silently mint an
-# empty page. The chapter map in SUMMARY.md is a promise; this keeps it honest.
+# A SUMMARY.md entry for a page that does not exist must fail the build, not
+# silently mint an empty page (in-page links are not checked). The chapter map
+# in SUMMARY.md is a promise; this keeps it honest.
create-missing = false
[output.html]
diff --git a/docs/settings.example.jsonc b/docs/settings.example.jsonc
index cceb757..cf65b73 100644
--- a/docs/settings.example.jsonc
+++ b/docs/settings.example.jsonc
@@ -156,6 +156,14 @@
"scale": 0.5
},
+ // ── MCP live bridge ──────────────────────────────────────────────────────
+ // Whether `prompt_in_session` may prompt another *Claude* session (an agent
+ // driving an agent). Shell sessions are never gated. A single call can also
+ // opt in with its own `allow_claude_nesting: true`. Default: false.
+ "mcp": {
+ "allow_claude_nesting": false
+ },
+
// ── Keyboard overrides ───────────────────────────────────────────────────
// Each entry binds an action to one chord or a list of chords and REPLACES
// that action's default; unlisted actions keep their per-platform default.
diff --git a/docs/src/guide/installation.md b/docs/src/guide/installation.md
index 869b8e6..2bf33b8 100644
--- a/docs/src/guide/installation.md
+++ b/docs/src/guide/installation.md
@@ -40,17 +40,21 @@ On Windows, SmartScreen may warn — choose **More info → Run anyway**.
## Bare command-line binary
The same releases carry one-line installers that drop `termherd` into your
-Cargo bin directory:
+Cargo bin directory. Every release so far is a **pre-release**, which GitHub's
+`/releases/latest/` shortcut skips, so name the tag — the newest one is at the
+top of the [Releases](https://github.com/Termherd/termherd/releases) page:
```bash
# macOS / Linux
+TAG=v0.1.0-prerelease.4
curl --proto '=https' --tlsv1.2 -LsSf \
- https://github.com/Termherd/termherd/releases/latest/download/termherd-installer.sh | sh
+ "https://github.com/Termherd/termherd/releases/download/$TAG/termherd-app-installer.sh" | sh
```
```powershell
# Windows
-powershell -c "irm https://github.com/Termherd/termherd/releases/latest/download/termherd-installer.ps1 | iex"
+$Tag = "v0.1.0-prerelease.4"
+irm "https://github.com/Termherd/termherd/releases/download/$Tag/termherd-app-installer.ps1" | iex
```
## Verifying a Linux download
@@ -60,12 +64,15 @@ attestation — no signing key; the signer is the release workflow itself, via
GitHub OIDC, logged in the public Rekor transparency log.
```bash
-gh attestation verify termherd-x86_64-unknown-linux-gnu.tar.xz \
+gh attestation verify termherd-app-x86_64-unknown-linux-gnu.tar.xz \
--repo Termherd/termherd
```
A passing check proves both integrity and that the artifact was built by this
-repository's CI. A `SHA256SUMS` file is attached to each release as well.
+repository's CI. The attestation and its `SHA256SUMS` file come from a signing
+step added after `v0.1.0-prerelease.4`, so that pre-release has neither — only
+per-file `.sha256` checksums and a combined `sha256.sum`, which every release
+carries.
## From source
diff --git a/docs/src/guide/quick-start.md b/docs/src/guide/quick-start.md
index e5f17ae..d3a09a4 100644
--- a/docs/src/guide/quick-start.md
+++ b/docs/src/guide/quick-start.md
@@ -67,8 +67,9 @@ shows the matched line under the row so you can tell *why* it matched. See
| Close the focused pane (a lone pane closes its tab) | Cmd+W | Ctrl+W |
| Reopen the tab you just closed | Cmd+Shift+T | Ctrl+Shift+T |
-Tabs also reorder by drag-and-drop. Splits resize by keyboard focus only for
-now — drag-resize is the remaining piece of `F-terminal-split`.
+Tabs also reorder by drag-and-drop. Split panes always share their space
+evenly — resizing them, by keyboard or by drag, is the remaining piece of
+`F-terminal-split`.
## 4. Watch what needs you
diff --git a/docs/src/mcp/keyboard.md b/docs/src/mcp/keyboard.md
index e747d77..48800e4 100644
--- a/docs/src/mcp/keyboard.md
+++ b/docs/src/mcp/keyboard.md
@@ -72,10 +72,11 @@ selection, and `copy` runs on it.
- On **`quit-confirm`**, `enter` quits the app — killing every session and the
connection you are speaking over.
-- **`session-rename`** (the sidebar's inline ✎ field) answers to neither
- `enter` nor the rename in the doc pane: both commit through the widget's own
- submit, which a synthesised key event never reaches. `escape` abandons it —
- so you can always back out and start over — but committing a rename over MCP
+- **`session-rename`** (the sidebar's inline ✎ field) does not commit on
+ `enter`, and neither does **`tab-rename`**: both commit through the widget's
+ own submit, which a synthesised key event never reaches. `escape` abandons
+ either — so you can always back out and start over — but committing a rename
+ over MCP
is a missing capability, tracked as
[#246](https://github.com/Termherd/termherd/issues/246).
- Every other overlay is exitable from the keyboard, and a test sweep derived
@@ -89,18 +90,19 @@ anything applies. The error names the offender and the syntax. This is
deliberate: a half-applied sequence is worse than none, because the caller
cannot tell how far it got.
-The action catalogue is published by the [stdio server](./stdio.md) at
+The action catalogue — less the `activate-tab-N` family, which `run_action`
+accepts all the same — is published by the [stdio server](./stdio.md) at
`termherd://keys/schema`; the live bridge serves tools only, so its `run_action`
error message carries the syntax instead.
## Example: verify a keyboard gesture end to end
```text
-run_action(["split-vertical"]) → { steps: [{ outcome: "ran",
+run_action(["split-vertical"]) → { steps: [{ result: "ran",
action: "split-vertical" }],
focused_handle: "4" }
screenshot({ max_width: 900 }) → the pixels, to check the divider
-press_keys(["cmd+w"]) → { steps: [{ outcome: "overlay",
- overlay: "close-confirm" }] }
+press_keys(["cmd+w"]) → { steps: [{ result: "overlay",
+ overlay: "tab-close-confirm" }] }
press_keys(["escape"]) → cancelled
```
diff --git a/docs/src/mcp/live-bridge.md b/docs/src/mcp/live-bridge.md
index c52398f..36bb579 100644
--- a/docs/src/mcp/live-bridge.md
+++ b/docs/src/mcp/live-bridge.md
@@ -16,7 +16,7 @@ session is torn down.
| Tool | Args | Returns |
| --- | --- | --- |
| `list_sessions` | — | `{ sessions: [...] }` — each row a live session: stable `handle`, tab title, cwd, kind (`shell` / `claude`), resumed Claude id, status |
-| `snapshot` | `sections`, `terminals`, `text_lines` | the whole state: config, sidebar, tabs and panes |
+| `snapshot` | `sections`, `terminals`, `focused_terminal`, `text_lines` | the whole state: config, sidebar, tabs and panes |
| `read_terminal` | `session`, `lines` | `{ text, rendered }` |
| `screenshot` | `max_width` | the window as a PNG |
@@ -25,7 +25,8 @@ schema check, which is why `list_sessions` puts its rows in a `sessions` field
rather than answering the array itself.
**`snapshot` is light by default**: structure only, no terminal text. Scope
-text to named handles with `terminals`, or pass `sections` (any of `"config"`,
+text to named handles with `terminals` (or set `focused_terminal: true` for the
+focused pane, when you do not know its handle yet), or pass `sections` (any of `"config"`,
`"sidebar"`, `"tabs"`) to narrow it further. `text_lines` defaults to 40. Read
the structure first, then ask for a handle — that ordering is why the filter
exists.
diff --git a/docs/src/mcp/stdio.md b/docs/src/mcp/stdio.md
index 40b34c3..06fc06a 100644
--- a/docs/src/mcp/stdio.md
+++ b/docs/src/mcp/stdio.md
@@ -55,7 +55,7 @@ outside `dark`/`light`) answers a JSON-RPC error and writes nothing. `null` is
always accepted on a writable id — it unsets the option.
That is the whole write surface today. The `close`, `sidebar`, `record`,
-`open`, `keys`, `terminal.font_size`, `terminal.copy_on_select` and
+`open`, `mcp`, `keys`, `terminal.font_size`, `terminal.copy_on_select` and
`terminal.paste_on_right_click` blocks of
[`settings.json`](../reference/settings.md) are file-only — `keys` is
readable as a resource, below.
@@ -71,7 +71,9 @@ readable as a resource, below.
keymap itself uses, so it cannot drift from the binary you are running. It is
the machine-readable form of
[Keyboard shortcuts](../reference/keyboard.md), and the catalogue the live
-bridge's `run_action` speaks.
+bridge's `run_action` speaks — less the `activate-tab-N` family, which
+`run_action` accepts but the resource does not list. `copy` and `paste` appear
+with no default: theirs differ per platform and are set outside that table.
## What it is not
diff --git a/docs/src/project/contributing.md b/docs/src/project/contributing.md
index e491914..0dee4c4 100644
--- a/docs/src/project/contributing.md
+++ b/docs/src/project/contributing.md
@@ -36,9 +36,11 @@ just docs # build → docs/book/index.html
just docs-serve # live reload on http://localhost:3000
```
-`create-missing = false` in `book.toml` means a link to a page that does not
-exist **fails the build** rather than silently minting an empty page. The
-chapter map in `SUMMARY.md` is a promise; that setting keeps it honest.
+`create-missing = false` in `book.toml` means a `SUMMARY.md` entry for a page
+that does not exist **fails the build** rather than silently minting an empty
+page. The chapter map is a promise; that setting keeps it honest. It covers
+`SUMMARY.md` only — a broken link *inside* a page still builds, so check those
+by hand.
## Three rules that surprise newcomers
diff --git a/docs/src/reference/keyboard.md b/docs/src/reference/keyboard.md
index 77a7805..e8d2864 100644
--- a/docs/src/reference/keyboard.md
+++ b/docs/src/reference/keyboard.md
@@ -92,7 +92,9 @@ way an [MCP caller](../mcp/keyboard.md) can answer a prompt it armed.
## Chord syntax
Case- and order-insensitive. Modifiers `ctrl`, `shift`, `alt`, `cmd`, joined to
-a key with `+`:
+a key with `+`. Aliases: `control` for `ctrl`, `option` for `alt`, and
+`super`, `logo`, `win` or `meta` for `cmd`. The `+` key itself is spelled
+`plus`, since a literal `+` is the separator:
```json
"keys": {
@@ -107,7 +109,10 @@ chords are logged and skipped — they do not invalidate the rest of the file.
## Reading the live keymap
-The [stdio MCP server](../mcp/stdio.md) publishes the whole catalogue —
-every action with its default *and* current chords — as a resource at
-`termherd://keys/schema`. It is generated from the same in-code table this page
-describes, so it cannot drift from the binary you are running.
+The [stdio MCP server](../mcp/stdio.md) publishes the action catalogue — each
+action with its default chords and the override `settings.json` sets for it,
+if any — as a resource at `termherd://keys/schema`. It is generated from the
+same in-code table this page describes, so it cannot drift from the binary you
+are running. Two gaps: the `activate-tab-N` family is not listed, and `copy` /
+`paste` show no default, because theirs differ per platform and are set
+outside that table — this page has them.
diff --git a/docs/src/reference/settings.md b/docs/src/reference/settings.md
index 001806b..34ad4b3 100644
--- a/docs/src/reference/settings.md
+++ b/docs/src/reference/settings.md
@@ -110,6 +110,17 @@ Values clamp: fps 1–60, `max_seconds` 1–600, `scale` 0.1–1.0.
"record": { "fps": 8, "max_seconds": 30, "scale": 0.5 }
```
+### `mcp`
+
+Whether the live bridge's `prompt_in_session` may prompt another **Claude**
+session — one agent driving another. Off by default; a shell session is never
+gated. A single call can opt in on its own with `allow_claude_nesting: true`
+(see [The live bridge](../mcp/live-bridge.md)).
+
+```json
+"mcp": { "allow_claude_nesting": false }
+```
+
### `open`
The command a Cmd/Ctrl-clicked file path opens in. Omit
@@ -166,9 +177,9 @@ The eight ids it covers today: `theme`, `shell.program`, `shell.args`,
`terminal.colors.palette`. Two of them — `shell.program` and `shell.args` —
are **read-only** over MCP: they name what TermHerd executes at the next
launch, so an agent may read them but never set them. The `close`, `sidebar`,
-`record`, `open`, `keys`, `terminal.font_size`, `terminal.copy_on_select` and
-`terminal.paste_on_right_click` blocks are file-only for now; `keys` is
-published as a read-only resource.
+`record`, `open`, `mcp`, `keys`, `terminal.font_size`,
+`terminal.copy_on_select` and `terminal.paste_on_right_click` blocks are
+file-only for now; `keys` is published as a read-only resource.
A `set_option` write lands in `settings.json` and **applies on restart**, like
any other edit to the file.
@@ -189,6 +200,7 @@ any other edit to the file.
"sidebar": { "session_limit": 0 },
"record": { "fps": 10, "max_seconds": 20, "scale": 0.5 },
"open": { "command": "code -g {path}:{line}:{col}" },
+ "mcp": { "allow_claude_nesting": false },
"keys": {
"toggle-sidebar": "ctrl+alt+b",
"focus-next": "ctrl+alt+right"
diff --git a/docs/src/workspace/tabs-and-splits.md b/docs/src/workspace/tabs-and-splits.md
index f01b88b..cb9dc28 100644
--- a/docs/src/workspace/tabs-and-splits.md
+++ b/docs/src/workspace/tabs-and-splits.md
@@ -53,8 +53,8 @@ there is no second, rival tab tree to drift out of sync.
| Focus a neighbour | Cmd+Shift+←↑↓→ | Ctrl+Shift+←↑↓→ |
A split opens a **fresh shell** beside the focused pane. Directional focus
-walks the pane tree geometrically — Shift+→ goes to the
-pane on the right, whatever the nesting.
+walks the pane tree geometrically — Cmd/Ctrl+Shift+→
+goes to the pane on the right, whatever the nesting.
Closing the **last** pane in a tab closes the tab.
diff --git a/docs/src/workspace/terminal.md b/docs/src/workspace/terminal.md
index 7521919..bbac232 100644
--- a/docs/src/workspace/terminal.md
+++ b/docs/src/workspace/terminal.md
@@ -30,11 +30,11 @@ so nothing reaches the clipboard unless you asked for it:
- **`copy_on_select`** — releasing a drag, or double-clicking a word, copies
the selection outright. With it off the selection still highlights and waits
- for the copy chord, which reads the highlight currently on screen — so the
- text you copy is the text you just selected, never what you copied last.
- With nothing selected the chord does nothing — in particular in a pane
- whose program owns the mouse (below), where the program's own copy of a drag
- stays on the clipboard untouched.
+ for the copy chord, which asks the terminal for its current selection — even
+ one scrolled out of view — so the text you copy is the text you just
+ selected, never what you copied last. With nothing selected the chord does
+ nothing — in particular in a pane whose program owns the mouse (below), where
+ the program's own copy of a drag stays on the clipboard untouched.
- **`paste_on_right_click`** — a right-click pastes into **the pane under the
pointer**, which need not be the focused one, and is bracketed when that pane
asked for bracketed paste. The click also focuses that pane, so the keys you