chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
@@ -1,16 +1,36 @@
|
||||
# Keybindings
|
||||
# Keybindings Reference
|
||||
|
||||
All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Each action can be bound to one or more keys.
|
||||
Pi exposes named actions, such as `app.session.new`, that can be assigned keybindings. You can change default assignments or bind unassigned actions in Pi's [user configuration](configuration.md#agent-directory).
|
||||
|
||||
The config file uses the same namespaced keybinding ids that pi uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.
|
||||
Run `/hotkeys` to see the active shortcuts for the main editor and application.
|
||||
|
||||
Older configs using pre-namespaced ids such as `cursorUp` or `expandTools` are migrated automatically to the namespaced ids on startup.
|
||||
## Assign keybindings
|
||||
|
||||
After editing `keybindings.json`, run `/reload` in pi to apply the changes without restarting the session.
|
||||
Create `<agent-dir>/keybindings.json`. The agent directory defaults to `~/.pi/agent` and is described in [Agent directory](configuration.md#agent-directory).
|
||||
|
||||
## Key Format
|
||||
Map each action identifier to one key or a list of keys:
|
||||
|
||||
`modifier+key` where modifiers are `ctrl`, `shift`, `alt`, `super` (combinable) and keys are:
|
||||
```json
|
||||
{
|
||||
"$schema": "https://pi.dev/schemas/keybindings.schema.json",
|
||||
"app.session.new": "ctrl+shift+n",
|
||||
"app.session.tree": ["ctrl+shift+t", "alt+shift+t"]
|
||||
}
|
||||
```
|
||||
|
||||
A configured value replaces the default for that action. Use an empty list to disable an action's keybindings:
|
||||
|
||||
```json
|
||||
{
|
||||
"tui.altScreen.pageUp": []
|
||||
}
|
||||
```
|
||||
|
||||
After editing the file, run `/reload` to apply the changes to the active session.
|
||||
|
||||
## Key syntax
|
||||
|
||||
Write a key as `modifier+key`. Modifiers are `ctrl`, `shift`, `alt`, and `super`. You can combine modifiers. Valid keys are:
|
||||
|
||||
- **Letters:** `a-z`
|
||||
- **Digits:** `0-9`
|
||||
@@ -18,64 +38,56 @@ After editing `keybindings.json`, run `/reload` in pi to apply the changes witho
|
||||
- **Function:** `f1`-`f12`
|
||||
- **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
|
||||
|
||||
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `super+k`, `ctrl+super+k`, `ctrl+1`, etc.
|
||||
Examples: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `super+k`, `ctrl+super+k`, and `ctrl+1`.
|
||||
|
||||
`super` bindings require a terminal that reports the modifier separately, typically through the Kitty keyboard protocol. They may not work in terminals without that support.
|
||||
|
||||
## All Actions
|
||||
## Actions
|
||||
|
||||
### TUI Editor Cursor Movement
|
||||
### Terminal UI
|
||||
|
||||
#### Cursor movement
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
|---|---|---|
|
||||
| `tui.editor.cursorUp` | `up` | Move cursor up, browsing older history at the top |
|
||||
| `tui.editor.cursorDown` | `down` | Move cursor down, browsing newer history at the bottom |
|
||||
| `tui.editor.historyPrevious` | *(none)* | Select the previous prompt history entry |
|
||||
| `tui.editor.historyNext` | *(none)* | Select the next prompt history entry |
|
||||
| `tui.editor.historyPrevious` | None | Select the previous prompt history entry |
|
||||
| `tui.editor.historyNext` | None | Select the next prompt history entry |
|
||||
| `tui.editor.cursorLeft` | `left`, `ctrl+b` | Move cursor left |
|
||||
| `tui.editor.cursorRight` | `right`, `ctrl+f` | Move cursor right |
|
||||
| `tui.editor.cursorWordLeft` | `alt+left`, `ctrl+left`, `alt+b` | Move cursor word left |
|
||||
| `tui.editor.cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right |
|
||||
| `tui.editor.cursorLineStart` | `home`, `ctrl+home`, `ctrl+a` | Move to line start |
|
||||
| `tui.editor.cursorLineEnd` | `end`, `ctrl+end`, `ctrl+e` | Move to line end |
|
||||
| `tui.editor.cursorLineStart` | `home`, `ctrl+a` | Move to line start |
|
||||
| `tui.editor.cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
|
||||
| `tui.editor.jumpForward` | `ctrl+]` | Jump forward to character |
|
||||
| `tui.editor.jumpBackward` | `ctrl+alt+]` | Jump backward to character |
|
||||
| `tui.editor.pageUp` | `pageUp`, `ctrl+pageUp` | Scroll up by page |
|
||||
| `tui.editor.pageDown` | `pageDown`, `ctrl+pageDown` | Scroll down by page |
|
||||
|
||||
The dedicated history actions always change history entries, regardless of the cursor position in a multiline prompt. Explicit history bindings take precedence over application actions while the main editor is focused, so binding `tui.editor.historyPrevious` to `ctrl+p` overrides model cycling in that context without changing `Ctrl+P` in selectors.
|
||||
The dedicated history actions browse prompt history regardless of cursor position and take precedence over application actions using the same key.
|
||||
|
||||
### TUI Editor Deletion
|
||||
#### Text editing
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
|---|---|---|
|
||||
| `tui.editor.deleteCharBackward` | `backspace` | Delete character backward |
|
||||
| `tui.editor.deleteCharForward` | `delete`, `ctrl+d` | Delete character forward |
|
||||
| `tui.editor.deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
|
||||
| `tui.editor.deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
|
||||
| `tui.editor.deleteToLineStart` | `ctrl+u` | Delete to line start |
|
||||
| `tui.editor.deleteToLineEnd` | `ctrl+k` | Delete to line end |
|
||||
|
||||
### TUI Input
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `tui.input.newLine` | `shift+enter`, `ctrl+j` | Insert new line |
|
||||
| `tui.input.submit` | `enter` | Submit input |
|
||||
| `tui.input.tab` | `tab` | Tab / autocomplete |
|
||||
|
||||
### TUI Kill Ring
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `tui.editor.yank` | `ctrl+y` | Paste most recently deleted text |
|
||||
| `tui.editor.yankPop` | `alt+y` | Cycle through deleted text after yank |
|
||||
| `tui.editor.undo` | `ctrl+-` (`ctrl+z` on Windows; `alt+z` on WSL) | Undo last edit |
|
||||
|
||||
### TUI Clipboard and Selection
|
||||
#### Input and selection
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
|---|---|---|
|
||||
| `tui.input.newLine` | `shift+enter`, `ctrl+j` | Insert new line |
|
||||
| `tui.input.submit` | `enter` | Submit input |
|
||||
| `tui.input.tab` | `tab` | Tab or autocomplete |
|
||||
| `tui.input.copy` | `ctrl+c` | Copy selection |
|
||||
| `tui.select.up` | `up` | Move selection up |
|
||||
| `tui.select.down` | `down` | Move selection down |
|
||||
@@ -84,39 +96,26 @@ The dedicated history actions always change history entries, regardless of the c
|
||||
| `tui.select.confirm` | `enter` | Confirm selection |
|
||||
| `tui.select.cancel` | `escape`, `ctrl+c` | Cancel selection |
|
||||
|
||||
### TUI Fullscreen Viewport
|
||||
#### Fullscreen
|
||||
|
||||
These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content. While the transcript is scrolled up, a clickable "Jump to latest message" label on its bottom row shows the `tui.altScreen.bottom` shortcut. See [Terminal setup](terminal-setup.md) for terminal-specific mouse and trackpad behavior.
|
||||
|
||||
Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
|
||||
|
||||
The transcript search panel shows the configured previous/next shortcuts and clickable arrow controls. Press `tui.altScreen.search` again, or use `tui.altScreen.searchClose`, to close it.
|
||||
|
||||
| Key | Default mode | Fullscreen mode |
|
||||
|-----|--------------|-----------------|
|
||||
| `home`, `end` | Editor | Transcript |
|
||||
| `ctrl+home`, `ctrl+end` | Editor | Editor |
|
||||
| `pageUp`, `pageDown` | Editor | Transcript |
|
||||
| `ctrl+pageUp`, `ctrl+pageDown` | Editor | Editor |
|
||||
|
||||
This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for half-page steps, or bind `tui.altScreen.lineUp` and `tui.altScreen.lineDown` for single-line steps. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
|
||||
In fullscreen mode, these actions control the transcript and take precedence over editor actions using the same key.
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
|---|---|---|
|
||||
| `tui.altScreen.pageUp` | `pageUp` | Scroll the transcript up by one page |
|
||||
| `tui.altScreen.pageDown` | `pageDown` | Scroll the transcript down by one page |
|
||||
| `tui.altScreen.halfPageUp` | *(none)* | Scroll the transcript up by half a page |
|
||||
| `tui.altScreen.halfPageDown` | *(none)* | Scroll the transcript down by half a page |
|
||||
| `tui.altScreen.lineUp` | *(none)* | Scroll the transcript up by one line |
|
||||
| `tui.altScreen.lineDown` | *(none)* | Scroll the transcript down by one line |
|
||||
| `tui.altScreen.halfPageUp` | None | Scroll the transcript up by half a page |
|
||||
| `tui.altScreen.halfPageDown` | None | Scroll the transcript down by half a page |
|
||||
| `tui.altScreen.lineUp` | None | Scroll the transcript up by one line |
|
||||
| `tui.altScreen.lineDown` | None | Scroll the transcript down by one line |
|
||||
| `tui.altScreen.previousPrompt` | `ctrl+shift+up`, `ctrl+up` (`ctrl+up` only on Windows and WSL) | Jump to the previous marked message |
|
||||
| `tui.altScreen.nextPrompt` | `ctrl+shift+down`, `ctrl+down` (`ctrl+down` only on Windows and WSL) | Jump to the next marked message |
|
||||
| `tui.altScreen.search` | `ctrl+shift+f` (`ctrl+f` on Windows and WSL) | Search the rendered transcript |
|
||||
| `tui.altScreen.searchNext` | `enter`, `ctrl+g` | Select the next search match while searching |
|
||||
| `tui.altScreen.searchPrevious` | `shift+enter`, `ctrl+shift+g` | Select the previous search match while searching |
|
||||
| `tui.altScreen.searchClose` | `escape` | Close transcript search |
|
||||
| `tui.altScreen.top` | `home` | Scroll to the beginning of the transcript |
|
||||
| `tui.altScreen.bottom` | `end` | Scroll to the transcript end and follow new output |
|
||||
| `tui.altScreen.top` | `ctrl+home` | Scroll to the beginning of the transcript |
|
||||
| `tui.altScreen.bottom` | `ctrl+end` | Scroll to the transcript end and follow new output |
|
||||
|
||||
### Application
|
||||
|
||||
@@ -125,18 +124,20 @@ This routing remains configurable through the ordinary action bindings. For exam
|
||||
| `app.interrupt` | `escape` | Cancel / abort |
|
||||
| `app.clear` | `ctrl+c` | Clear editor (first) / exit (second) |
|
||||
| `app.exit` | `ctrl+d` | Exit (when editor empty) |
|
||||
| `app.suspend` | `ctrl+z` (none on Windows) | Suspend to background |
|
||||
| `app.suspend` | `ctrl+z` (None on Windows) | Suspend to background |
|
||||
| `app.editor.external` | `ctrl+g` | Open in external editor (`externalEditor`, `$VISUAL`, `$EDITOR`, Notepad on Windows, or `nano` elsewhere) |
|
||||
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows and WSL) | Paste image or text from clipboard |
|
||||
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows and WSL) | Paste files on macOS, images, or text from clipboard |
|
||||
|
||||
On native Windows, `app.suspend` has no default because Windows terminals do not support Unix job control. If you assign it manually, Pi shows a status message instead of suspending. WSL uses the normal `ctrl+z` and `fg` behavior.
|
||||
|
||||
### Sessions
|
||||
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `app.session.new` | *(none)* | Start a new session (`/new`) |
|
||||
| `app.session.tree` | *(none)* | Open session tree navigator (`/tree`) |
|
||||
| `app.session.fork` | *(none)* | Fork current session (`/fork`) |
|
||||
| `app.session.resume` | *(none)* | Open session resume picker (`/resume`) |
|
||||
| `app.session.new` | None | Start a new session (`/new`) |
|
||||
| `app.session.tree` | None | Open session tree navigator (`/tree`) |
|
||||
| `app.session.fork` | None | Fork current session (`/fork`) |
|
||||
| `app.session.resume` | None | Open session resume picker (`/resume`) |
|
||||
| `app.session.togglePath` | `ctrl+p` | Toggle path display |
|
||||
| `app.session.toggleSort` | `ctrl+s` | Toggle sort mode |
|
||||
| `app.session.toggleNamedFilter` | `ctrl+n` | Toggle named-only filter |
|
||||
@@ -161,7 +162,7 @@ This routing remains configurable through the ordinary action bindings. For exam
|
||||
| Keybinding id | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `app.tools.expand` | `ctrl+o` | Collapse or expand tool output |
|
||||
| `app.message.copy` | `ctrl+x` | Copy the selected message in `/tree`; otherwise copy the last assistant message, or the active fullscreen text selection when `fullscreenCopyOnSelect` is disabled |
|
||||
| `app.message.copy` | `ctrl+x` | Copy the selected message in `/tree`; in fullscreen mode, copy the active selection when `fullscreenCopyOnSelect` is `false`; otherwise copy the last assistant message. On OAuth sign-in screens, copy the sign-in URL |
|
||||
| `app.message.followUp` | `alt+enter` (`ctrl+q` on Windows and WSL) | Queue follow-up message |
|
||||
| `app.message.dequeue` | `alt+up` (`alt+q` on Windows and WSL) | Restore queued messages to editor |
|
||||
|
||||
@@ -192,48 +193,3 @@ Used inside the scoped models selector (opened via `/scoped-models`).
|
||||
| `app.models.toggleProvider` | `ctrl+p` | Toggle all models for the current provider |
|
||||
| `app.models.reorderUp` | `alt+up` | Move the selected model up in the cycle order |
|
||||
| `app.models.reorderDown` | `alt+down` | Move the selected model down in the cycle order |
|
||||
|
||||
## Custom Configuration
|
||||
|
||||
Create `~/.pi/agent/keybindings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"tui.editor.historyPrevious": "ctrl+p",
|
||||
"tui.editor.historyNext": "ctrl+n",
|
||||
"tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
|
||||
}
|
||||
```
|
||||
|
||||
Each action can have a single key or an array of keys. User config overrides defaults.
|
||||
|
||||
On native Windows, `app.suspend` has no default binding because Windows terminals do not support Unix job control. If you bind it manually, pi shows a status message instead of suspending. In WSL, the normal Linux `ctrl+z`/`fg` behavior still applies.
|
||||
|
||||
### Emacs Example
|
||||
|
||||
```json
|
||||
{
|
||||
"tui.editor.historyPrevious": "ctrl+p",
|
||||
"tui.editor.historyNext": "ctrl+n",
|
||||
"tui.editor.cursorLeft": ["left", "ctrl+b"],
|
||||
"tui.editor.cursorRight": ["right", "ctrl+f"],
|
||||
"tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
|
||||
"tui.editor.cursorWordRight": ["alt+right", "alt+f"],
|
||||
"tui.editor.deleteCharForward": ["delete", "ctrl+d"],
|
||||
"tui.editor.deleteCharBackward": ["backspace", "ctrl+h"],
|
||||
"tui.input.newLine": ["shift+enter", "ctrl+j"]
|
||||
}
|
||||
```
|
||||
|
||||
### Vim Example
|
||||
|
||||
```json
|
||||
{
|
||||
"tui.editor.cursorUp": ["up", "alt+k"],
|
||||
"tui.editor.cursorDown": ["down", "alt+j"],
|
||||
"tui.editor.cursorLeft": ["left", "alt+h"],
|
||||
"tui.editor.cursorRight": ["right", "alt+l"],
|
||||
"tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
|
||||
"tui.editor.cursorWordRight": ["alt+right", "alt+w"]
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user