Files
tty7/docs/reference/keyboard-shortcuts.mdx
l0ng-ai 7bcb91d8af fix(input): give the PTY back the Ctrl chords tty7 was eating (#684)
* fix(input): give the PTY back the Ctrl chords tty7 was eating

Follow-up to #682, which handed Ctrl+V to a full-screen program but left
three neighbouring holes of the same shape: a key the terminal answers
without the keymap ever seeing it.

The C0 table was half a table. `input.rs` mapped the alphabet, `[ \ ]`
and Ctrl+2, and nothing else — so `Ctrl-^` (Ctrl+6, vim's alternate
file), `Ctrl-_` (readline's undo, typed as Ctrl+/ or Ctrl+Shift+-) and
Ctrl+3..8 produced no bytes at all. They were not mis-encoded, they were
silent: gpui filters control characters out of `key_char` on all three
backends, so the text fallback had nothing to offer either. The table is
now the VT-220 one, each digit beside the punctuation that shares its
key, because every platform hands Ctrl+Shift+6 over as `^` with the
Shift already spent. Ctrl+/ is xterm's addition rather than VT-220's and
is spelled out with the reason. The twenty-six letters fold to `& 0x1f`.

`on_key_down` swallowed plain Ctrl+1..9 off macOS with a bare `return`,
left over from when tabs lived on ctrl-digits — they have been on
Alt+1..9 for a long time, so nothing claimed those chords and the block
only deleted keys. It also sat before `keystroke_to_bytes`, so not even
the kitty protocol got through it. Gone.

Ctrl+V is now a binding. `AlternatePaste` carries `ctrl-v` off macOS in
a `Terminal && !alt_screen` context, and the pane declares `alt_screen`
whenever a full-screen program owns the grid, so the behaviour #682
settled on is unchanged — paste at a prompt, SYN inside vim — while the
keymap can finally express it, the Keybindings page lists it, and the
user gets a say: `"AlternatePaste": ""` hands Ctrl+V to the shell
everywhere, including readline's `quoted-insert`, and
`"PasteText": "ctrl-v"` pastes on every screen the way Windows Terminal
does. That cohort is real — Warp keeps Ctrl+V pasting on Windows on
purpose, as a removable binding, for exactly this reason. The hardcoded
arm in `handle_cmd_shortcut` now answers Cmd+V alone, which is macOS's
only paste chord and carries no control code to lose.

Last, the rule about control codes is one function instead of an
assertion buried in a test. `steals_a_control_code` plus a commented
`control_code_binding_allowed` back both the defaults test and a new
runtime warning, so a hand-edited config.json that takes EOF away from
every shell says so in the log. It warns rather than refuses: a chord
the user asked for by name is theirs to spend, the way the tmux preset
spends Ctrl+B. The invariant that still fails a build is that no
*default* spends one silently.

Tests: `cargo test --bin tty7-app` 1360 passed, 1 known flake
(`a_routed_auth_prompt_carries_the_machine_that_raised_it`, green on a
rerun and on a clean tree). New: the whole VT-220 table asserted byte by
byte, with Ctrl+- held out; `ctrl_6_reaches_the_pty_as_rs`,
`ctrl_v_pastes_at_a_prompt` and `ctrl_v_reaches_a_full_screen_program_as_syn`
drive the real keymap through `simulate_keystrokes` rather than calling
into the view; the keymap tests cover both escape hatches and the
context that withholds the binding. #682's two `handle_cmd_shortcut`
tests are replaced by those three, which assert the same behaviour at
the layer that now decides it; its end-to-end SYN test stands unchanged.
The gpui tests are unix-only, so CI is what runs them.

* fix(input): ask the grid, not the last frame, before Ctrl+V pastes

`AlternatePaste` carries `Terminal && !alt_screen`, but gpui matches a
keystroke against the frame it last painted, so the context outlives the
switch: a full-screen program that took the screen after that paint is
still "at a prompt" as far as the keymap is concerned, and the clipboard
lands in it. In vim's normal mode that runs as commands. The action now
re-reads the terminal mode and propagates instead, which hands the chord
to `on_key_down` and encodes it as the SYN the program is waiting for.

Also:

- the two escape-hatch assertions in
  `paste_ships_both_terminal_chords_off_macos_and_retires_together`
  built a one-entry binding table instead of the default one, so both
  passed without the hatch working — an emptied `AlternatePaste` cannot
  dispatch anything when it is the only entry in the table. They now
  apply the config line on top of the whole default table, and the
  `PasteText: ctrl-v` case checks both screens;
- the keyboard-shortcuts page claimed every other Ctrl chord reaches the
  program, which Ctrl+Tab and the Windows/Linux font-size chords do not;
- `steals_a_control_code` documents `@` and the backtick, which are in
  the set it walks but were not in the list beside it.
2026-08-19 17:38:28 +08:00

132 lines
5.8 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Keyboard shortcuts"
description: "Every default binding, plus the action names for rebinding."
---
**Settings → Keybindings** (<kbd>⌘ ,</kbd>) is the live version of this page —
it shows what *your* copy is bound to. This is the shipped default.
## Tabs and workspaces
| Action | macOS | Windows / Linux |
|---|---|---|
| New Tab | <kbd>⌘ T</kbd> | <kbd>Ctrl ⇧ T</kbd> |
| Close Pane / Tab | <kbd>⌘ W</kbd> | <kbd>Ctrl ⇧ W</kbd> |
| Reopen Closed Tab | <kbd>⌘ ⇧ T</kbd> | <kbd>Alt ⇧ T</kbd> |
| Next Tab · Previous Tab | <kbd>⌃ ⇥</kbd> · <kbd>⌃ ⇧ ⇥</kbd> | same |
| Go to Tab 19 | <kbd>⌘ 1</kbd>…<kbd>⌘ 9</kbd> | <kbd>Alt 1</kbd>…<kbd>Alt 9</kbd> |
| New Workspace | <kbd>⌘ ⇧ N</kbd> | <kbd>Ctrl ⇧ N</kbd> |
| Switch Workspace | <kbd>⌘ ⇧ O</kbd> | <kbd>Ctrl ⇧ O</kbd> |
## Panes
| Action | macOS | Windows / Linux |
|---|---|---|
| Split Right | <kbd>⌘ D</kbd> | <kbd>Ctrl ⇧ D</kbd> |
| Split Down | <kbd>⌘ ⇧ D</kbd> | <kbd>Ctrl Alt ⇧ D</kbd> |
| Next Pane · Previous Pane | <kbd>⌘ ]</kbd> · <kbd>⌘ [</kbd> | <kbd>Ctrl ⇧ ]</kbd> · <kbd>Ctrl ⇧ [</kbd> |
| Focus Pane Left / Right / Up / Down | <kbd>⌘ ⌥ ←→↑↓</kbd> | <kbd>Alt ←→↑↓</kbd> |
| Zoom Pane | <kbd>⌘ ⇧ ⏎</kbd> | <kbd>Ctrl ⇧ ⏎</kbd> |
| Enter Full Screen | <kbd>⌘ ⏎</kbd> | <kbd>F11</kbd> |
## View
| Action | macOS | Windows / Linux |
|---|---|---|
| Command Palette | <kbd>⌘ P</kbd> | <kbd>Ctrl ⇧ P</kbd> |
| Toggle Left Sidebar | <kbd>⌘ B</kbd> | <kbd>Ctrl ⇧ B</kbd> |
| Toggle Right Panel | <kbd>⌘ J</kbd> | <kbd>Ctrl ⇧ J</kbd> |
| Toggle Code Panel | <kbd>⌘ ⇧ E</kbd> | <kbd>Ctrl ⇧ E</kbd> |
| Font Size Up · Down · Reset | <kbd>⌘ +</kbd> · <kbd>⌘ </kbd> · <kbd>⌘ 0</kbd> | <kbd>Ctrl +</kbd> · <kbd>Ctrl </kbd> · <kbd>Ctrl 0</kbd> |
| Zoom the font | <kbd>⌘</kbd> + wheel | <kbd>Ctrl</kbd> + wheel |
## Terminal
| Action | macOS | Windows / Linux |
|---|---|---|
| Find in Terminal | <kbd>⌘ F</kbd> | <kbd>Ctrl ⇧ F</kbd> |
| Find Next · Previous | <kbd>⌘ G</kbd> · <kbd>⌘ ⇧ G</kbd> | <kbd>F3</kbd> · <kbd>⇧ F3</kbd> |
| Clear Scrollback | <kbd>⌘ K</kbd> | <kbd>Ctrl ⇧ K</kbd> |
| Copy · Paste | <kbd>⌘ C</kbd> · <kbd>⌘ V</kbd> | <kbd>Ctrl ⇧ C</kbd> · <kbd>Ctrl ⇧ V</kbd> · <kbd>⇧ Insert</kbd> |
| Insert Newline (at the prompt) | <kbd>⇧ ⏎</kbd> · <kbd>⌥ ⏎</kbd> | same |
| Fuzzy history search | <kbd>⌃ R</kbd> | same |
| Accept ghost suggestion | <kbd>→</kbd> | same |
| Completion menu | <kbd>⇥</kbd> | same |
On Windows and Linux plain <kbd>Ctrl V</kbd> also pastes at a shell prompt.
Inside a full-screen application — vim, less, tmux — it is passed through as
the key, so it means what the application says it means (blockwise Visual mode
in vim); paste there with <kbd>Ctrl ⇧ V</kbd> or <kbd>⇧ Insert</kbd>.
That convenience is the **Paste (outside full-screen apps)** binding, and it is
yours to move. Clearing it hands <kbd>Ctrl V</kbd> to the shell everywhere,
including readline's `quoted-insert`:
```json
{ "keybindings": { "AlternatePaste": "" } }
```
Putting Paste itself on the chord goes the other way, pasting on every screen
the way Windows Terminal does out of the box:
```json
{ "keybindings": { "PasteText": "ctrl-v" } }
```
Every <kbd>Ctrl</kbd> chord that stands for a control code reaches the program
you are running: <kbd>Ctrl 6</kbd> and <kbd>Ctrl ⇧ 6</kbd> are `^^` (vim's
alternate file), <kbd>Ctrl /</kbd> and <kbd>Ctrl ⇧ </kbd> are `^_` (readline's
undo), <kbd>Ctrl 3</kbd> is Escape. The plain <kbd>Ctrl</kbd> chords tty7 keeps
are the ones that stand for nothing: <kbd>Ctrl ⇥</kbd> for the next tab, and on
Windows and Linux <kbd>Ctrl +</kbd> · <kbd>Ctrl </kbd> · <kbd>Ctrl 0</kbd> for
the font size.
## Git and SSH
| Action | macOS | Windows / Linux |
|---|---|---|
| Commit (caret in the message box) | <kbd>⌘ ⏎</kbd> | <kbd>Ctrl ⏎</kbd> |
| Save (in the editor) | <kbd>⌘ S</kbd> | <kbd>Ctrl S</kbd> |
| Restart SSH Session | <kbd>⌘ ⇧ R</kbd> | <kbd>Ctrl ⇧ R</kbd> |
## Application
| Action | macOS | Windows / Linux |
|---|---|---|
| Settings | <kbd>⌘ ,</kbd> | <kbd>Ctrl ,</kbd> |
| Keyboard Shortcuts | <kbd>⌘ /</kbd> | — |
| Hide tty7 · Hide Others · Minimize | <kbd>⌘ H</kbd> · <kbd>⌘ ⌥ H</kbd> · <kbd>⌘ M</kbd> | — |
| Quit | <kbd>⌘ Q</kbd> | <kbd>Ctrl ⇧ Q</kbd> |
## Actions with no default key
All of these are in the command palette, and all are bindable under **Settings →
Keybindings**:
| Group | Actions |
|---|---|
| Tabs | `RenameTab` · `NewWorktreeTab` · `CloseOtherTabs` · `CloseTabsToTheRight` · `CopyWorkingDirectory` · `MarkTabUnread` · `ToggleTabSidebar` |
| Panes | `ResizePaneLeft/Right/Up/Down` · `SwapPaneNext` · `SwapPanePrev` |
| Workspaces | `SelectWorkspace1`…`SelectWorkspace9` · `RenameWorkspace` · `StopWorkspace` · `DeleteWorkspace` |
| Agents | `ForkAgentSession` (+ `Right` / `Left` / `Down` / `Up`) · `CopyAgentSessionId` |
| Git | `ScmStageAll` · `ScmUnstageAll` · `ScmDiscardAll` · `ScmCommitAmend` · `ScmRefresh` · `ScmSync` · `ScmPush` · `ScmPull` · `ScmFetch` · `ScmCheckoutBranch` · `ScmCreateBranch` · `ScmToggleGraph` · `ToggleDiffViewMode` |
| Panels | `ShowRightPanelInfo` · `ShowRightPanelChanges` · `ShowRightPanelFiles` |
| SSH | `ToggleSftp` · `ShowSshForwards` · `OpenSshProfiles` |
| Application | `About` · `CheckForUpdates` · `OpenDocumentation` · `OpenDiscord` · `ReportIssue` · `ShowAll` · `ZoomWindow` |
## Rebinding syntax
```json
{
"keybindings": {
"ResizePaneLeft": "ctrl-alt-left",
"ToggleSftp": "secondary-shift-u",
"ScmSync": "ctrl-b s"
}
}
```
`secondary` means <kbd>⌘</kbd> on macOS and <kbd>Ctrl</kbd> elsewhere. A space
separates the steps of a chord.
[More →](/customization/keybindings)