zellij: tmux-faithful keybinds (clear-defaults; only Ctrl-\ global)#21
Open
bddap-bot wants to merge 3 commits into
Open
zellij: tmux-faithful keybinds (clear-defaults; only Ctrl-\ global)#21bddap-bot wants to merge 3 commits into
bddap-bot wants to merge 3 commits into
Conversation
Owner: "zellij hijacks my Ctrl-p/n, Ctrl-f and friends." Stock zellij binds a
dozen Ctrl/Alt chords GLOBALLY (Ctrl-p/n/f/t/h/s/o/g/q, Alt-…) as mode-switches,
stealing them from the shell. The previous config rebound the prefix to C-\ but
left clear-defaults=false, so all those stock global binds still stole keys.
Switch to clear-defaults=true (nukes every stock bind, global and in-mode) and
rebind, tmux-style:
- ONE global capture: `Ctrl \` -> tmux mode (shared_except tmux/scroll/renametab,
so the prefix is free to send-prefix inside tmux mode and doesn't yank you out
of the text/scroll sub-modes). Every other Ctrl/Alt key now falls through to
the running program — verified with a headless pty: Ctrl-f/p/n/t reach a shell
verbatim while `Ctrl \` enters tmux mode.
- tmux-mode bindings modeled on tmux's default prefix table + ~/.tmux.conf:
% / " splits, hjkl+arrows focus, o next-pane, z zoom, x close, Space
next-layout, c/n/p/& tab new/next/prev/close, 1-9 tab jump, d detach,
, rename, [ copy-mode/scroll. Single keys (post-prefix). One-shots return to
normal; scroll/renametab get escape binds (clear-defaults wiped the stock ones,
so without them you'd be stuck in-mode).
- prefix prefix -> Write 28 (literal Ctrl-\) for send-prefix.
The spiral plugin block + layout are untouched (the 4e7076c re-tile fix stays
intact; its headless test still passes on the production artifacts).
IMPORTANT (separate from this file): zellij only captures `Ctrl \` when the
terminal delivers it via the kitty keyboard protocol (CSI-u). zellij's input
parser (vendored termwiz) has no decode mapping for the legacy bare 0x1c byte, so
a terminal that sends Ctrl-\ as 0x1c won't trigger the prefix. Our Alacritty has a
`ReceiveChar` override on Ctrl-Backslash (added for tmux) that forces exactly that
legacy byte — so until that's reconsidered, the prefix won't fire in Alacritty
(the Ctrl-p/n/f passthrough fix works regardless). Flagged to the owner.
Verified: `zellij setup --check` clean; home-manager build RC=0; headless pty
proves prefix capture (prefix c/1/3 create+jump tabs), passthrough of freed Ctrl
keys, and o/Space return-to-normal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
clear-defaults=true wiped zellij's stock mode escapes, and an unbound key in tmux mode is swallowed (you stay in-mode). So a stray prefix `Ctrl \` left you in tmux mode able to leave only by triggering one of the action keys. tmux drops back to normal on Esc / C-c after a stray prefix; this matches that. Found in the pre-merge review of bddap#21. Config parses (`zellij setup --check`). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… config) This binding looked load-bearing for the `Ctrl \` story — as if it forced the legacy 0x1c byte and starved zellij of the kitty CSI-u sequence its prefix needs. It does not. Alacritty's keyboard handler makes a `ReceiveChar` binding a no-op for byte output (`*suppress_chars.get_or_insert(true) &= action != ReceiveChar` leaves it unsuppressed, i.e. identical to no binding), and the legacy-vs-CSI-u choice is taken purely from terminal keyboard mode, never from a binding (verified against alacritty src v0.13–v0.15/master). So it neither blocked zellij's prefix nor was needed for tmux (Ctrl-\ produces 0x1c natively). Removed as cruft — no behavior change either way. The actual `Ctrl \`-in-both mechanism lives in the zellij keybinds + zellij's default `support_kitty_keyboard_protocol true`, not here. NOT live-tested (no headless terminal); the no-op claim is from Alacritty source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3bdd5d6 to
2a6cfae
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #19 (merged). Goal: make
Ctrl \behave like tmux's prefix in zellij, and keepCtrl \usable at both layers when tmux is nested inside zellij (or vice-versa). Three commits.1. zellij: tmux-faithful keybinds (
config.kdl) — the actual fixFixes the owner complaint: "zellij hijacks my Ctrl-p/n, Ctrl-f and friends." Stock zellij binds ~a dozen Ctrl/Alt chords globally (Ctrl-p/t/n/h/s/o/g/q, plus Alt-f/n/…) as mode-switches, stealing them from the shell. (Ctrl-f isn't itself a stock bind — Alt-f is — but
clear-defaultsfrees every Ctrl/Alt chord regardless, so Ctrl-f falls through too.) The previous config rebound the prefix toCtrl \but leftclear-defaults=false, so all the stock global binds still stole keys.clear-defaults=true— nuke every stock bind.Ctrl \→ tmux mode (shared_except "tmux" "scroll" "renametab", so the prefix can send-prefix inside tmux mode and doesn't yank you out of the text/scroll sub-modes). Every other Ctrl/Alt key now falls through to the running program.~/.tmux.conf:%/"splits, hjkl+arrows focus,o/z/x, Space=next-layout,c/n/p/&+1-9 tabs,ddetach,,rename,[scroll.scroll/renametabget explicit escape binds (clear-defaults wiped the stock ones).Ctrl \ Ctrl \→Write 28(literal Ctrl-) to the pane, matching.tmux.conf'sbind "C-\\" send-prefix. So a tmux running inside a zellij pane still gets its ownCtrl \prefix.Why this gives you
Ctrl \in both: zellij defaultssupport_kitty_keyboard_protocol true, so in a kitty-capable terminal (Alacritty) it receivesCtrl \as a kitty CSI-u sequence and the prefix fires. tmux doesn't request the kitty protocol, so it keeps receivingCtrl \as the legacy 0x1c byte and its prefix fires too. The two coexist.2. zellij: Esc / Ctrl-c aborts the tmux-mode prefix (
config.kdl)Caught in the pre-merge review. With
clear-defaults=truean unbound key in tmux mode is swallowed (you stay in-mode), so a stray prefix used to strand you in tmux mode with only the action keys as a way out. NowEsc/Ctrl cdrop back to normal, like tmux after a stray prefix.3. alacritty: drop an inert
ReceiveCharbinding on Ctrl-Backslash (alacritty.toml)Cruft cleanup, not a functional fix — flagging the honest story because my first pass got it wrong. I initially thought this binding forced the legacy 0x1c byte and starved zellij of the CSI-u sequence. It doesn't: Alacritty's keyboard handler makes a
ReceiveCharbinding a no-op for byte output (*suppress_chars.get_or_insert(true) &= action != ReceiveCharleaves it unsuppressed = same as no binding), and the legacy-vs-CSI-u choice is taken purely from terminal keyboard mode, never from a binding (verified against Alacritty source v0.13–v0.15/master). So it neither blocked zellij nor was needed for tmux. Removed as dead config; no behavior change.Testing — verified vs not
zellij setup --checkpasses on the renderedconfig.kdl(real zellij 0.43.1; confirmed it actually parses via a broken-KDL negative control that exits 1).alacritty.tomlparses clean (pythontomllib).Write 28== 0x1c == Ctrl-. The AlacrittyReceiveCharno-op claim is read straight from Alacritty source; the zellij CSI-u requirement is zellij-org/zellij#4509. Reviewed by a fan-out reviewer loop (correctness/byte-protocol, KDL, taste) — that loop is what caught both the missing Esc escape and the Alacritty misdiagnosis.support_kitty_keyboard_protocolstays at its defaulttrue. If it's ever set false, zellij would get the 0x1c byte, which its input parser doesn't decode asCtrl \(the #4509 failure) — and no Alacritty setting fixes that.