Commit Graph
285 Commits
Author SHA1 Message Date
Aram Drevekenin ca9210bd44 fix: tab and shift-tab to cycle in session-manager 2026-11-03 09:10:58 +01:00
Aram Drevekenin bef750cb43 fix: inbox preview offset, terminal title reset, -e hang (#5816)
* fix: remember explicit client disconnects (-e fix)

* fix: inbox previews, empty titles bulk session deletes

* disable attention
2026-11-02 16:46:54 +01:00
Myah MitchellandAram Drevekenin bf517077c8 feat(plugin-api): let plugins add an entry to the settings screen (#5779)
* feat(plugin-api): let plugins register a settings screen entry

- add register_settings_entry, unregister_settings_entry and the PluginSettingsEntries event
- the server keeps one entry per plugin instance and drops it when the plugin unloads
- instances of one plugin with the same title are listed once
- selecting an entry sends the plugin an OPEN_PLUGIN_SETTINGS_MESSAGE pipe message

* feat(configuration): list plugin settings entries on the plugins page

- a read-only "Plugin settings" section after aliases, load plugins and environment
- selecting an entry pipes OPEN_PLUGIN_SETTINGS_MESSAGE to its plugin, which opens its settings over this pane
- sections without actions get no actions row; with nothing selectable shown, the selection rests on the heading instead of a hidden section

* docs(changelog): add the plugin settings entries feature

* fix(plugins): remove a shared plugin's settings entry when it crashes or is reloaded by URL

* rustfmt

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-10-30 17:09:49 +01:00
Aram Drevekenin bd64701660 Desktop fixes (#5808)
* desktop fixes

* rustfmt

* merges

* resize preview adjustments

* update assets
2026-10-30 12:15:43 +01:00
Aram Drevekenin ca787b5877 redesign inbox (#5800)
* redesign inbox

* return dropped hint
2026-10-29 19:08:21 +01:00
Aram Drevekenin 78a097e457 Overhaul right click settings (#5795)
* improve right click menu and settings screen

* fix tests

* rustfmt
2026-10-29 11:29:15 +01:00
Aram Drevekenin 1f3df93397 Rename zellij window to zellij terminal (#5784)
* rename window to terminal

* rustfmt
2026-10-27 17:19:49 +01:00
Aram Drevekenin 237fe15970 New feat fixes (#5783)
* fix: delay when opening tab with the mouse, rename pane coverup issue

* fix: quit races causing ANSI leaks

* fix: resizing direction on corners, mouse click on text elements to edit

* fix: theme contrast

* rustfmt and plugins

* doule-click race fix

* assets
2026-10-27 15:20:21 +01:00
Aram Drevekenin 890474b88a feat: allow hiding ui at runtime (#5781)
* feat: allow hiding ui at runtime

* add pr

* add plugin assets
2026-10-27 11:31:57 +01:00
Aram Drevekenin ed033d0115 Inbox read fixes (#5768)
* fix(inbox): keep read messages in the UI until close

* rustfmt
2026-10-26 11:26:43 +01:00
Aram Drevekenin 145ed50d8a Drag and pane (#5766)
* feat: ctrl+mouse-drag to get a floating pane

* rustfmt

* add pr
2026-10-26 08:11:12 +01:00
Aram Drevekenin ffb334a949 Pane mirror embed (#5758)
* improve inbox ui

* various fixes

* last minute fixes and ux improvements

* various inbox ui/ux fixes

* single desktop window per session

* fix test

* tests and fmt

* add pr
2026-10-23 17:42:30 +02:00
Aram Drevekenin 7014cb440c perf: improve typing latency in the window (#5757)
* perf: improve typing latency in the window

* fix flaky tests

* rustfmt
2026-10-23 16:39:03 +02:00
Aram Drevekenin c7c4ce42b8 Allow renaming sessions from session mode (#5754)
* feat: allow renaming sessions from session mode

* rustfmt

* fix tests

* manually download protoc

* add pr
2026-10-22 18:11:26 +02:00
Aram Drevekenin a28f3ca9c2 Adjust Setup for Desktop Window (#5750)
* setup wizard

* rustfmt

* fix ci issues

* fix integration tests

* harden flaky tests

* fix ipc creation races
2026-10-22 10:41:39 +02:00
Aram Drevekenin 3ce7e7dc71 Inbox, notifications, better session-manager, desktop integration (#5734)
* feat(attention): add per-pane attention status with OSC 7501/133/633 parsing, frame symbols, mute/ignore/watch and plugin API

* revamp attention plugin

* desktopify attention

* tests, protobuffs, etc.

* strengthen tests

* desktop integrations

* test cases and hardening

* fix(app): keep tests off the live desktop app socket and recover from a lost socket

* fix(attention): readable tab marks, persist session mute, fix inbox clicks, rename socket, standalone windows and flaky tests

* unify new window keybindings

* fix: return to session shortcut display

* hide hover hints

* rustfmt

* merge

* fix tests

* fix tests

* fix tab-bar race

* fix tests again

* fix: prevent out of order cached pty writes on startup

* add pr
2026-10-20 13:29:16 +02:00
Myah MitchellandAram Drevekenin 014fdd728f fix(configuration): keep config formatting on save and scroll long dialogs (#5729)
* fix(config): edit plugin aliases in place per option

- Saving replaced a changed alias with a rebuilt node, dropping its
  comments, blank lines and option order
- Changed, added and removed options and the location are now edited in
  place; the alias is still replaced when that isn't possible (options
  written as properties, a changed option with several arguments)
- load_plugins entries use the same edit

* fix(configuration): keep spaces in plugin config values

- The pairs field trimmed every value on apply, so saving rewrote
  untouched values and turned " " into ""
- Keys are still trimmed; values are kept as typed, like env values

* fix(configuration): scroll dialog fields that don't fit

- The dialog capped its height at the pane but drew every field, so a
  long option list ran out of the pane with no way to reach it
- Scroll the fields with RowScroll, following focus and the mouse wheel

* docs: add changelog entry for #5729

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-10-19 15:04:50 +02:00
Aram Drevekenin 519a23715c Grapheme cluster support (#5714)
* initial implementation

* optimizations

* grapheme_clusters config, emoji font, VS15/Hangul/accent rendering fixes

* add pr

* fix flaky tests

* fix more flakes and some races
2026-10-14 11:21:38 +02:00
bc66c40189 feat: zellij terminal window (#5652)
* feat: zellij terminal window

* rustfmt

* improve default theme, bundle Nerd font icons, fix some rendering issues

* opacity

* remember window size

* rustfmt

* pref: improve input echo speed

* font schenanigens: padding, line height, cell width, font weight, etc.

* fullscreen toggle, close confirmation dialog, hide pointer while typing, hollow unfocused cursor, minimum contrast

* smooth scrolling

* scroll momentum

* rustfmt

* fix tests

* fix: show popups only once drawn at their requested size

* session suggestions

* moar suggestion tests

* macos option as alt

* macos system bell

* merge wrapups and tests

* dead keys, font size in points, extra tests

* terminal window config in settings

* shift+mouse highlighting and link-clicking in window

* rustfmt

* adjust window error messages

* confirm on quit

* fix popup and multiplayer cursors, mouse pointer shapes for ui elements

* rebase stragglers

* fix(window): keep a dead key's accent through modifier keys

A dead key followed by a character it can't combine with lost its
accent when that character needed Shift or AltGr: on a French AZERTY
layout, `^` then `/` typed `/` instead of `^/`. The window settled the
accent on the next key press, the Shift or AltGr press included, while
Windows keeps the dead key until a key produces text and reports the
accent in that key's text, which the window then ignored.

Leave a pending accent alone on modifier and lock keys, and type a
character key's text when it carries an accent ahead of the character,
which also covers an accent Windows kept through an arrow key.

(cherry picked from commit 7822bf4c02)

* fix: filter out locked sessions

* rustfmt

* fix e2e

* add pr

---------

Co-authored-by: Thomas Linford <linford.t@gmail.com>
Co-authored-by: divens <divens.dev@gmail.com>
2026-10-12 17:10:13 +02:00
Aram Drevekenin b1033be2a3 Improved mouse handling (#5697)
* configurable mouse bindings

* feat(bars): reorder tabs with mouse drag, clickable status-bar shortcuts with hover effects

* fix tests

* add pr
2026-10-09 11:59:23 +02:00
Aram Drevekenin 9dacbc1982 allow dangerously disabling certificate on non-localhost (#5694)
* allow dangerously disabling certificate on non-localhost

* add pr
2026-10-08 11:26:00 +02:00
Myah MitchellandAram Drevekenin 6af3a36eb8 feat(plugin-api): let a plugin give its layout space back while empty (#5590)
* feat(plugin-api): let a plugin give its layout space back while empty

A plugin mounted in a layout as a bar keeps the row the layout reserved
for it even when it has nothing to draw, so an empty bar shows as a blank
line. Nothing in the plugin API could give that row up: HideSelf
suppresses the pane and brings it back through add_tiled_pane, which
re-inserts it by splitting rather than at its layout position, and
CloseSelf does not come back at all.

SetSelfCollapsed takes the pane out of the constraint solve without
taking it out of the layout. The pane keeps its size constraint while it
is out, so a Fixed(1) bar is still Fixed(1) when it rejoins and expanding
restores exactly what the layout asked for, while constrain_spans makes
its neighbors grow over the space in the meantime.

Collapsed panes are tracked separately from panes_to_hide, which
fullscreen overwrites wholesale, so a collapse survives entering and
leaving fullscreen. They are also left out of the viewport offset, since
a pane holding no space must not shrink the viewport, and their state is
dropped when the pane closes so a reused pane id does not arrive already
invisible.

* test(tab): cover collapsing a pane out of the layout and back

Pins down what the collapse is for: the neighbors take the space, the
collapsed pane keeps its size constraint so expanding restores the layout
exactly rather than approximately, and the collapse outlives a fullscreen,
which rebuilds the hidden set from scratch.

Also covers the two ways it should do nothing: a second collapse of an
already collapsed pane, and a pane id that is not in the tab. Closing a
collapsed pane drops the state, so a reused id does not come back
invisible.

* fix(screen): keep one deferred collapse per pane instead of a queue

A plugin sends this whenever its content comes and goes, so a plugin
with no pane in any tab would otherwise leave an entry behind on every
change, all of them replayed the next time a tab is created. Only the
most recent word on a pane means anything, so drop the earlier one.

* fix(tab): keep a collapsed pane's geometry current across a relayout

Being filtered out of the constraint solve is what stops a collapsed pane
from holding space, but it also means nothing writes geometry to it. That
was fine while the tab kept its shape and wrong the moment it did not: the
pane was left describing a display area that no longer existed.

Worse than stale, because the solver reads the layout tree back off where
the panes currently sit. A one-row bar collapsed in a 121x20 tab that then
became 118x23 stayed at y 19 in a tab whose last row was 22, so the next
solve was handed a tree that did not match the screen and gave up. The bar
came back three rows above the bottom, at a width wider than the tab, and
its neighbor never gave the row back.

Let collapsed panes take part in the resize and the relayout, then collapse
them again over the result, which is what fullscreen already does a few
lines above for the same reason.

* docs(changelog): note the plugin collapse command

Links the tracking issue rather than a pull request, since no pull
request is open yet. Wants updating to the pull request URL once there
is one, to match every entry in the released sections.

* fix(tab): give a collapsed pane's row back to the viewport after a relayout

A relayout solves with the collapsed panes taking part, and the layout
offsets the viewport while they are still there. Collapsing them again
afterwards handed their rows back to the panes around them, but not to the
viewport, so a collapsed bar went on holding its row out of it until the
next resize. Fullscreen reads the viewport, so it would not cover that row
either.

Offset the viewport again once the collapsed panes are gone, the same as
resize_whole_tab already does.

* refactor(tiled-panes): keep the hidden pane bookkeeping in PanesToHide

Fullscreen and collapse both hide tiled panes, and each needs to undo only
what it hid. Until now that was done by keeping collapsed panes in a set of
their own and rebuilding panes_to_hide from both sources whenever either
changed, which every caller had to remember to do.

panes_to_hide is now a PanesToHide struct that tracks the two reasons
separately: panes beneath a fullscreen pane, and covered panes such as a
plugin that collapsed itself. set_fullscreen and unset_fullscreen only
touch the first, set_covered and unset_covered only the second, so a
covered pane stays hidden across a fullscreen without any rebuilding, and
the fullscreen pane itself is never hidden.

add_to_hidden_panels and remove_from_hidden_panels had no callers and
wrote straight into the set, so they are gone.

* fix(plugin-api): collapse the slot being rendered for a shared plugin

set_self_collapsed sent env.plugin_id, which for a shared plugin is the
instance and not any of its panes, so a shared plugin such as the bundled
bars could not collapse at all. Resolve the pane through self_pane_id like
the other self commands do, and list SetSelfCollapsed in is_self_command so
a shared plugin can only use it while a slot is current.

* feat(plugin-api): let a shared plugin collapse a slot by id

The other self commands have a slot form that names the pane outright, so
a shared plugin can use them from update or pipe, where no slot is current
and the self form is refused. set_collapsed_slot does the same for
set_self_collapsed, with the ownership check and response the other slot
commands give.

* fix: resurrection, covering selectable panes, mouse clicks, closing, paneinfo

* rebuild assets

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-10-06 13:23:29 +02:00
Aram Drevekenin 201c1593da Interactive configuration, popups, notifications, right-click menu (#5685)
* ui components

* right click menu + popups

* settings screen

* various fixes

* presets in config

* zellij prompt - ui elements in the cli

* context menu shortcuts and toggle, keybindings in popups, info popups + zellij prompt notify

* smart config writing and some leftovers

* keybindings/right-click/config editors

* some wrapups

* feat(plugins): add prompt() plugin API for zellij:prompt, dialog forms, and Text labels in widgets

* theme editors

* upstream by-id action types, config env for new panes only, smaller saved menu config, web right-click, example config

* upstreamify

* rustfmt

* fix windows and theme editor layout

* add pr
2026-10-05 18:46:12 +02:00
ZykinoandZykino 66e6676698 Reduce a bit some code length and improve readability (#5681)
Co-authored-by: Zykino <3809938+Zykino@users.noreply.github.com>
2026-10-04 23:42:10 +02:00
GhostCoder6969andGhostCoder6969 4ba55d7248 Fix duplicated words in tips and plugin comment (#5677)
* Fix duplicated words in tips and a comment

* Use color_substring helpers for the Ctrl o tip

* Use substring helpers for the remaining tip highlights

---------

Co-authored-by: GhostCoder6969 <ghostcoder6969@users.noreply.github.com>
2026-10-04 18:40:05 +02:00
ZykinoandZykino ef497e1ae3 NestedListItem::new require Text instead of &str (#5611)
Part of the change was done with `ast-grep run -p 'Text::new($A)' -r 'Text::from($A)' --update-all`

Co-authored-by: Zykino <3809938+Zykino@users.noreply.github.com>
2026-09-30 19:26:19 +02:00
Aram Drevekenin 208a0da5e9 Resource usage optimizations (#5662)
* shared instance plugins

* reduce needless allocations and share memory

* fix: read buffer bug

* idle plugin fixes and optimizations

* trim allocator for glibc on pane close

* fix flaky integration tests

* refactor: naming

* rustfmt

* add pr
2026-09-28 10:58:12 +02:00
Myah MitchellandAram Drevekenin 0591ca5432 feat(nested-sessions): report a guest's input mode and key bindings to its host (#5589)
* refactor(plugin-api): share the keybinding protobuf conversions

The conversion between a keybinding table and its protobuf form was written
out four times: once each way for the ModeUpdate and InitialKeybinds events.
Collect them into `keybinds_to_protobuf` and `keybinds_from_protobuf`.

Decoding now drops a binding whose key is missing instead of unwrapping it,
so a malformed or foreign payload can no longer panic the conversion, and a
mode whose key fails to convert costs only that binding rather than every
binding in the mode.

* feat(nested-sessions): carry input mode and keybindings over the protocol

A session hosting a nested session has no way to learn what that session is
doing, so its plugins cannot show hints for the session the user is actually
typing into. Add the three messages that carry it:

- GuestModeUpdate, sent by a guest whenever its input mode changes, so a host
  always knows which of the guest's bindings currently apply.
- RequestGuestKeybinds and GuestKeybindsUpdate, a query and its answer, for
  the far larger keybinding table. Keeping the table behind a query means it
  is fetched once by whoever wants it rather than pushed at every host.

The table travels as an encoded plugin-API payload in an opaque bytes field.
Describing keybindings natively here would mean restating the whole Action
schema in this contract, which the codegen compiles with only its own include
path. Reusing the existing payload also means a host and a guest built from
different Zellij versions exchange whatever both understand and silently drop
the rest, which is the behavior this wire needs.

An input mode is written under the name InputMode::from_str reads, so adding a
mode needs no change to this contract and an unknown mode is rejected rather
than misread.

Peers advertise the new HintReporting capability, so each side can tell
whether the other can take part before asking it anything.

* feat(plugin-api): expose nested session mode and keybinding events

Plugins running in a host session can see that a pane holds a nested guest
session, but they have no way to learn what that guest is doing. A status bar
in the host therefore keeps showing the host's own hints while the user is
descended into the guest, which is the wrong keybinding table for the keys the
user is actually pressing.

Add two events and one command covering that gap:

  - Event::NestedSessionModeUpdate reports a guest's input mode as it changes.
  - Event::NestedSessionKeybinds delivers a guest's full keybinding table.
  - PluginCommand::RequestNestedSessionKeybinds asks a guest pane for that
    table, which arrives asynchronously as the event above.

Both events carry the pane the guest runs in and the guest's session name, so
a plugin watching several nested panes can tell them apart. Keybindings are
requested rather than pushed because the table is large and most plugins never
need it.

* feat(nested-sessions): report guest input mode and keybindings to the host

Wire the nested session hint events end to end.

A guest announces the HintReporting capability during the handshake and, from
then on, emits a GuestModeUpdate frame whenever its input mode changes. The
mode is reported on every change rather than only while the host is descended,
so the host already holds the right mode the moment focus arrives and the
status bar does not lag behind the descent.

The host turns each such frame into Event::NestedSessionModeUpdate. It answers
PluginCommand::RequestNestedSessionKeybinds by writing a RequestGuestKeybinds
frame into the guest pane; the guest replies with its keybinding table plus its
current mode, and the host forwards the table as Event::NestedSessionKeybinds.

Requests to guests that did not advertise HintReporting are dropped rather than
written, and frames from panes whose guest is not currently live are ignored,
matching how the other guest-to-host frames are handled.

Both events and the command require the ReadApplicationState permission, the
same gate ModeUpdate uses.

* test(nested-sessions): cover guest mode and keybinding reporting

Unit tests over the contract check that every input mode survives the round
trip under its own name, that a mode name the reading side does not know is
rejected rather than guessed at, and that a keybinding table keeps its modes,
keys and actions across the wire. The undecodable and empty payload cases are
covered too, since a host and a guest may be built from different versions.

Integration tests drive two real sessions bridged through a pane: both sides
advertise hint reporting during the handshake, the guest answers a keybinding
request with a populated table plus its current mode, and the guest reports
each mode change while the user is descended into it.

* test(nested-sessions): drop unknown capabilities without losing known ones

A peer built from a newer Zellij can advertise capabilities this side has
never heard of, so pin down that they are ignored individually rather than
invalidating the whole advertisement.

* feat(nested-sessions): carry the guest's base mode alongside its input mode

A host plugin that only knows a guest's current mode cannot tell which of the
guest's bindings are inherited from its base mode. Zellij's own hint rendering
leans on that distinction: bindings the base mode already advertises are
inherited by every other mode through `shared_except` groups, so repeating them
in each mode is noise. Without the guest's base mode a host plugin either
suppresses the wrong bindings or suppresses none.

A guest with a non-Normal base mode, such as an unlock-first config, is where
this shows: assuming Normal there hides the wrong half of its bindings.

The base mode rides along on the existing mode message, so a guest that has not
switched modes yet still reports one, resolved the way the rest of Screen
resolves it (the configured default mode is the base). It stays optional on the
wire, so a name the reading side does not recognize costs only the
inherited-binding distinction rather than the whole message.

* feat(nested-sessions): report the guest's mode when the handshake completes

A guest only pushed its input mode when that mode changed, so a host that
had just picked up a nested session learned nothing about it until the user
happened to switch modes inside it. A host plugin has no other way to tell
which of its panes holds a session worth asking for keybindings, which left
it unable to act on the feature at all in the common case of a guest sitting
in its starting mode.

Send the report once on contact as well, and reuse the same client mode
lookup the keybinding answer already did.

* docs(changelog): note the nested session hint reporting events

* fix(nested-sessions): drop guest keybindings on control characters

Nothing a guest says is authenticated. Its frames travel in the terminal
stream of the pane it runs in, so any program with that pane can write them,
including a keybinding table claiming a binding on a raw control character.
A host that draws those bindings puts their keys on its own screen, where a
control character is a terminal escape in the host's output rather than a
key anyone could press.

Drop them where the guest's payload is decoded, so no host plugin inherits
the problem. Zellij spells the control keys that do exist as their own
BareKey variants, so a Char holding one describes no binding worth keeping.

* test(nested-sessions): expect hint reporting in the announce ack

The host now advertises HintReporting alongside NestedControl when it
acknowledges a guest, so the assertion on the exact capability list had to
follow.

* fix(plugin-api): drop only what has no protobuf form when writing keybindings

keybinds_to_protobuf failed the whole table on the first key or mode it could
not represent, so one unrepresentable binding cost the caller every binding:
a ModeUpdate that failed to convert entirely, and a nested session's answer
that reached its host as an empty table indistinguishable from a session with
no bindings at all.

Drop the individual mode, key or action instead, which is what the reading
half already does and what the writing half already did for actions. A table
now survives the trip between builds minus whatever they do not have in
common.

* fix(nested-sessions): keep a host's view of the guest fresh across a reconfigure

A reconfigure rewrites a session's keybindings and base mode without going
through change_mode, and keybindings are otherwise only ever sent in answer
to a request. A host that had already asked once therefore kept drawing the
table the guest had before its config was reloaded, with no way of noticing
it had gone stale, and would not have picked up the new base mode until the
user happened to switch modes inside the guest.

Report both from reconfigure, next to the shortcut broadcast that already
happens there. Answer a keybinding request from the requesting client's own
table too, since a reconfigure with write_to_disk unset rebinds only the
client that asked: the mode in the same reply already came from that client,
so the two halves now describe the same thing.

* fix: adjust protocol + API

* Update CHANGELOG.md

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-09-24 14:43:03 +02:00
Aram DrevekeninandLucca Huguet 81f56e1aed Yazelix fixes (sixel/kitty correctness, explicit-swap-layout change rather than toggle, border styling) (#5630)
* fix: sixel image reaping/id-reuse

* fix: kitty scaling issues

* fix: stacked pane ordering

* feat: apply tiled/floating swap layout by name

* border styling

* fix tests

* fix: complete Yazelix feature validation (#5631)

* fix: retire client-ids instead of reusing them

* distributions

* rustfmt

* fix tests

* update changelog

* fix tests and race

---------

Co-authored-by: Lucca Huguet <lucca.huguet2@gmail.com>
2026-09-24 09:26:20 +02:00
Oli Treadwell (he/him) a162323384 fix: correct typos in docs and code comments (#5599) 2026-09-09 19:16:46 +02:00
MsfPablo af38660c58 fix typos in code comments (#5562) 2026-08-31 21:00:55 +02:00
Thomas Dickson f4d38d6510 fix(plugins): release a CLI pipe when the plugin handling it crashes (#5537)
apply_pipe_message_to_plugin sends UnblockCliPipes on every success path,
including the path for old plugins that do not export `pipe`, but not when
the call into the plugin fails. When a plugin traps while handling a pipe
message, both call sites in wasm_bridge only log and call handle_plugin_crash,
which paints a loading-indication error on the pane and does not unload the
plugin. The (plugin_id, client_id) entry therefore stays in PendingPipes and
the `zellij pipe` client blocks until the plugin is unloaded or the session
ends.

Move the body to apply_pipe_message_to_plugin_inner and have the wrapper
release the pipe on any error before re-returning it, so neither call site
can forget.

Adds a regression test driving a fixture-plugin branch that panics while
handling a pipe, asserting UnblockCliPipeInput is emitted at crash time
rather than at teardown.
2026-08-28 10:20:24 +02:00
habeebweeb 52f1210710 fix first run wizard unlock first nested session keybinds (#5539) 2026-08-26 09:42:44 +02:00
Aram Drevekenin 18cb94e1cc Release notes (in the about plugin) for the 0.45 release (#5498)
* vesion 0.45.0 release notes

* update release notes
2026-08-20 09:41:18 +02:00
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 4156b50233 fix: close session manager if switching sessions (#5486) 2026-08-17 13:37:34 +02:00
Aram Drevekenin 3239d37b40 Native web mobile UI (#5441)
* initial chrome

* mobile state

* feat(mobile-web): implement browser→server actions (fit toggle, single-pane fullscreen, pane/tab focus) with fullscreen-truth reconciliation

* panning

* remove mobile plugin

* fix first load race

* improve web handshake

* rustfmt

* cleanups

* moar cleanups

* add bundle asset check to ci

* fix(mobile-web): tab-scope co-presence, yield single-pane to desktop clients, fix render-mode desync

* make mobile use no-ui fullscreen

* client side welcome screen for mobile

* attach web clients to first tab on tiles surface

* fix: opening new pane in mobile single mode no longer exits mobile single mode

* mobile chrome light theme support

* fix server races and flaky tests

* rustfmt

* fix flakes

* add pr
2026-08-05 15:32:53 +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
Aram Drevekenin ea07e2d5b6 Nested session handling (#5417)
* 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
2026-07-27 18:24:37 +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 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
DawidPietrykowskiandAram Drevekenin ebd731b0ff feat(panes): FocusLastPane action (#4241)
* feat(panes): focus last pane (#4142)

* add tests

* add client id parameter to `add_floating_pane`

* add action for floating panes

* add tests for floating panes

* add keybinds to configs

* rebase fixes

* simplify focus logic when adding stacked pane

* formatting fix

* formatting fix 2

* fix: make sure expanding pane always focuses it for all clients in stack

* add pr

* fix rebase

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
2026-06-25 18:12:51 +02:00
Aram Drevekenin b6a5ad0e5a Mobile layout (#5241)
* 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
2026-06-10 16:50:55 +02:00
Aram Drevekenin fc6c5942a1 Welcome screen del fix (#5160)
* fix: session-manager delete

* rustfmt

* add pr
2026-05-12 12:20:23 +02:00
cossio 441158f67b Fix session-manager Esc/Ctrl-c to close plugin instead of hiding (#5055) 2026-05-11 16:13:46 +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
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
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 93bc9ec00f fix: do not reset layout selection in layout manager (#4919) 2026-03-26 12:48:24 +01:00