Commit Graph
589 Commits
Author SHA1 Message Date
Aram Drevekenin 070b9c3d1c Fixes before 045 (#5492)
* fix: keep single-pane tabs when serializing, stop the busy-spin on IPC disconnect, and make client-less CLI actions either work or fail loudly

* fix: some tab closing/ordering issues

* test: integration coverage for OSC 133 selection, scroll retention, paste-read opt-in, theme actions, and input fragmentation

* rendering-width regression tests

* fix: forward alt+mouse events into a guest pane the client is descended into

* fix: alt + [] delay in non-kitty

* allow disabling mouse hover tips while keeping the other effects

* more osc133 actions

* fix: base mode race when changing keybinding presets

* fix compilation warnings

* make releases drafts and remove diagnostic logging

* add pr
2026-08-20 08:04:12 +02:00
Aram Drevekenin 0e6e440402 Support the Kitty Image Protocol (#5428)
* 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
2026-07-31 19:19:49 +02:00
Aram Drevekenin cab75c58fe More dependency upgrades for debian (#5421)
* 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
2026-07-29 17:08:08 +02:00
Aram Drevekenin 9969ed10b2 Dep upgrades for debian (#5420)
* chore(deps): upgrade base64 0.22, colored 3.1, crossterm 0.29, dialoguer 0.11, directories 6.0, highway 1.2, prost 0.12.6, strip-ansi-escapes 0.2.1, suggest 0.5.1

* chore(deps): upgrade miette 7.6, nix 0.30, notify 8.2, notify-debouncer-full 0.5

* vte 0.15

* clap 4.6

* workspaceify plugin deps

* don't send empty fs watch events
2026-07-28 12:05:38 +02:00
Pierre Kisters d9682a2eef fix: input spam when moving mouse while typing by splitting the input bytes into their respective events (#5323) 2026-07-17 15:24:52 +02:00
Aram Drevekenin 4bfda976b1 Allow creating panes/tabs from the CLI without changing focus to them (#5346)
* feat: allow opening panes and tabs from the cli without focusing them

* rustfmt

* fix flake

* rustfmt

* add pr
2026-07-09 16:52:50 +02:00
Aram Drevekenin 5b310ada79 UI tweaks (#5337)
* remove dimmed

* clearer list ui

* fix integration tests

* rustfmt

* move hint to tab-bar

* redesign stack list

* rustfmt

* fix e2e

* add pr
2026-07-06 22:09:06 +02:00
Aram Drevekenin 7b823f972a fix: more verbose startup errors (#5334)
* fix: more verbose startup errors

* add pr
2026-07-06 08:55:09 +02:00
Aram Drevekenin 245f5141c9 Title frames (#5318)
* 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
2026-06-29 18:10:59 +02:00
Aram Drevekenin 8c7e41c9aa chore: new test infra (#5269)
* initial implementation

* refactoring and cleanups

* port basic e2e tests

* fix tab rotation

* migrate client and mouse tests

* migrate the rest of the tests

* remove old e2e tests

* rustfmt

* add e2e note

* fix stale test

* fix: cross platform locking/cleanup

* fix: change mode race discovered by tests

* rustfmt

* fix: attach/detach race in tests

* fix plugin test assertion

* add pr
2026-06-16 15:44:22 +02:00
Aram Drevekenin aa29cbaf66 Some idle CPU and disk/io fixes, new CommandChanged plugin Event (#5063)
* initial implementation

* fix mouse cpu spam

* prevent excess metadata write and prune sessions on startup

* consolidate CommandChanged and PaneCommandChanged

* tests

* rustfmt

* add pr
2026-04-17 14:08:48 +02:00
Satoru HigaandAram Drevekenin 27a825ebdc fix: position host cursor for CJK IME even when app hides cursor (#4951)
* fix: position host cursor for CJK IME even when app hides cursor

When apps like Claude Code (ink/React library) hide the cursor during
rendering, Zellij's render_cursor() was not sending a CUP sequence to
the host terminal. This caused IME composition candidates to appear at
the wrong position, breaking CJK input in these apps.

Change cursor_coordinates() to return the cursor position unconditionally
(as long as it is within bounds) along with a bool indicating visibility.
render_cursor() now positions the host cursor even when the app has hidden
it, so the IME subsystem can read the correct cursor position.

* add test

* rustfmt

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-04-03 10:21:34 +02:00
Thomas Linford 6542afabd8 fix(e2e): stabilize tests and support Apple Silicon local dev (#4952)
- cross-compile musl binary on macOS via cargo-zigbuild, with
arch-independent symlink so snapshots are stable across x86_64 and aarch64

- kill_running_sessions() now calls stop_zellij() instead of
start_zellij(), eliminating 3s startup per test

- prevent steps from firing prematurely by tightening completion conditions
and adding re-send logic for garbled keys
2026-04-01 12:41:07 +02:00
Aram Drevekenin 8ce05f0bbd Layout string flag (#4956)
* allow sending a stringified layout with --layout-string

* add --tab-id to all the things

* fix windows tests

* add pr
2026-03-30 16:02:09 +02:00
divensanddivens d12b75800c fix: resolve Windows compilation warnings (#4890)
- Consume unused CompilationResult from embed_resource::compile in build.rs
- Gate std::io::prelude import with #[cfg(unix)] since it's only used by
  daemonize_web_server which is unix-only

Co-authored-by: divens <divens.dev@gmail.com>
2026-03-28 10:38:37 +01:00
Aram Drevekenin 12ee607532 fix: performance regression when switching tabs (#4918)
* remove pane render report

* only collect pane contents if pane should render

* add logs

* conditional keybinding serialization

* remove logs

* rustfmt

* fix tests

* tests

* rustfmt
2026-03-26 12:49:05 +01:00
Aram Drevekenin 6143d485ed Minor fixes and updates (#4861)
* add all blocking flags to action new-pane

* security updates
2026-03-17 16:00:59 +01:00
divensanddivens c4a572a884 Add Windows MSI installer with WiX v6 (#4847)
* Add Windows MSI installer with WiX v6

Build a dual-scope MSI installer that lets users choose per-user
(%LocalAppData%\Zellij) or per-machine (Program Files\Zellij) install,
with automatic PATH configuration and clean uninstall support.

- Custom UI based on stock WixToolset.UI.wixext dialogs to work around
  the long-standing WixUI_Advanced dual-scope bug (wixtoolset/issues#7137)
- Custom folder resolution CAs (SetFolderPerUser/SetFolderPerMachine)
- Embed application icon into zellij.exe via embed-resource
- Icon shown in Add/Remove Programs via ARPPRODUCTICON
- MSI build integrated into release.yml CI workflow

* Add MSI installer to no-web build and fix artifact naming

- Add MSI build steps to build-release-noweb job
- Add SHA256 checksums for MSI artifacts
- Pin WixToolset.UI.wixext to 6.0.2 to avoid v7 RC incompatibility
- Use -installer suffix after target in artifact names

---------

Co-authored-by: divens <divens.dev@gmail.com>
2026-03-16 12:38:38 +01:00
15571f8083 Fix debug-mode stack overflow on Windows (#4843)
* Fix debug-mode stack overflow on Windows

The clap-derived augment_subcommands for CliAction (~70 variants)
produces a >1 MB stack frame in debug mode, overflowing the Windows
default 1 MB main-thread stack. Increase it to 8 MB via linker flag
to match Linux. Only applies to debug builds; release optimizes the
frame down and doesn't need it.

* move file and include dev-opt

---------

Co-authored-by: divens <divens.dev@gmail.com>
Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-03-12 16:54:27 +01:00
Aram Drevekenin 40d9a5b1ee add verify cli test (#4835) 2026-03-11 11:11:18 +01:00
Aram Drevekenin 458f90cbbd Web security hardening (#4830)
* security hardening

* fix some issues

* rustfmt

* add pr
2026-03-10 18:25:05 +01:00
Aram Drevekenin 780784ab76 allow specifying ip/port with the zellij web --status cli (#4825)
* allow specifying ip/port with the zellij web --status cli

* add pr
2026-03-09 16:02:43 +01:00
Aram Drevekenin 58cb2267fd Allow subscribing to pane viewport updates (renders) from the CLI (#4814)
* initial subscribe implementation

* tests for subscribe

* update cli help

* rustfmt

* add pr
2026-03-07 16:33:05 +01:00
f77cdec298 feat: add per-pane default foreground/background color support (#4737)
* 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>
2026-03-04 14:26:26 +01:00
divensanddivens f6bf1af1ce [Windows port PR8] feature: add Windows support (#4768)
* 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>
2026-03-04 07:29:16 +01:00
Aram Drevekenin 8cd6286c3f remove sequence plugin (#4761) 2026-02-24 13:10:40 +01:00
Aram Drevekenin 2f069143fd Allow closing replaced panes when opening panes in place (#4760)
* allow close_replaced_pane from keybind and cli

* rustfmt

* add pr
2026-02-24 10:37:08 +01:00
har7an 3a9cf0a6d6 Purge async_std from the codebase (#4672)
* 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.
2026-02-19 12:59:14 +01:00
divensanddivens 9d9af7a3a4 refactor: replace nix::Error with std::io::Error in public APIs (#4720)
Co-authored-by: divens <divens.dev@gmail.com>
2026-02-18 13:56:47 +01:00
Marcus Michaels 9287080974 fix: add --timeout flag to zellij web --status (#4706)
* feat: add --timeout flag to zellij web --status

The HTTP client for checking web server status didn't have a timeout configured. This could cause the CLI to hang indefinitely if the server was unreachable, so I've added a 30-second default timeout and lets users override it with `--timeout <seconds>` when running `zellij web --status`. For example:

```
zellij web --status --timeout 60
```

* Update web timeout to work with --status (and add some tests to make sure everything works as expected)
2026-02-18 13:29:08 +01:00
Aram Drevekenin 4e66a0beff Revamp the sequence plugin (#4713)
* initial pipe interface

* initial open_x_pane_in_new_tab plugin api implementation

* fix: send CommandPaneExited for command panes opened as initial_terminals in new tabs from plugins

* open panes in place of specific pane id plugin commands - initial implementation

* sequence and plugin api ux

* focus self when starting

* combine ui and pipe paths

* highlight selected pane

* initial sequence removal of editing capabilities

* fix: translate plugin paths in api

* properly trim commands when loaded from pipe or pasted text

* minor ux fixes

* get ctrl c to work properly

* behavior fixes

* more ui fixes

* fix tests

* close tab and end sequence properly

* default to AND

* zellij sequence alias

* add alias

* consolidate paths

* rustfmt

* fix ui padding

* add pr

* fix: reset scrolling when resetting terminal state
2026-02-17 15:43:28 +01:00
Aram Drevekenin 860e8e323a Improve plugin API ergonomics and add CLI goodies (#4690)
* return created tab_id from relevant plugin API methods

* add to cli

* return Option<PaneId> in plugin API methods that create panes

* return created pane_id in cli for relevant actions

* allow plugins to query for pane_info based on pane_id

* allow plugins to query for TabInfo by its id

* allow plugins to query pane command/cwd synchronously

* zellij action list-panes

* style and formatting

* fix e2e tests

* add pr
2026-02-10 10:42:46 +01:00
har7an bdf20eef50 Fix loading short layouts and custom config dirs (#4640)
* test(e2e): Write a regression test to validate behavior

w.r.t. loading and determining the session layout file. Compared to
release v0.43.1, right now there is a problem where `zellij --layout
NAME`, with `NAME` being the filename of a layout in the
`$ZELLIJ_DATA_DIR/layouts/` subfolder, doesn't resolve to the correct
layout file. Instead, zellij will silently fall back to its default
config. It does, however, recognize nonexistent configuration files.

* fix(utils): Treat bare layout names as file paths first

before defaulting to builtin layout names. This restores the behavior
shown by zellij up until 0.43.1, which was altered in a recent extension
of the server-client API.

* fix: Forward client layout information to startup code

and ensure it isn't ignored along the way. Update a bunch of tests to
react to the new function interface and write new tests to catch
deviations in the future.

* test: Fix misconfigured e2e test

to ensure that a custom `--config-dir` is indeed respected during
application startup.

* test: Rewrite config dir test to not use variable metadata

since the `LayoutInfo` object previously dumped into the snapshot
contains information that isn't platform agnostic, including an absolute
file path and a timestamp.

* docs(CHANGELOG): Mention PR #4640

in the list of changes for the next release.

* fix: Handle bare layouts with name "default" correctly

and assume a "default" layout if no layout name is given during layout
resolution. "default" may not always be the builtin default layout,
since users can write their own "default.kdl" that takes effect when
placed in the layout directory an no other layouts are explicitly
specified.
2026-01-26 18:05:51 +00:00
Aram Drevekenin 81ca742a69 Allow disabling OSC8 link generation (#4624)
* implementation

* rustfmt

* add pr
2026-01-22 11:45:16 +01:00
Aram Drevekenin 03c86d09cf Allow toggling pane frames for specific panes (#4615)
* 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
2026-01-20 10:13:37 +01:00
Aram Drevekenin a71c6ba47c fix: remove layout config when switching sessions (#4604) 2026-01-14 13:55:59 +01:00
Thierry Santos 544bc7a451 fix(security): validate session name in delete-session to prevent directory deletion (#4583)
* fix(security): validate session name in delete-session to prevent directory deletion

When delete-session receives a path instead of a session name (e.g., due to
shell alias misconfiguration), PathBuf::join() replaces the cache directory
base path entirely, causing remove_dir_all() to delete the user's directory.

Add validate_session_name() to reject names containing '/' or invalid values.

* refactor: use Result instead of Option for validate_session_name

Change validate_session_name to return Result<(), &'static str> instead
of Option<&'static str> for clearer error semantics.

* refactor: use String for validate_session_name errors

Return Result<(), String> and include the session name in error messages
for better debugging context.

* chore: lint changed files
2026-01-14 13:54:52 +01:00
Aram Drevekenin 3fe48a972c Feature: allow overriding a layout for a currently running tab (change 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
2025-12-23 13:41:56 +01:00
Aram Drevekenin 1296a46a68 Read only web tokens (#4551)
* initial implementation

* fix race condition potentially allowing read-only clients to gain write access

* clear read only status on disconnect

* cleanups and formatting

* fix tests

* refactor first message + ipc pipe creation out of trait

* fix web tests

* fix web tests again

* refactor: move os_input connection establishment to session manager trait

* add read-only-token tests

* fix: identify watchers as web-clients when they are and enforce no-web-clients for them as well

* identify watcher web clients on the server

* fix tests

* cleanups and formatting

* add read-only-tokens to the plugin api

* update share plugin ui for read-only tokens

* cleanups and formatting

* docs(changelog): add PR
2025-12-16 09:16:41 +01:00
Aram Drevekenin 693fa082de Command Sequences, Blocking CLI Commands, New Plugin APIs (#4546)
* 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
2025-12-11 14:25:42 +01:00
Aram Drevekenin 82f30e2cde Improve CLI interface (add detach, switch session, blocking zellij run and 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
2025-10-31 20:15:32 +01:00
Aram Drevekenin 8762f86638 Feature: watcher clients (#4487)
* initial implementation

* make Screen aware of watchers - slightly buggy

* fix: only render focused tab to watcher

* track watcher sizes on Screen

* pad watcher output as needed

* truncate watcher sizes as needed

* render on watcher resize

* fix watcher first resize

* allow watchers to quit with esc, ctrl-c or ctrl-q

* fix: send watcher size on initial connection message

* refactor: move  padding logic to output

* fix watcher rendering after all clients disconnected

* fix watcher rendering caching issues

* crop watcher cursor when out of bounds

* remove watchers cleanly on session close

* standardize watcher messages ignoring

* add e2e test for watcher functionality

* update snapshots

* add output tests

* rustfmt

* cleanups

* docs(changelog): add PR
2025-10-27 12:31:02 +01:00
Aram Drevekenin 889bd06f44 Migrate from wasmtime to wasmi (#4449)
* initial implementation

* fix stdio and host folder mounting

* some memory usage optimizations

* fix plugin tests

* remove unused plugin cache

* fix docker-compose for e2e tests when running locally

* rustfmt

* initial pinned executor implementation

* EXPERIMENT: add jemalloc

* initial dynamic pinned threadpool

* cleanups and experiments

* keep state on execution threads

* reintroduce memory cache

* add wasmi engine to executor threads

* load plugins for new clients on the relevant executor thread

* only show loading indication of loading for more than 0.4 secs

* fix anonymous plugin loading without client id

* refactor lots of stuff

* update snapshots

* tests for pinned executor

* remove jemalloc

* fix stderr from plugins

* cleanups

* rustfmt

* cleanups

* fix endless loading for additinal attachments

* more cleanups

* remove singlepass feature

* fix displaying plugin permission message

* render optimizations

* always render for tests

* rustfmt

* optimize release build for wasmi

* fixes for multiple client plugin loading

* fix frame rendering for multiple clients

* rustfmt

* fix loading background plugins and e2e event ordering change

* rustfmt

* account for races in the pin_floating_panes e2e test

* docs(changelog): add PR
2025-10-21 14:36:30 +02:00
Aram Drevekenin 209d525c92 New Feature: remote attach to a Zellij session from the terminal (#4460)
* remote web attach

* docs(changelog): add PR
2025-10-06 16:25:53 +02:00
Aram Drevekenin 3a26df6314 refactor(client-server-contract): config + layout (#4383)
* commented out ConfigWrittenToDisk instructions

* commented out WriteConfigToDisk instructions

* commented out FailedToWriteConfigToDisk and WriteConfigToDisk instructions

* pass cli assets from client to server instead of parsed config - kind of working, lots of stuff still broken

* move ClientAttributes to the server side

* move ClientAttributes to the server side in Attach instruction as well

* move CliArgs and runtime options from NewClient -> move them to the server

* moved plugin_aliases to the server side

* moved initial config writing to the server side

* moved layout parsing to the server

* some cleanups

* move config file watching and live reload to the server

* move config file writing to the server side

* use saved config when attaching

* get web server to work with the new config roles

* some cleanups

* moar cleanups

* even moar cleanups

* yet more cleanups

* fix tests

* style(fmt): rustfmt

* style(fmt): rustfmt

* fix e2e tests

* docs(changelog): add PR
2025-08-28 17:48:34 +02:00
Aram Drevekenin 25a684e094 feat(web): allow specifying ip/port/cert/key through the cli (#4314)
* feat(web): allow specifying ip/port/cert/key through the cli

* fix no-web
2025-07-23 10:56:10 +02:00
Aram Drevekenin 91716979e0 fix(status-bar): proper truncation of secondary info (#4313)
* fix(status-bar): properly truncate secondary keybindings

* style(fmt): rustfmt

* more correct fix

* fix e2e tests

* docs(changelog): add PR
2025-07-22 21:12:38 +02:00
Aram Drevekenin 44a3c1dae9 fix(grid): account for wide characters when double-triple mouse clicking (#4302)
* fix(grid): account for wide characters when double-triple mouse clicking

* fix(e2e): moar race conditions

* docs(changelog): add PR
2025-07-18 10:05:32 +02:00
Aram Drevekenin 4a68c6d90b fix(resurrection): do not parse resurrection layouts on startup (#4292)
* fix(resurrection): do not parse resurrection layouts on startup

* proper error when file is corrupt

* docs(changelog): add PR

* fix attach command

* style(fmt): rustfmt
2025-07-16 12:03:32 +02:00
Aram Drevekenin 403f0a07be fix(sessions): remove popups from welcome screen (#4294)
* remove popups from welcome screen

* docs(changelog): add pr
2025-07-16 11:43:18 +02:00