ADR-0006: Plain browser-style tab cycling (Ctrl+Tab)
Status: Active · Date: 2026-07-07
References
- ADR-0018: Consolidated browser focus & keyboard routing — refines this decision. Ctrl+Tab still cycles positionally with no MRU popup, but now targets the center pane regardless of which dock holds focus (
tranquil:show-next/previous-item-in-centerinstead of the plainpane:show-*-itembelow), and the browser-view re-dispatch has moved into a single consolidatedwebview-key-eventslistener. The Decision/Consequences below describe the original 2026-07-07 rebind; read them together with ADR-0018 for the current behavior.
Context
Ctrl+Tab / Ctrl+Shift+Tab invoked Pulsar’s MRU (most-recently-used) tab switcher: holding Ctrl popped up a modal overlay listing open tabs and cycled through them by recency of use,
committing the choice on Ctrl release. That is Atom/Pulsar’s editor-oriented default, but Tranquil
is browser-first — its tabs are predominantly web pages, and users expect the universal browser
convention: Ctrl+Tab → next tab, Ctrl+Shift+Tab → previous tab, cycling by tab position with
wraparound and no popup. This follows the container-tabs / browser-tab work
(ADR-0005) that is steadily making Tranquil’s tab strip
behave like a browser’s.
The plain commands already exist and already work: pane:show-next-item / pane:show-previous-item (backing Pane.activateNextItem() / activatePreviousItem()) do positional
cycling with wraparound and are already bound to other keys (cmd-}, ctrl-pagedown, etc.). The MRU
popup (the tabs package’s MRUListView) is only ever triggered by the *-recently-used-item commands, so nothing extra needs to render or suppress it.
Decision
Rebind Ctrl+Tab / Ctrl+Shift+Tab to the plain pane:show-next-item / pane:show-previous-item commands in the three app keymaps, dropping the two ^ctrl key-up bindings that committed the MRU
selection. The tabs package’s MRU switcher is left entirely untouched — it simply stops being
reached. Because a focused browser <webview> swallows the keystroke (Pulsar’s keymap never sees
it), the key is forwarded over IPC and dispatched to the same plain commands from the browser view’s webview-key-events handler, before its active-item guard, so cycling keeps working even when
keyboard focus stays behind in the previously-focused webview after a switch.
Options considered
- Option A: Repoint the app keymaps to the existing plain commands (chosen) — two-line change per
keymap plus the browser-view re-dispatch. Reuses commands that already ship and are already proven
(they power
cmd-}). No third-party code touched. Con: the MRU switcher is no longer reachable viaCtrl+Tab(see Consequences). - Option B: Flip the
tabs.enableMruTabSwitchingconfig off — thetabspackage’supdateTraversalKeybinds()already swapsCtrl+Tabtopane:show-next-itemwhen that setting is disabled. Rejected: its guard bails out when another source already bindsCtrl+Tab, and Tranquil’s own keymaps do bind it — so the swap is unreliable. It also would not cover the browser webview’s manual re-dispatch path, leaving focused browser tabs still showing the popup. - Option C: Modify or remove the MRU code in the
tabspackage — Rejected: violates the “never modify third-party packages” rule and is unnecessary, since simply not dispatching the MRU commands already suppresses the popup.
Consequences
- Recency cycling via
Ctrl+Tabis gone. Cycling is now strictly positional (left→right) with wraparound. Users who relied on “jump back to the last tab” viaCtrl+Tablose that; theMRUListViewcode still lives in thetabspackage and could be re-bound or exposed behind a setting if demand returns — that is the re-evaluation trigger. - Consistent across focus contexts. Because the browser-view re-dispatch uses the same commands,
cycling behaves identically whether a browser page (focused
<webview>) or a native editor tab has focus. - Cross-platform. All three keymaps (
darwin,linux,win32) were updated; macOS is the primary target. - Other bindings unaffected.
cmd-{/cmd-},ctrl-pageup/ctrl-pagedown,cmd-alt-left/cmd-alt-rightalready mapped to the same plain commands and are unchanged.
Validation
The three keymap files parse cleanly (season CSON parser) and resolve ctrl-tab → pane:show-next-item, ctrl-shift-tab → pane:show-previous-item. The target commands are the same
ones already driving cmd-} et al., so behavior is exercised code. Final interactive confirmation
(Ctrl+Tab cycles with no popup, wraps at the ends, works from a focused browser page) is done by
reloading a window. Implementation touched tranquil-client keymaps and tranquil-browser/lib/tranquil-browser-view.js.