mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-22 03:03:56 +00:00
* feat(cli): Ctrl+B promote keybind — wire UI to PR-2's promoteAbortController (#3831 PR-3 of 3) Final piece of the foreground → background promote feature. PR-1 (#3842) landed the `signal.reason` foundation; PR-2 (#3894) wired `shell.ts` to detect a `{ kind: 'background' }` abort, snapshot output, register a `BackgroundShellEntry`, and stash the promote `AbortController` on `TrackedExecutingToolCall`. This PR exposes the user-visible surface: pressing Ctrl+B during an in-flight foreground shell command transfers ownership to a background task the user can inspect via `/tasks` or stop via `task_stop`. ## Changes - `keyBindings.ts`: new `Command.PROMOTE_SHELL_TO_BACKGROUND` bound to `Ctrl+B`. JSDoc explains the no-shell-running no-op semantics. - `useReactToolScheduler.ts`: project `promoteAbortController` from the core's `ExecutingToolCall` through `TrackedExecutingToolCall` so the React layer (AppContainer keypress handler) can find it by callId without re-plumbing through the scheduler. - `AppContainer.tsx`: `handleGlobalKeypress` gains a `PROMOTE_SHELL_TO_BACKGROUND` branch that walks `pendingToolCallsRef.current` (the ref, not the destructured array — keeps the deps list stable so the handler isn't re-bound on every tool-call status update), finds the executing tool call with a defined `promoteAbortController`, calls `.abort({ kind: 'background' })`, and returns early. No-op when no foreground shell is executing — Ctrl+B then falls through to the input layer's existing cursor-left binding. - `keyboard-shortcuts.md`: documents Ctrl+B with explicit fall-through behavior so the conflict with the prompt-area cursor-left binding is intentional + understandable. ## Tests - `keyMatchers.test.ts` (+1): Ctrl+B positive / bare-b + meta+b + Ctrl+other negatives. - `AppContainer.test.tsx` (+2): - **Ctrl+B promotes** — pendingToolCalls includes an executing shell with a stubbed `AbortController` + spy; firing Ctrl+B asserts `abort({ kind: 'background' })` is called once. - **Ctrl+B no-op** — empty `pendingToolCalls` + Ctrl+B must NOT throw (pins the safety contract for the typing-mid-prompt case where the input layer's own Ctrl+B should still fire). - 37/37 keyMatchers + 58/58 AppContainer pass; tsc + ESLint clean. ## E2E (manual, PR description guidance) The unit / integration tests cover the keybind → abort wiring and the promote handler's downstream behavior (PR-2's tests). Real-PTY E2E is intentionally manual since headless test infrastructure doesn't drive a real shell child + Ctrl+B keystroke; documented in the PR description checklist. Closes the 3-PR sequence for #3831 (Phase D part b of #3634). * fix(cli): #3969 review wave — broadcast comment + debug log + redundancy 5 #3969 review threads addressed: - **AppContainer.tsx Ctrl+B handler**: documented the KeypressContext.broadcast caveat (after `return`, the same Ctrl+B is still dispatched to text-buffer cursor-left + DebugProfiler; visible cursor-left side effect is cosmetic) so future readers understand why the prompt cursor moves on a successful promote. Added `debugLogger.debug` calls on both branches (matched callId on success; streamingState + pendingToolCalls.length on no-op fall-through) so "Ctrl+B doesn't work" reports are debuggable. - **useReactToolScheduler.ts TrackedExecutingToolCall**: dropped the redundant `pid?` and `promoteAbortController?` declarations — both come through the `& ExecutingToolCall` intersection unchanged. Fixed the JSDoc that wrote `{ kind: 'background', shellId }`: callers don't generate `shellId` (it's optional on the abort-reason union and `handlePromotedForeground` produces it downstream). The corresponding executing branch in `toolCallsUpdateHandler` no longer projects pid / promoteAbortController explicitly — `...coreTc` already spreads them; the explicit-undefined clearing in the non-executing branch is also dropped (those fields aren't on coreTc when status !== 'executing', so `...coreTc` doesn't carry them). - **AppContainer.test.tsx**: replaced two `as unknown as Key` double-casts with direct `: Key` annotations on the literal — the object already conforms to the Key interface, double-cast was bypassing type safety needlessly. Tests: 37/37 keyMatchers + 58/58 AppContainer pass; tsc + ESLint clean. No behavior change beyond the new debug log lines. * fix(cli): #3969 wave — tool-name guard + non-shell test + defensive clear 3 #3969 review threads addressed; 1 deferred: - AppContainer.tsx: Ctrl+B `find()` predicate now also checks `tc.request.name === ToolNames.SHELL` before matching the executing tool call. Defense-in-depth — today only the shell tool wires `promoteAbortController`, but a future copy-paste / type confusion that adds the property to a non-shell tool would otherwise let Ctrl+B mistakenly fire `abort({kind:'background'})` on a tool whose service has no promote-handoff handler. - useReactToolScheduler.ts: re-added explicit `pid: undefined` and `promoteAbortController: undefined` to the non-executing return. Previously dropped on the assumption that `...coreTc` doesn't carry these fields when the status isn't `executing` — true today, but the explicit clearing is defense-in-depth against a future core change that adds either field to a non-executing status type (would surface as a stuck PID display or a Ctrl+B handler that matches a no-longer-executing tool call). - AppContainer.test.tsx: replaced the placeholder "no-op when no pending tool calls" framing on the empty-array case (it does exercise the `executing-status` predicate but NOT the tool-name guard) with TWO tests: 1. existing empty-array no-throw test (renamed for clarity) 2. NEW: executing non-shell tool with a hostile-shape `promoteAbortController` — asserts `abortSpy` is NOT called. This is the regression test for the new tool-name guard above. Tests: 61/61 AppContainer.test.tsx pass; tsc + ESLint clean. Deferred to follow-up (replied + tracked): - `debugLogger.debug` is file-only; success-path "agent unblocks + next message says 'promoted to bg_xxx'" is the user-visible signal. Adding a synthetic history item or stderr line for the gap between keypress and agent message conflicts with Ink rendering and is better as a focused UX PR. * test(cli): pin inheritance of pid + promoteAbortController via type assertions #3969 review: the earlier "redundant declaration" review removed the explicit `pid?: number` and `promoteAbortController?: AbortController` from `TrackedExecutingToolCall`, relying on the `& ExecutingToolCall` intersection to inherit them. Current review flags the type-safety regression: if core renames or removes either field, the React-side build won't catch it locally — Ctrl+B handler silently breaks at runtime. Compromise: keep the type minimal (no re-declaration noise the prior review flagged) but add compile-time `extends keyof ExecutingToolCall` assertions that fail loudly + locally if either field disappears. The assertions are evaluated at compile time and zero-cost at runtime; the dummy `const` pins them so they aren't dead code. 61/61 AppContainer tests pass; tsc clean.
11 KiB
11 KiB
Qwen Code Keyboard Shortcuts
This document lists the available keyboard shortcuts in Qwen Code.
General
| Shortcut | Description |
|---|---|
Esc |
Close dialogs and suggestions. |
Ctrl+C |
Cancel the ongoing request and clear the input. Press twice to exit the application. |
Ctrl+D |
Exit the application if the input is empty. Press twice to confirm. |
Ctrl+L |
Clear the screen. |
Ctrl+O |
Toggle compact mode (hide/show tool output and thinking). |
Ctrl+S |
Allows long responses to print fully, disabling truncation. Use your terminal's scrollback to view the entire output. |
Ctrl+T |
Toggle the display of tool descriptions. |
Ctrl+B |
While a foreground shell command is running: promote it to a background task. The child keeps running, the agent's turn unblocks, and the shell appears in /tasks + the Background tasks dialog. No-op when no shell is executing — Ctrl+B then falls through to its prompt-area binding (cursor-left). |
Alt/Option+M |
Toggle Markdown output between rich rendered previews and raw/source mode. On macOS, the terminal must send Option as Meta. |
Shift+Tab (Tab on Windows) |
Cycle approval modes (plan → default → auto-edit → yolo) |
Input Prompt
| Shortcut | Description |
|---|---|
! |
Toggle shell mode when the input is empty. |
? |
Toggle keyboard shortcuts display when the input is empty. |
\ (at end of line) + Enter |
Insert a newline. |
Down Arrow |
Navigate down through the input history. |
Enter |
Submit the current prompt. |
Meta+Delete / Ctrl+Delete |
Delete the word to the right of the cursor. |
Tab |
Autocomplete the current suggestion if one exists. |
Up Arrow |
Navigate up through the input history. |
Ctrl+A / Home |
Move the cursor to the beginning of the line. |
Ctrl+B / Left Arrow |
Move the cursor one character to the left. |
Ctrl+C |
Clear the input prompt |
Esc (double press) |
Clear the input prompt. |
Ctrl+D / Delete |
Delete the character to the right of the cursor. |
Ctrl+E / End |
Move the cursor to the end of the line. |
Ctrl+F / Right Arrow |
Move the cursor one character to the right. |
Ctrl+H / Backspace |
Delete the character to the left of the cursor. |
Ctrl+K |
Delete from the cursor to the end of the line. |
Ctrl+Left Arrow / Meta+Left Arrow / Meta+B |
Move the cursor one word to the left. |
Ctrl+N |
Navigate down through the input history. |
Ctrl+P |
Navigate up through the input history. |
Ctrl+R |
Reverse search through input/shell history. |
Ctrl+Y |
Retry the last failed request. |
Ctrl+Right Arrow / Meta+Right Arrow / Meta+F |
Move the cursor one word to the right. |
Ctrl+U |
Delete from the cursor to the beginning of the line. |
Ctrl+V (Windows: Alt+V) |
Paste clipboard content. If the clipboard contains an image, it will be saved and a reference to it will be inserted in the prompt. |
Ctrl+W / Meta+Backspace / Ctrl+Backspace |
Delete the word to the left of the cursor. |
Ctrl+X / Meta+Enter |
Open the current input in an external editor. |
Suggestions
| Shortcut | Description |
|---|---|
Down Arrow |
Navigate down through the suggestions. |
Tab / Enter |
Accept the selected suggestion. |
Up Arrow |
Navigate up through the suggestions. |
Radio Button Select
| Shortcut | Description |
|---|---|
Down Arrow / j |
Move selection down. |
Enter |
Confirm selection. |
Up Arrow / k |
Move selection up. |
1-9 |
Select an item by its number. |
| (multi-digit) | For items with numbers greater than 9, press the digits in quick succession to select the corresponding item. |
IDE Integration
| Shortcut | Description |
|---|---|
Ctrl+G |
See context CLI received from IDE |