mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
xterm hands back whole screen rows and trims only the cells that were never written to, so the real spaces a full-screen TUI paints across the unused part of a row count as content and reach the clipboard. Measured against Claude Code in a 282-column pane, single lines arrived carrying 138 trailing spaces, and every line carried the two-space transcript indent as well. Windows Terminal, iTerm2 and GNOME Terminal all trim that for you, decideAutoCopy already calls a wall of spaces "never what the gesture meant", and _selectTouchSelectionLine already treats those cells as padding — the mouse and keyboard paths never had the same rule. CodemanCopySelection.clean lives in constants.js beside decideAutoCopy, its pure sibling. It drops the trailing run from each line, and removes the leading run only where every selected row shares one. A selection of a single row keeps its run, because one row shares nothing with anything and stripping it would silently reindent one line of `git log` body text or one line out of `less`. A drag that began inside a row keeps its partial first line untouched and out of the measurement, which otherwise pins the shared run to zero and leaves every following row indented. Every pass over a line is a scan rather than a regex. `/[ \t]+(\r?)$/` is quadratic on a line whose spaces are followed by a non-space character, which is what right-aligned or centred TUI content looks like: measured over 50 000 rows with a 280-column run it took 2.9s, against 1.3ms for the scan, and a 2 000-column run took 16s. The scan is also the faster of the two on an ordinary padded row. cleanedTerminalSelection in terminal-ui.js is the half that needs the live terminal. It returns a COLUMN selection untouched: Alt+drag makes one, and a rectangle's rows lining up is the point of the gesture, so both halves of the clean would destroy it. xterm exposes the mode nowhere public, so the check reads terminal._core._selectionService, the way this file already reads terminal._core for cell dimensions, and cleans normally if a future xterm renames the field. A test pins that assumption against the library rather than against a stub repeating the literal. The Ctrl+C chord decides on the cleaned selection, not the raw one. A drag across the blank part of a row selects real padding spaces, so the raw text is truthy, and testing it would spend that press on a copy of nothing and make the user press again to interrupt. A padding-only selection is now dropped and the press falls through to the PTY, while Ctrl+Shift+C still never falls through. copyTerminalSelection gates on trim() for the same reason, since a multi-row drag across padding cleans to line breaks alone and a bare newline pasted into a chat composer submits it. All four of the main terminal's copy paths go through it: the Ctrl+C chord, right-click, the phone selection button and Auto Copy. The browser's own Edit menu copy, a disabled copy shortcut and the subagent windows still copy raw rows, as they did before, and the invariants doc now says so rather than claiming every copy is cleaned. Auto Copy resolves its own toggle before it reads the selection, since it is off by default and a selection can run to the 50 000-row scrollback ceiling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
79 lines
4.6 KiB
Markdown
79 lines
4.6 KiB
Markdown
# Keyboard Shortcuts
|
|
|
|
Every binding, and how to change them. `Ctrl` also accepts `Cmd` on macOS.
|
|
|
|
Press `Ctrl+?` in the app for the same list in a floating overlay.
|
|
|
|
## Sessions and tabs
|
|
|
|
| Shortcut | Action |
|
|
| ------------------------------- | --------------------------------------------------------------- |
|
|
| `Ctrl+K` (also `Cmd+K`, `Alt+K`)| Find an open session or start a new one. |
|
|
| `Ctrl+W` | Kill the active session. |
|
|
| `Ctrl+Tab` | Next session. |
|
|
| `Alt+[` / `Alt+]` | Previous / next tab. |
|
|
| `Alt+1` to `Alt+9` | Switch to tab N. Physical keys, so macOS Option layouts work. |
|
|
| `Ctrl+Shift+{` / `Ctrl+Shift+}` | Move the active tab left / right. |
|
|
| `Alt+B` | Collapse / expand the session sidebar, when that layout is on. |
|
|
|
|
## Terminal
|
|
|
|
| Shortcut | Action |
|
|
| ----------------------- | --------------------------------------------------------------- |
|
|
| `Enter` | Send. |
|
|
| `Shift+Enter` | Insert a newline without sending. |
|
|
| `Ctrl+Enter` | Same. |
|
|
| `Ctrl+C` | Copy the selection, or interrupt when nothing is selected. |
|
|
| `Ctrl+Shift+C` | Copy the selection. Never interrupts. |
|
|
| `Ctrl+V` | Paste. An image on the clipboard uploads and pastes its file path instead. |
|
|
| `Ctrl+L` | Clear the terminal. |
|
|
| `Ctrl+Shift+R` | Restore terminal size. |
|
|
| `Ctrl` `+` / `Ctrl` `-` | Font size. |
|
|
| `Shift+Wheel` | Scroll the local buffer, even where the wheel is forwarded to the CLI. |
|
|
| `Shift+drag` | Start a selection in a pane whose mouse events go to the CLI. |
|
|
| Right-click | Copy the selection. With nothing selected the native menu is left alone. |
|
|
| `Ctrl+Z` | Swallowed in agent sessions so a running CLI cannot be suspended. Normal job control in a shell. |
|
|
|
|
Anything you copy is cleaned on the way to the clipboard. Each line loses the padding spaces a full-screen program paints across the rest of the row, and a selection covering several rows also loses the indent every one of those rows shares, which is usually the program's own margin rather than your text. A one-row selection keeps its indent, and an `Alt+drag` rectangular selection is copied exactly as it looks, so its columns stay lined up.
|
|
|
|
## Everything else
|
|
|
|
| Shortcut | Action |
|
|
| -------------- | ------------------------------- |
|
|
| `Ctrl+Shift+V` | Toggle voice input. |
|
|
| `Ctrl+?` | Shortcut reference overlay. |
|
|
| `Escape` | Close panels and modals. |
|
|
|
|
## Rebinding
|
|
|
|
**App Settings → Shortcuts.** Bindings live in a registry with per-user overrides, so a
|
|
rebind is stored as an override on top of the default rather than replacing the table.
|
|
|
|
Two things are deliberately not rebindable:
|
|
|
|
- **`Ctrl+C` smart copy.** The generic dispatch loop calls `preventDefault()` on every
|
|
shortcut it handles, and doing that to `Ctrl+C` would swallow the interrupt when nothing
|
|
is selected. It is handled separately for that reason.
|
|
- **`Escape`**, which closes whatever is open.
|
|
|
|
## Why some chords behave oddly
|
|
|
|
The terminal sees keystrokes before the app does. Any chord the app claims has to also be
|
|
swallowed at the terminal layer, or xterm writes the control byte into the session as well
|
|
as triggering the action. If you rebind something to a chord the terminal cares about
|
|
(`Ctrl+D`, say), expect the CLI to see it too.
|
|
|
|
`Alt+1` through `Alt+9` are matched on **physical key position** rather than the character
|
|
produced, so macOS Option layouts that produce `¡™£` still switch tabs.
|
|
|
|
## On phones
|
|
|
|
There is no physical keyboard, so the equivalents live in the keyboard accessory bar: `Esc`,
|
|
`Ctrl` as a one-shot modifier, `Tab`, arrows, and quick actions. See
|
|
[Mobile Guide](Mobile-Guide).
|
|
|
|
## Read next
|
|
|
|
- [The Dashboard](The-Dashboard) - what the shortcuts are navigating.
|
|
- [Settings Reference](Settings-Reference) - where the overrides are stored.
|