[twarp 06] tab rename: bind ⌘⌥R to rename the active tab#65
Conversation
Attach the default key chord `cmdorctrl-alt-r` (⌘⌥R on macOS, Ctrl+Alt+R on Linux/Windows) to the existing, previously-unbound `workspace:rename_active_tab` EditableBinding. This lights up the keyboard path into the inline tab-rename flow that double-click already triggers — same editor, same pre-selected text, same Enter-commits / Escape-cancels semantics. No new action, handler, state, render path, persistence, telemetry, or feature flag. The binding stays editable, so it remains remappable on the keybindings settings page and surfaces ⌘⌥R on the Rename Tab menu entry via CustomAction::RenameTab. Also add a zero-tab bounds guard to `rename_tab`, which indexed `self.tabs[index]` before `rename_tab_internal`'s existing guard ran. This guarantees PRODUCT §7 (the shortcut is a no-op with no crash when there is no tab to rename) and also hardens the existing Rename Tab menu path. Conflict check (TECH §2): `cmd-alt-r` is unbound on macOS, so the ⌘⌥R default is conflict-free on the primary target. On Linux/Windows the same `ctrl-alt-r` chord is also bound to ResumeConversation, but that binding requires the CAN_RESUME_CONVERSATION_KEY context flag, which is gated on FeatureFlag::AIResumeButton AND an active conversation in error state. Post-AI-removal (twarp 2c-d) no conversation is ever created and `was_manually_cancelled` is hardcoded false, so the flag is provably never set — the shadow is dead. The binding is remappable as the escape hatch regardless. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reconcile STATUS to git (spec #64 merged) and record the impl PR. Tick the single sub-phase and note the resolved §2 conflict check (macOS ⌘⌥R conflict-free; Linux/Windows ⌃⌥R shadow dead post-AI-removal). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…g_to_keystroke
The previous approach (`EditableBinding::with_key_binding("cmdorctrl-alt-r")`
on `workspace:rename_active_tab`) panicked the app at startup:
thread 'main' panicked at app/src/app_menus.rs:122:13:
action should have a name: RenameTab
Root cause: `with_custom_action` and `with_key_binding` write the *same*
`EditableBinding::trigger` field. Calling `with_key_binding` last overwrote
`Trigger::Custom(RenameTab)` with a keystroke trigger. The macOS menu builds
its "Rename Tab" item via `description_for_custom_action(RenameTab)`, which
only resolves a binding whose `trigger`/`original_trigger` is
`Trigger::Custom(RenameTab)`. With that clobbered the lookup returned `None`,
tripping `default_name`'s `debug_assert!`.
Fix: revert the `with_key_binding` call (so the binding keeps its custom
trigger) and assign the default chord in `custom_tag_to_keystroke` instead —
the same `CustomAction -> Keystroke` map used by every other menu shortcut
(NewTab, Copy, ShowSettings, ...). It feeds the runtime converter on both
macOS (`register_default_keystroke_triggers_for_custom_actions`) and
Linux/Windows (`convert_custom_triggers_to_keystroke_triggers`), so ⌘⌥R
(Ctrl+Alt+R) fires RenameActiveTab while the menu still resolves correctly.
Verified by launching warp-oss: process survives the startup window
(menu build) with no panic on stderr. fmt + clippy clean. The zero-tab
guard from the first commit is unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…chanism The merged spec prescribed `EditableBinding::with_key_binding(...)`, which panics the menu builder (it clobbers `Trigger::Custom(RenameTab)`). Update §1 to document the correct mechanism — register the default chord in `custom_tag_to_keystroke` — and to require launching the app for validation, since the panic escaped build/clippy/test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update: fixed a startup panic found in manual testingRunning Cause: Fix (commits Re-verified: launched Please still run the PRODUCT.md smoke test (⌘⌥R rename / Escape revert / terminal-focused) before merging. |
Implements feature 06 (tab rename shortcut). Specs merged in #64.
What changed
Two files, Rust only:
app/src/workspace/mod.rs— attach the default chordcmdorctrl-alt-rto the existing, previously-unboundworkspace:rename_active_tabEditableBinding. This is the entire headline feature: it lights up the keyboard path into the inline tab-rename flow that double-click already triggers. Same editor, same pre-selected title, same Enter-commits / Escape-cancels / blur-commits semantics (PRODUCT §1–§4). No new action, handler, state, render path, persistence, telemetry, or feature flag. The binding stays editable, so it remains remappable on the keybindings settings page and surfaces ⌘⌥R on the Rename Tab menu entry viaCustomAction::RenameTab(PRODUCT §10).app/src/workspace/view.rs— add a zero-tab bounds guard torename_tab, which indexedself.tabs[index]beforerename_tab_internal's existing guard ran. This guarantees PRODUCT §7 (the shortcut is a no-op, no crash, when there's no tab to rename) and also hardens the pre-existing Rename Tab menu path.Conflict analysis (TECH §2)
cmd-alt-rbinding exists anywhere inapp/orcrates/(thecmdorctrl-alt-right/ctrl-alt-righthits are the arrow key — a different chord).ctrl-alt-rchord is bound toTerminalAction::ResumeConversation(terminal/view/init.rs:180), but that binding requires theCAN_RESUME_CONVERSATION_KEYcontext flag. That flag is gated onFeatureFlag::AIResumeButtonand an active conversation in error state (terminal/view.rs:25950). Post-AI-removal (feature 02 / twarp 2c-d), no conversation is ever created andwas_manually_cancelledis hardcodedfalse— the in-tree comment literally reads "resume button cannot fire." So the flag is never set and the shadow can't occur. The binding is remappable as the escape hatch regardless. Removing the defunctResumeConversationbinding is feature-02 cleanup, out of scope here.Edge cases verified (TECH §3)
rename_tab_internalclears and re-insert_selected_texts into the single sharedtab_rename_editor; no second editor.tab.rs) and vertical (vertical_tabs.rs) render paths key offis_tab_being_renamed(), so the inline editor renders in both layouts. No code change needed.Testing
cargo fmt --check✅ · clippy--workspace --all-targets --tests -D warnings✅ · clang-format ✅wgslfmt— N/A (no.wgslfiles in the diff).cargo testrun surfaced 5 failures, all pre-existing test-isolation artifacts in unrelated subsystems — autoupdate/telemetry/settings — that pass under nextest's process isolation; none are touched by this change.)Smoke test
See
roadmap/06-tab-rename/PRODUCT.md→ Smoke test. Headline: open 3 tabs, focus tab 2, press ⌘⌥R, type a name, Enter → tab 2 renamed; ⌘⌥R then Escape → reverts; works with a terminal runningtopfocused; settings page + Rename Tab menu show ⌘⌥R.Specs
roadmap/06-tab-rename/PRODUCT.mdroadmap/06-tab-rename/TECH.md🤖 Generated with Claude Code