aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/ipc/tests (follow)
Commit message (Collapse)AuthorAge
* sl0p: --purpose flag and tab-level purposeuser2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Completes the two pieces deferred from the first workspace-hints pass. `zellij run --purpose X` / `zellij action new-pane --purpose X` tag a pane at spawn time, which is what an agent wants for panes it creates itself; the OSC wrapper still works for programs that declare their own role. Not supported with --in-place, which replaces another pane rather than being a pane of its own: clap rejects the combination rather than accepting a flag that would do nothing. `tab name="work" purpose="agent-work"` gives a whole tab a role, reported by `list-tabs --json`. It rides the tab's ROOT layout node, reusing the pane field because a tab's root is the tab container and never itself a pane -- asserted by a test for the tightest case (a tab holding exactly one pane), since a leak there would silently mislabel a pane. The interesting part is why the flag first shipped broken. There are TWO protobuf boundaries -- the plugin API and the client->server IPC contract -- and a CLI flag must cross the second one. Defaulting the field in the conversion (what "no protoc" usually forces) compiles cleanly and then silently drops the value in transit, so --purpose parsed, printed a pane id, and did nothing. Fixed by adding the field to both contracts by hand, in the .proto AND the committed generated prost, kept in lockstep so a future regeneration reproduces it: protoc is only needed to regenerate, not to build. Both boundaries now have a round-trip test, and the IPC one was confirmed to fail when the wire read is removed. Sanitising moved to Grid::set_authoritative_purpose, the single choke point every out-of-band source passes through, after the CLI path was observed delivering `bad purpose; rm -rf /` intact into list-panes --json.
* sl0p: per-pane workspace hints (purpose=)user2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Implements the zellij half of sl0p/workspace-hints-proposal.md: a pane can carry an opaque agent-facing hint for what it is FOR, so a project can ship a layout that an agent is able to navigate instead of guessing. zellij never interprets a purpose. The consuming agent owns the entire vocabulary, which is what keeps this to one string threaded along the existing status_bar path rather than a policy engine, and lets the vocabulary change without a rebuild. Two ways in, because declared panes and agent-created panes are different: layout: pane name="server" purpose="dev-server" in-band: printf '\033]5577;1;purpose;agent:build\033\\' The second exists because tagging at spawn time would mean threading a field through 28 SpawnTerminal call sites, and a new action variant is impossible while protobuf enums cannot be regenerated. Wrapping the command costs one printf. A declared purpose outranks an in-band one and cannot be overridden or cleared by it. OSC arrives from whatever the pane happens to be showing, so otherwise a `cat hostile.txt` in the human's editor pane could relabel it as the agent's scratch pane and invite an agent to run commands where the human is working. A layout is written by a human in a file they can read; in-band data only fills a blank. Exposed on PaneListEntry (`list-panes --json`) rather than PaneInfo, which crosses the plugin protobuf API we cannot regenerate; resolved in the screen thread where panes live rather than via route.rs's per-pane PTY round-trips. Values are sanitised to a bounded [A-Za-z0-9_.:/-] token at both entry points, because a purpose is never rendered -- it is matched against and pasted into consumers' shell and JSON pipelines. Verified end to end rather than by inspection: purposes from a layout appear in list-panes --json against the right pane ids, an agent-spawned pane tags itself, a declared purpose survives an in-band override attempt, all of it comes back after kill + resurrect, an unknown pane property is still a parse error, and a layout with no purpose leaves dump-layout unchanged.
* sl0p: separate the hover resize hint from the hover highlightuser2026-08-12
| | | | | | | | | | | | | | | | | | Upstream's mouse_hover_effects governs two unrelated things: the frame highlight on hover, and the "Ctrl <MouseScroll> or <drag borders> to resize" hint. Its own comment in default.kdl admits as much. So silencing a beginner reminder you have outgrown also costs you a highlight that stays useful indefinitely. mouse_hover_help_text (default true) gates only the hint. One line in execute_send_to_terminal; the highlight is set in execute_update_hover and is untouched. Config-file only, deliberately. The option has no protobuf slot, so it does not cross the client/server IPC contract -- the roundtrip test asserts exactly that, with the fixture set to None and a comment explaining why. It still works from the config file because the server parses the file itself and Options::merge keeps the file value when the client sends None; a CLI flag would be silently ignored.
* sl0p: add close_if_focused to LaunchOrFocusPluginuser2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | Upstream's action focuses an already-running plugin, so a chord bound to it can only ever open one -- there is no way to dismiss with the same key. This cannot be fixed in a plugin. Keybindings are resolved into actions in route.rs before a key reaches a pane, so the launching chord never arrives at the plugin. intercept_key_presses does not help either: the intercept lives in screen.rs and only sees keys that already became Action::Write, i.e. keys destined for a pane. Confirmed empirically -- an intercepting build received Ctrl-u but never Ctrl-;. Closes only when the plugin is the focused pane in the client's ACTIVE tab, so the chord cannot close whatever pane the user happens to be on. A plugin that exists but is hidden behind a floating-layer toggle, or is focused in a different tab, is revealed or brought over as before. Defaults to false, so every existing binding is unaffected. Config-only, with no protobuf representation: defaulted at both boundaries and dropped when an action crosses the plugin API, so no prost regeneration is needed. The 24 snapshot lines are the new field appearing in serialised keybind dumps.
* Support the Kitty Image Protocol (#5428)Aram Drevekenin2026-07-31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * initial implementation - kinda working * tests and fixes * fix bounds * tests and compatibility fixes * fix: cursor scroll, clears, deletes, key tolerance, and host id range * fix: keep images alive across resize, relayout and history scroll * anchor to lines, not pixels * fix image/text alignments * config to allow disabling * fix pinned pane issue * never let host graphics replies reach the keyboard parser * fix nested session * properly handle fullscreening a pane * rustfmt * cleanup of ignored test * add pr
* More dependency upgrades for debian (#5421)Aram Drevekenin2026-07-29
| | | | | | | | | | | * upgrade insta, rand, sha2, strum, thiserror, tokio-tungstenite, toml, which; drop unused semver and typetag * upgrade sysinfo to 0.39.5, bump toolchain (msrv) to 1.95.0 * remote legacy yaml config converter and thus drop serde_yaml * upgrade unicode-width to 0.2.2 * fix(tests): run ipc roundtrip test on a larger stack
* Nested session handling (#5417)Aram Drevekenin2026-07-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix: theme query and updated pixel dimensions * add no-ui-fullscreen key/action/capability * protocol core * integration test harness * fix integration tests * fix flaky tests * nested ui (dimming) and directional focus initial implementation * integration tests for nested ui dimming and directional focus * initial full screen nesteed implementation * fix: keep hidden floating panes hidden across nested no-ui fullscreen * fix integration tests * no ui fullscreen integration tests * hardening behavior/tests * fix(nested): re-derive descend/dim on host tab switch and new-tab so clicking dimmed chrome ascends * initial modal implementation * initial ui improvements * fix integration tests * improve nested selection ui * nested session modal refactoring and tests * improve integration test speed somewhat * some ui adjustments * simplify full/auto nested session handling * hints in compact-bar * guest stdin leak fix * allow floating panes to be fullscreen * make nested session handling configurable * protocol reannounce * refactor: naming confusion * improve ux somewhat * rustfmt * merge fixes * improve integration test rate limiting (fix ci) * add pr
* feat(config): add mouse_scroll_resize option (#5283)WeZZard2026-07-17
|
* fix(config): allow binding theme actions in config.kdl (#5302)Truffle2026-07-10
| | | | | | | | | | | | | | | | | | | | | | | * fix(config): allow binding theme actions in config.kdl ToggleTheme, SetDarkTheme and SetLightTheme work from the CLI (`zellij action toggle-theme`) but the keybinding parser rejected them with "Unsupported action", so they could not be bound in config.kdl. The inner `parse_kdl_action_arguments!` macro already knew these actions, but the main `match action_name` arm that dispatches to it had no entry for them, so they fell through to the unsupported-action error. Add the missing parse arms, and the matching `to_kdl` serialization arms so the bindings round-trip. Closes #5297 * add actions to round trip tests * add pr --------- Co-authored-by: Aram Drevekenin <aram@poor.dev>
* Allow creating panes/tabs from the CLI without changing focus to them (#5346)Aram Drevekenin2026-07-09
| | | | | | | | | | | * feat: allow opening panes and tabs from the cli without focusing them * rustfmt * fix flake * rustfmt * add pr
* Stacked lists (#5331)Aram Drevekenin2026-07-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * initial implementation * improve ui * fix: stacked resize interaction * title list boundaries fix * fix BEL * mouse parity * float/embed + bulk-op features * fix in-place bug * improve ui * config live reload * improve ui * fix issues, add exit status * fix for serialization * fix tests * integration tests * comments * refactor: duplicate title logic * refactor: consolidate logic * fix: flaky tests * add a stacked swap layout * rustfmt * fix e2e * add pr
* Title frames (#5318)Aram Drevekenin2026-06-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * initial implementation * improve single line title design * hint text plugin infra * add proto regen task * display alt text in status bar * don't display text with full frames * style alt hover text * fix + style control own pane hover * make multiplayer indications responsive * update snapshots * plugin api * single pane as tab * better scroll styling * fix tests * tab-bar plus hover * plugin surface tests * integration tests * adjust all integration tests * reduce hover noise * add pane id to in place * more integration tests * style: rustfmt * update plugin assets * update assets and snapshots * add pr
* Mobile layout (#5241)Aram Drevekenin2026-06-10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * phase 2+3 * initial mobile plugin (phases 4 + 5 + 6) * some bugfixes * implement stage 7 * mobile interface improvements * improve mobile pane/tab picker * more ui improvements and fixes * various mobile fixes * some mobile fixes * mobile keyboard triggering fix * some cleanups * initial plugin keyboard implementation * improve keyboard hit zones * improve keyboard * pinch resize * pinching fixes * implement scrolling + panning * initial keyboard resizing * fix: mobile first render issues * keyboard responsiveness * fix some issues with the keyboard * implement fit * fix mobile scrolling * add tilde cell to compact * improve mobile keyboard * fix starting mobile terminal font to natural keyboard size * fix mobile resize blank screen flash * shadow focus for mobile * more keyboard fixes * improve mobile status bar * fix: render plugins to mobile clients * allow opening new panes/tabs from the mobile plugin * allow configuring * fix dot slash * improve mobile native soft keyboard interaction * switch to native keyboard - initial implementation * dirty hacks, but phone keyboard works now * adjust keyboard help strip * fix cursor in mobile * fix keyboard and help line * rename keyboard to modifier bar * allow starting new session * make clicking session name bring us to new session menu * allow switching to desktop from the mobile ui * mobile welcome screen initial implementation * mobile welcome screen fixes * various welcome screen fixes * more mobile fixes * moar mobile fixes * mobile ui redesign * fix: swallowed backspace bug * switch session screen improvement * touch up some interfaces * refactor: move mobile state to own struct * refactor: move fit resizing to the server * remove dead flash code * some cleanups * refactor: clear fit on close * refactor: improve fit api * refactor: pane sync functions * refactor: mouse * refactor: break into modules * some cleanups for the sessions screen * fix scrolling and other stuff * refactor: sessions screen * refactor: panes screen * refactor: new session screen * refactor: menu screen * refactor: render * cleanups * refactor: plugin structure * remove unused welcome screen path * Rename api * refactor input.js * cleanup useless comments * fit/mobile refactoring * take out the garbage * remove more comments * remove mobile flash on startup/attach * fix: various mobile startup issues * fix space bugs * cleanup * rustfmt * fix windows build * adjust modifier bar ui * add pr
* Support CSI2031 (dark/light theme switching) + remove STDIN cache to avoid ↵Aram Drevekenin2026-04-28
| | | | | | | | | | | | | | | | | | | | | | | | | | | stale color queries (#5105) * initial phase 1 implementation * various fies * some fixes * fix fragmented stdin cases * some fixes * renaming * guard against old clients * implement csi 2031 * allow toggling theme with actions * rustfmt * fix: finalize trailing characters in ansi parser as well * add pr
* fix: respect --name flag when creating new panes (#4979)divens2026-04-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix: respect --name flag when creating and renaming panes Three issues fixed: 1. Pane creation: --name was silently discarded for default shell panes because use_terminal_title was true. Now user-provided names take priority. Also pass initial_pane_title as pane_name to TerminalPane constructor (was hardcoded to empty string). 2. CLI rename without --pane-id: was routed through PaneNameInput which appends to existing name. Now uses a dedicated RenameActivePane action that fully replaces the name, working for any name length including single characters. 3. Interactive rename: entering rename mode preserves the existing name for editing (append/backspace). Esc reverts to the name before rename mode was entered. Adds 28 tests covering rename semantics, interactive editing, undo, OSC title interaction, and a wire-level IPC round-trip test. * refactor: route active-pane rename via Option<PaneId> Replace the dedicated Action::RenameActivePane variant with an Option<PaneId> on the existing Action::RenamePaneByPaneId. route.rs dispatches None to the server-internal ScreenInstruction::RenameActivePane and Some(id) to the existing RenamePaneWithPaneId path. Drops all proto/conversion boilerplate for the removed variant: plugin API additions, IPC tag 137, and both directions of the wire conversion. --------- Co-authored-by: divens <divens.dev@gmail.com>
* Layout string flag (#4956)Aram Drevekenin2026-03-30
| | | | | | | | | * allow sending a stringified layout with --layout-string * add --tab-id to all the things * fix windows tests * add pr
* CLI focus-pane-id and are-floating-panes-visible actions (#4926)Aram Drevekenin2026-03-27
| | | | | | | | | * add zellij action focus-pane-id * zellij action are-floating-panes-visible * fix e2e tests * add pr
* Ansi dump support (#4848)Aram Drevekenin2026-03-14
| | | | | | | | | | | | | | | | | | | | | * add missing pane-id and tab-id arguments to all cli actions * rustfmt * dump-screen --ansi * edit-scrollback --ansi * add --ansi to subscribe * add tests for ansi additions * add ansi render report to plugins * rustfmt * fix e2e tests * add pr
* Add `--pane-id` and `--tab-id` to all relevant CLI commands (#4846)Aram Drevekenin2026-03-13
| | | | | | | | | | | * add missing pane-id and tab-id arguments to all cli actions * rustfmt * fix tests * update e2e snapshots * add pr
* Focus follows mouse and mouse clickthrough (#4836)Aram Drevekenin2026-03-11
| | | | | | | | | * implement focus follows mouse * mouse click through * rustfmt * add pr
* allow dumping screen to STDOUT as well (#4823)Aram Drevekenin2026-03-09
|
* feat(cli): add --pane-id option to dump-screen action (#4598)Yacine Hmito2026-03-09
| | | | | | | | | | | | | | | | | * feat(cli): add --pane-id option to dump-screen action Adds the ability to dump a specific terminal pane's content by passing `--pane-id <ID>` to the `dump-screen` CLI action. When omitted, the existing behavior of dumping the focused pane is preserved. This enables coding agents running inside Zellij to inspect the content of other panes programmatically, without needing complex workarounds. Prior art: https://github.com/theslyprofessor/zellij-pane-tracker, whose design complexity is due to current limitations that this PR addresses. * address review * improve man page entry
* Allow subscribing to pane viewport updates (renders) from the CLI (#4814)Aram Drevekenin2026-03-07
| | | | | | | | | | | * initial subscribe implementation * tests for subscribe * update cli help * rustfmt * add pr
* feat: add per-pane default foreground/background color support (#4737)Karl Bunch2026-03-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: add per-pane default foreground/background color support Add per-pane default foreground and background colors, configurable through four surfaces: - OSC 10/11 escape sequences (set/query) and OSC 110/111 (reset) - CLI action: zellij action set-pane-color --pane-id <id> --fg/--bg - Layout config: default_fg/default_bg properties on pane nodes - Plugin API: set_pane_color() SDK function and PaneInfo read-side Colors are applied at render time as a fallback when cells have no explicit foreground/background, without mutating stored grid data. Closes #4712 * refactor: address review feedback for pane color support - Extract adjust_styles_for_custom_bg_fg in output/mod.rs - Move color parsing (xparse_color) from tab into Grid - Move color serialization (ansi_code_to_color_string) into Grid - Pane trait now uses Option<String> for color getters/setters - Add colors to session serialization (dump-layout) - Add default_fg/default_bg to protobuf IPC schema to fix layout-in-session color loss - Update example layout with tab-bar and status-bar * fix stack overflow and ordering * rustfmt * update e2e snapshots --------- Co-authored-by: Karl Bunch <karl@karlbunch.com> Co-authored-by: Aram Drevekenin <aram@poor.dev>
* [Windows port PR8] feature: add Windows support (#4768)divens2026-03-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * feat: add Windows signal and process implementations - AsyncSignalListener: polls crossterm size at 100ms, tokio ctrl_c/break/close - BlockingSignalIterator: SetConsoleCtrlHandler + AtomicBool, polls size at 50ms - signal_process: GenerateConsoleCtrlEvent for Interrupt, TerminateProcess for Kill - Add windows-sys workspace dependency * feat: add Windows IPC support with named pipes and marker files - ipc_connect/ipc_bind/ipc_bind_async helpers with cfg gates for named pipes - Dual-pipe architecture on Windows: main pipe + reply pipe per connection to prevent IPC deadlock (half-duplex named pipe limitation) - is_ipc_socket returns is_file() on non-Unix for marker file discovery - ipc_bind creates empty marker file after binding named pipe on Windows - assert_socket split: cfg(unix) probes with ConnStatus, cfg(not(unix)) returns true to avoid deadlocking the server accept loop - Replace tokio UnixListener/UnixStream with interprocess tokio Listener/Stream in web server IPC for cross-platform support - Add interprocess tokio feature to workspace deps * feat: add Windows client support for input, server spawn, and stack size - Two-mode Windows input: crossterm event reader for native console, termwiz byte parser for terminal emulators (VT input mode) - cast_crossterm_key: convert crossterm KeyEvent to KeyWithModifier - ENABLE_VIRTUAL_TERMINAL_INPUT on Windows stdin for raw VT byte reading - Skip ANSI terminal query on Windows to unblock startup - spawn_server: CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP on Windows - 8MB stack trampoline in main() for Windows (default 1MB overflows) - 8MB stack for server worker threads (WASM compilation needs it) - Enable crossterm events and bracketed-paste features * test: make tests cross-platform for Windows - Socket tests: cross-platform IpcGuard/IpcName helpers with GenericNamespaced on Windows vs GenericFilePath/TempDir on Unix - Layout tests: normalize_layout_debug() replaces backslash separators in Debug output on Windows; gate env_var_expansion test with cfg(unix) - Setup tests: use PathBuf::join + display() instead of hardcoded / separators - Server OS tests: cross-platform command helpers (long_running_cmd, echo_cmd, stdin_reader_cmd) with CREATE_NO_WINDOW on Windows - zellij_exports: replace GenericFilePath with ipc_connect() helper * ci: add Windows build and test jobs with debug logging - Add build-windows job: cargo check --no-default-features on windows-latest - Add test-windows job: cargo test --no-default-features for utils/server/client - Enable manual workflow_dispatch trigger - Add debug log::info! calls in server startup, plugin loading, PTY spawning, and screen layout application for troubleshooting * feat: implement Windows stubs for shell, command hooks, and process listing Replace unimplemented!() stubs with working Windows implementations: - get_default_shell: reads $COMSPEC, falls back to cmd.exe - run_command_hook: uses cmd /C with RESURRECT_COMMAND env var - get_all_cmds_by_ppid: uses sysinfo to enumerate processes by parent PID * feat: implement Windows daemonize_web_server with detached process spawning Replace the `unimplemented!()` stub with a proper background process spawner that mirrors the existing `spawn_server` pattern: launch a foreground `zellij web --start` child with CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP, poll the TCP port to confirm it's listening, then exit the parent process. * feat: implement native ConPTY backend for Windows PTY Replace all WindowsPtyBackend stubs with a full ConPTY implementation: - CreatePseudoConsole with overlapped named pipes for IOCP-based async I/O (zero extra threads on the read path per pane) - CreateProcessW with PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE and proper UTF-16 command line quoting / environment block construction - ConPtyAsyncReader with lazy promotion from OwnedHandle to tokio NamedPipeServer (reactor not available at spawn time) - Per-terminal exit monitoring thread using WaitForSingleObject - ResizePseudoConsole for terminal resize, WriteFile for stdin, TerminateProcess / GenerateConsoleCtrlEvent for signals Note: for PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, the HPCON value must be passed directly as lpValue (not a pointer to it), matching the C convention where HPCON is void*. In Rust (windows-sys) HPCON is isize, requiring an explicit cast. See microsoft/terminal#6705. * chore: remove debug logging from ConPTY backend * fix: resolve Windows plugin directory and WASI mount errors Two Windows-specific fixes for the plugin system: 1. Replace colons with underscores in URL-derived plugin directory names (e.g. "zellij:tab-bar" -> "zellij_tab-bar"). Colons are illegal in Windows path components, causing OS error 123 on plugin dir creation. 2. Use FILE_FLAG_BACKUP_SEMANTICS when opening directories for WASI pre-opened mounts. Windows requires this flag to open directory handles, otherwise File::open() returns OS error 5 (access denied). Both fixes are behind #[cfg(windows)] — Unix behavior is unchanged. * fix: enable mouse support on Windows native console path Mouse events were silently dropped in the crossterm event loop, and enable_mouse() wrote VT escape sequences that don't set the required ENABLE_MOUSE_INPUT console mode flag. Add from_crossterm_mouse() converter, InputInstruction::MouseEvent variant, and use crossterm's EnableMouseCapture/DisableMouseCapture on Windows. * fix: Windows get_default_shell() now checks $SHELL before $COMSPEC * fix: resolve bare command names via PATH and PATHEXT on Windows CreateProcessW doesn't reliably resolve bare command names (e.g. "pwsh") through PATH the way Unix execvp does. Additionally, the existing command_exists() check didn't consider Windows PATHEXT extensions (.exe, .cmd, .bat, etc.). Add find_executable() and resolve_command() which search PATH with PATHEXT support on Windows, and use the resolved absolute path when spawning via CreateProcessW. * chore: run cargo fmt --all * fix: canonicalize expected paths in setup tests for Windows \\?\ prefix * fix: Windows CI test failures in spawn_and_read_output and snapshot test Use cmd /K instead of /C in spawn test so ConPTY has time to flush output before the pipe closes. Normalize backslashes in snapshot test to handle Windows path separators. * fix: strip redundant Shift and AltGr modifiers from Windows key events On the Windows native console path, crossterm reports physical modifier flags alongside the already-translated character. For example on French AZERTY, Shift+ù produces Char('%') with SHIFT, and AltGr+_ produces Char('\') with CTRL+ALT. These extra modifiers cause keybinding mismatches and prevent modified characters from being typed in plugin text inputs. Strip Shift for all Char events and Ctrl+Alt (AltGr) when the character is printable, matching Unix terminal behavior where only the resulting character is reported. Also fix raw byte synthesis for AltGr characters to emit plain UTF-8 instead of ESC-prefixed sequences. * fix: detect and clean up stale Windows sessions via PID-based liveness check Write server PID to marker files instead of creating empty files. assert_socket() on Windows now reads the PID and checks process liveness via OpenProcess, cleaning up stale marker files for dead sessions. * fix: connect reply pipe on Windows for kill-session and delete-session On Windows the server blocks on reply_listener.accept() after accepting the main pipe connection. Without a reply pipe connection, the route thread is never spawned and the KillSession message is never processed. * fix: wait for server Exit response in kill/delete session on Windows The previous fire-and-forget approach was unreliable: the client would disconnect before the server's route thread had time to read and process the KillSession message. Now we wait for the Exit response on the reply pipe, ensuring the server has fully processed the kill before we return. * fix: resolve Windows console mode race between VT input and mouse setup Two threads race over SetConsoleMode on the stdin console handle: - stdin_handler calls enable_vt_input() (read-modify-write) - input_handler calls enable_mouse() via crossterm's EnableMouseCapture (full SetConsoleMode overwrite to 0x0098) Depending on ordering, crossterm could clobber ENABLE_VIRTUAL_TERMINAL_INPUT (breaking the VT byte reader), or enable_vt_input could preserve ENABLE_QUICK_EDIT_MODE (intercepting mouse events at the console level). Fix enable_vt_input() to explicitly set the exact console mode needed (0x0298) instead of read-modify-write, clearing QUICK_EDIT_MODE and other line-editing flags. Fix enable_mouse()/disable_mouse() on the VT path (TERM is set) to use ANSI escape sequences instead of crossterm's Console API, avoiding the competing SetConsoleMode call entirely. Enable ENABLE_VIRTUAL_TERMINAL_PROCESSING on stdout first so ConPTY forwards the DEC private mode sequences to the terminal emulator. * fix: session-manager plugin kill session on Windows dual-pipe IPC The plugin's kill_sessions() only connected the main pipe and sent KillSession, but on Windows the server blocks on reply_listener.accept() before spawning the route thread. Without connecting the reply pipe the message was never processed. Add the same dual-pipe handling as the CLI kill_session(): connect the reply pipe first, send the message, then wait for the Exit response. * fix(windows): replace resize polling with event forwarding from stdin thread Forward crossterm Event::Resize from the stdin thread to the signal handler thread via an mpsc channel, replacing the 50ms polling loop. This makes terminal resizing much more responsive during mouse-driven resizes and eliminates wasteful polling when idle. When the VT reader path is active (terminal emulators with TERM set), the sender is dropped, causing the signal handler to automatically fall back to size-polling — preserving existing behavior for that path. Unix is unaffected: handle_signals receives None for the receiver and BlockingSignalIterator continues using signal_hook as before. * fix(windows): enable ANSI terminal queries on the VT reader path The startup ANSI query mechanism (pixel dimensions, colors, sync output) was blanket-skipped on Windows. The actual limitation is specific to the native console path, where crossterm's event::read() uses ReadConsoleInput (INPUT_RECORDs) and never reaches the byte-reader loop that parses ANSI responses. On the VT reader path (terminal emulators like Alacritty with TERM set), fill_buf() reads raw VT bytes via ReadFile — same as Unix — so ANSI query responses work normally. Move the use_vt_reader decision earlier and use it to gate the query, enabling it for the VT reader path while still skipping it on native console. * fix: handle early TerminalResize before client is fully registered On Windows, enable_mouse()'s SetConsoleMode call can generate a WINDOW_BUFFER_SIZE_EVENT that arrives as a resize before the server finishes processing the initial client connection. At that point set_client_data() hasn't been called yet, so set_client_size() silently no-ops on the None entry and min_client_terminal_size() returns None. Instead of panicking, skip the resize when the minimum size can't be determined — the server will query the terminal size once setup completes. * fix: remove unnecessary custom stack size Early versions of zelilj windows port crashed with stack overflow. Increasing stack size allowed proper startup and moving further with the porting effort. Current implementation no longer suffers from stack issues, so we can revert back to default stack size. * fix(windows): re-enable Ctrl+C handling inherited by ConPTY children The server is spawned with CREATE_NEW_PROCESS_GROUP, which disables Ctrl+C for the process. Children inherit this disabled state, so ConPTY child processes (shells, ping, etc.) silently ignore CTRL_C_EVENT signals generated by the pseudo-console. Call SetConsoleCtrlHandler(NULL, FALSE) early in start_server() to clear the inherited ignore flag before any ConPTY children are created. * refactor(windows): move inline cfg(windows) blocks to platform files Break out inline #[cfg(windows)] blocks from shared client code into the existing _unix.rs / _windows.rs platform files, per upstream feedback. - Split spawn_server into two #[cfg]-gated function definitions - Extract setup_ipc, enable_mouse_support, disable_mouse_support into os_input_output_unix.rs and os_input_output_windows.rs - Unify BlockingSignalIterator::new() signature across platforms - Extract native console stdin loop into stdin_handler_windows.rs * fix: remove sporadic info log statements * ci(windows): add Windows x64 release builds and upgrade CI - Add Windows x64 target to release.yml for both normal and no-web release matrices, with NASM, static CRT, .zip packaging, and PowerShell checksum steps - Upgrade build-windows in rust.yml from cargo check to cargo xtask build, add wasm32-wasip1 target and NASM - Add build_release() function and platform-aware e2e_build() to xtask/src/ci.rs - Add BuildRelease command definition to xtask/src/flags.rs * refactor(client): make resize channel unconditional across platforms Create the resize mpsc channel on all platforms instead of gating it behind #[cfg(windows)], avoiding conditionally-existing variables that are hard to follow. On Unix the sender is immediately dropped and the receiver is passed as None-equivalent to handle_signals. * refactor(windows): restructure signal iterator with if/else for channel vs poll Consolidate the quit check at the top of a single loop and use if/else for channel mode (native console) vs poll mode (VT reader). On channel disconnect, set resize_receiver to None and continue into the else branch instead of falling through. * docs(server): clarify comment about early resize before client init Explain why min_client_terminal_size() can return None even after set_client_size(): new_client() inserts None, and set_client_size() is a no-op on None entries since it uses as_mut().map(). * feat(web): add --server-startup-timeout flag for web server Make the hardcoded 10-second TCP-poll timeout in the non-Unix daemonize_web_server configurable via a CLI flag, defaulting to 10s. * fix(windows): use unique pipe names for ConPTY output on re-spawn When a held pane re-runs a command or drops to shell, do_spawn tried to create a named pipe with the same name as the previous spawn. The old ConPtyAsyncReader still held the read handle, so CreateNamedPipeW failed (FILE_FLAG_FIRST_PIPE_INSTANCE, max instances = 1) and the error was silently swallowed, leaving the pane blank. Add a monotonic AtomicU64 counter to the pipe name so each spawn gets a globally unique pipe, regardless of whether the previous one has been cleaned up yet. * ci(windows): enable static CRT for regular Windows release build The no-web Windows build already had RUSTFLAGS="-C target-feature=+crt-static" but the regular build was missing it, resulting in a dynamic CRT dependency. * docs(web): clarify --server-startup-timeout is Windows-only --------- Co-authored-by: divens <divens.dev@gmail.com>
* Visual indication for terminal bells (#4781)Aram Drevekenin2026-03-03
| | | | | | | | | | | | | * initial implementation * rustfmt * allow disabling with config * add missing kdl * add pr * fix tests
* Allow closing replaced panes when opening panes in place (#4760)Aram Drevekenin2026-02-24
| | | | | | | * allow close_replaced_pane from keybind and cli * rustfmt * add pr
* [Windows port PR5] refactor: upgrade interprocess to v2+ and abstract IPC ↵divens2026-02-21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | for cross-platform support (#4740) * refactor: upgrade interprocess to v2+ with cross-platform IPC support Replace interprocess 1.2.1 with 2.2+ which provides cross-platform local socket support (Unix domain sockets on Unix, named pipes on Windows). Migrate all call sites from the flat v1 API to the v2 enum-dispatch API, and replace nix::unistd::dup fd-duplication with interprocess::TryClone::try_clone(). * refactor: abstract FD duplication in IPC behind IpcStream trait Decouple IPC structs from the concrete transport by introducing an IpcStream trait that abstracts read/write/clone. Internal fields change from BufWriter<LocalSocketStream> to BufWriter<Box<dyn IpcStream>>, while the public new() constructors still accept LocalSocketStream so no callers need updating. * refactor: abstract session discovery behind is_ipc_socket() helper Replace all 6 direct uses of std::os::unix::fs::FileTypeExt::is_socket() with a cross-platform is_ipc_socket() helper in consts.rs. On Unix it delegates to FileTypeExt::is_socket(); on non-Unix it returns false as a placeholder for platform-specific session discovery added later. --------- Co-authored-by: divens <divens.dev@gmail.com>
* Purge `async_std` from the codebase (#4672)har7an2026-02-19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * build(utils): Replace `async_std` with `tokio` removing an entire async runtime from the dependency tree. `tokio` has previously been required by `wasmtime` in any case, and the version of async_std we used was ancient (1.3) and relied on unstable features. * build(server): Remove `async_std` from the codebase and replace it with `tokio` instead, which is already used by `zellij-utils` and `wasmtime`. * build(server): Remove dead dependency. * fix: Don't keep an async runtime in the `zellij-utils` subcrate but prefer to reuse an existing runtime from a caller instead. If no such runtime exists, create an ephemeral runtime on the current thread to run async tasks instead. Ideally, the functions needing the async task would be async themselves, but these are called by the `Layout` code based on a `ClientMsg`, and the code handling this currently lives in `zellij-utils` and is sync itself. So, for the time being, there is no way around this runtime requirement without a huge refactoring. * refactor(server): Unclutter async tasks in a few cases where either blocking code was called in an (unnecessary) async task or an entire thread was spawned to block on the result of an async task. * docs(CHANGELOG): Mention PR 4672 * fix(server): Don't terminate when killing a panes children fails but log the error and continue instead. * feat: Add config option for number of async tasks to spawn so users on machines with few resources can configure a task limit without requiring recompilation.
* Allow resizing panes with the mouse (#4678)Aram Drevekenin2026-02-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * initial implementation * improve edge detection * fix up/down resize increment bug * temporarily disable alt-mouse grouping * fix inverting strategies and simplify edge detection * resize of floating -> ctrl click, resize of tiled -> (ctrl)click * fix old functionality and tests * refactor and fixes * refactor mouse click handling * move mouse click handling to separate module * resize scroll up/down with scroll wheel * tests for scroll resize * implement hover help * fix occlusion bug * allow disabling with config * fix focus pinned pane on frame * use strategy invert resize directly rather than function parameter * remove annoying log message * cleanups and formatting * add pr
* Allow disabling OSC8 link generation (#4624)Aram Drevekenin2026-01-22
| | | | | | | * implementation * rustfmt * add pr
* Fix tiled new pane borderless (#4618)Aram Drevekenin2026-01-20
| | | | | | | | | * allow opening tiled pane as borderless * rustfmt * add pr * fix e2e tests
* Allow toggling pane frames for specific panes (#4615)Aram Drevekenin2026-01-20
| | | | | | | | | | | | | | | | | | | | | | | | | * initial implementation * add borderless to edit and plugin cli commands * allow changing existing pane to borderless * allow setting in layouts and keybindings * get to work through the existing plugin api commands * fix when applying (swap) layouts * fix tests * allow setting pane as bordered (borderful?) when changing its coordinates (eg. through the cli) * allow explicitly setting a pane as bordered or borderless without toggling * rustfmt * adjust snapshots * docs(changelog): add PR
* Layout manager (#4601)Aram Drevekenin2026-01-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * ad plugin override_layout command * watch available layouts and report to plugin thread * Event::AvailableLayoutInfo * save layout command * refactor save_layout * fix api and permissions * delete_layout API command * edit layout in place API * edit layout response through api * propagate layout parsing errors * generate random name plugin api * dump stringified layout API * synchronicity dump_session_layout and include LayoutMetadata in sync response * parse_layout plugin api * fix: default to default layout dir in plugin api * rename_layout plugin command API * initial implementation of multi-tab override * apply to multiple tabs * allow applying to only the active tab * add tab/pane names to layout parsing metadata * indicate is_builtin_plugin in PaneMetadata * get_layout_dir plugin API command * consolidate (and fix) is_builtin_plugin logic * fix bad ret * allow dumping the layout for just a specific tab in the session * get focused pane and tab sync api * color last substring variants * add plugin * update assets * fix tests * add e2e tests for new plugin apis * update ui with new shortcut * rustfmt * docs(changelog): add PR
* Feature: allow overriding a layout for a currently running tab (change ↵Aram Drevekenin2025-12-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | layout at runtime) (#4566) * add tests for LayoutApplier * initial untested implementation of override functions * add override-layout cli action with stub in screen * filter run instructions to ignore * implement override-layout roundtrip through plugin and pty threads * initial full-cycle working override implementation * fix some bugs (eg. actually start new terminals) * fix some bugs with focus after override * fix floating pane matching bug in layout applier * formatting * use first tab, error on more than 1 tab * fix some floating_panes ordering and shell issues * get new tab name to work * respect swap layouts * allow specifying tab properties on main layout node if we just have one tab * add tests for new override methods * start work on retaining panes, hard-coded things, kind of working but broken in many places * fixed most tiled pane override bugs * reset viewport before reapplying * revert constraint system changes * retain-existing-terminal-panes flag * add retain terminal panes tests * add retain plugin panes flag * add keybind * add retain plugin panes tests * add override-layout e2e test * refactor: layout_applier * style: rustfmt * some cleanups * fix cli flags * no crashy * formatting and artifacts * moar cleanups * fix: respect expanded in stack when overriding * docs(changelog): add PR
* Command Sequences, Blocking CLI Commands, New Plugin APIs (#4546)Aram Drevekenin2025-12-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix deadlocks * initial logging to plugin implementation * only log actions, include keys as Action::Write * send actions to plugins as a new Event::UserAction * add Action::Write metadata to plugin API * run_action plugin command and permission * block-until-exit/success/failure in the cli * fix tests * add NewBlockingPane to the plugin API * run actions in a different thread so as not to block plugin execution * add custom context to run_action flow * fixes for floating pane z_index sorting and unknown protobuf events not crashing plugins * always render the frame of pinned panes * macros module * add macros to config * KDL macro parsing * thread macros to the plugin thread * get/update/delete macros from plugins * add macros updated event * add ability to rename macros * fix deadlock * fix z_indices with pinned unselectable panes bug * allow plugins to opt-in to show_cursor * change show_cursor(bool) to show_cursor(Option<coordinates>) * test * upgrade strum to allow proper enum iteration and case insensitive fromstr implementation for Actions * better cwd tracking for exited command panes * add initial panes to NewTab Action (no-op for now) * add initial panes to cli newtab action * make initial panes work * add close_on_exit and start_suspended to the cli * properly convert newtab action (potentially breaking for plugins) * allow first pane in tab to block * make distinction between opening panes with the last active client and the current pane in the cli * improve some apis * fix fixed size closing pane bug * fix plugin cursor coordinates * fix issues with launch-or-focus-plugin having to do with in-place and suppressed panes * fix: set affected pane in replace pane * allow setting a pane in place when it is suppressed and being focused (tests failing) * fix tests * some fixes for unsuppression of panes * some fixes for completion_tx in new tab action * allow replace/suppressed rather than replace/close only * fixes for inserting suppressed panes without conflicts * pane focus history and explicit unsuppress plugin api * fix: prefer explicitly provided pane id in placement in actions that provide it * fix floating pane coordinate change and z_index * fix plugin cache dir to persist between sessions * fix some stack focusing issues when adding panes without a client id * make sure pinned panes are always above non-pinned floating panes * allow plugins to copy to clipboard * initial text styling additions implementations - buggy * fix dimming issues * remove extras, stay with just dim and unbold * unbold and dim as indices * allow ui components to render success/error colors * allow plugins to send sigint/sigkill to processes, as well as receive their pid * ui component fixes and send originating plugin context with run_action * originating plugin for new tab too * make plugn show pane command also expand stacked panes * add sequence plugin * remove macros * remove snapshots * add shortcut for sequence plugin * fix plugin tests * plugin tests for new apis * update snapshots for sequence shortcut * cleanups and formatting * Event::CwdChanged * moar cleanups * remove some warnings * remove mroe warnings * remove dead code * remove more dead code * fix minor bugs in sequence plugin * update sequence help and format codebase * fix conditional blocking cli commands * fix initial-command new-tab cli flag * add client_ids to CwdChanged Event * last fixes * add pr
* Improve CLI interface (add detach, switch session, blocking zellij run and ↵Aram Drevekenin2025-10-31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | more) (#4492) * initial implementation * fix tests * move more ations * screen adjustments (does not compile) * plugin/pty adjustments (does not compile) * more progress, tests not compiling * fix tests * more progress, does not compile * more progress, compiles, tests failing * tests passing * rely on Drop for NotificationEnd * atomicify some more actions * fmt * move unblock input to route * don't pass hard-coded action names * refactor: consolidate completion channel logic * comment * track last active client * track cli clients explicitly * use the last active client for cli commands when possible * fix focus-next-pane for multiple clients * various fixes for multi-client actions from the cli * add detach action * fix tests * add switch session cli action * fix switch session deadlock * add and layout to switch-session cli action * blocking zellij run: add NewBlockingPane variant * blocking zellij run: wait forever mechanism * blocking zellij run: thread NotificationEnd as needed until TerminalPane (tests not compiling) * blocking zellij run: update cli * blocking zellij run: add command * blocking zellij run: finish implementation * fix tests * e2e test and close_on_exit fixes * fmt * fix e2e tests * fix plugin tests
* fix(ipc): make sessions compatible between versions (#4439)Aram Drevekenin2025-09-24
* translate ipc tuple enum variants to struct enum variants * initial client/server contract * tests and missing types * migrate web server and remove rmp_serde * change socket folder * fix crash on unknown messages * fix client logout on unknown message * fix web client logout on unknown message * rustfmt * add comment and change log level * address compilation warnings * style(fmt): rustfmt * fix plugin system test assertions * add pr