diff options
| author | user <user@clank> | 2026-08-12 13:36:50 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-12 13:36:50 +0200 |
| commit | 3d936e2b4f6fafb3b319e609cc74a4340ce675bf (patch) | |
| tree | aa046fab99384e8d1dbc1d7738ac72e3899a91f2 /sl0p/zj-pane-finder | |
| parent | sl0p: add close_if_focused to LaunchOrFocusPlugin (diff) | |
| download | sl0ppij-3d936e2b4f6fafb3b319e609cc74a4340ce675bf.tar.gz sl0ppij-3d936e2b4f6fafb3b319e609cc74a4340ce675bf.tar.xz sl0ppij-3d936e2b4f6fafb3b319e609cc74a4340ce675bf.zip | |
sl0p(pane-finder): find panes hidden in a stack, not just the visible one
In a collapsed (mobile) layout every stack member except the visible one is
suppressed, and the finder skipped suppressed panes outright -- so it could only
ever find the one pane already on screen, which defeats the point of having it
there.
Suppressed terminals are now listed and marked "(hidden)". Suppressed plugins
still are not: zellij:link and friends are deliberately invisible
infrastructure, and focusing one shows an empty pane. Unfiltering everything
listed it, which is how that distinction surfaced.
Needed no server work. Screen::focus_pane_with_id already locates the owning tab
via has_pane_with_pid, which includes suppressed panes, and calls go_to_tab; and
Tab::focus_pane_with_id tries focus_hidden_stack_list_member first. So selecting
a hidden stack member swaps it into view and selecting a pane in another tab
switches tab, both already handled by the host.
Diffstat (limited to 'sl0p/zj-pane-finder')
| -rw-r--r-- | sl0p/zj-pane-finder/README.md | 10 | ||||
| -rw-r--r-- | sl0p/zj-pane-finder/src/main.rs | 20 |
2 files changed, 28 insertions, 2 deletions
diff --git a/sl0p/zj-pane-finder/README.md b/sl0p/zj-pane-finder/README.md index 83ed136b..da7ebf3f 100644 --- a/sl0p/zj-pane-finder/README.md +++ b/sl0p/zj-pane-finder/README.md @@ -3,6 +3,16 @@ A floating fuzzy finder for every pane in the session. Lists panes across all tabs, filters as you type, previews the highlighted one, and jumps to it. +It lists every pane in the session, including ones you cannot see: members of a +stack hidden behind the visible one, and panes in other tabs. Selecting a hidden +stack member swaps it into view; selecting a pane in another tab switches to that +tab first. Both come free from the host's `FocusPaneWithId`, which resolves the +owning tab through suppressed panes and hands hidden stack members to the fork's +stack-list logic. + +Suppressed **plugin** panes are the exception — `zellij:link` and friends are +deliberately invisible infrastructure, and focusing one shows an empty pane. + Filtering matches pane **metadata** (tab, title, command, cwd) and, failing that, the **visible contents** of each pane — so you can find a pane by something you can see in it rather than only by what it is called. Content diff --git a/sl0p/zj-pane-finder/src/main.rs b/sl0p/zj-pane-finder/src/main.rs index 807a2356..5f333316 100644 --- a/sl0p/zj-pane-finder/src/main.rs +++ b/sl0p/zj-pane-finder/src/main.rs @@ -36,6 +36,7 @@ struct PaneEntry { tab_name: String, title: String, is_floating: bool, + is_hidden: bool, is_focused_in_tab: bool, exited: bool, command: Option<String>, @@ -296,6 +297,10 @@ impl ZellijPlugin for State { if entry.is_floating { line.push_str(" (floating)"); } + if entry.is_hidden { + // stacked behind another pane, or otherwise not on screen + line.push_str(" (hidden)"); + } if entry.exited { line.push_str(" (exited)"); } @@ -362,12 +367,22 @@ impl State { .map(|t| t.name.clone()) .unwrap_or_else(|| format!("tab {}", tab_position + 1)); for pane in panes { - // never list ourselves, and skip suppressed (invisible) panes + // never list ourselves if pane.is_plugin && Some(pane.id) == self.own_plugin_id { continue; } // unselectable panes are UI furniture (status-bar, tab-bar, …) - if pane.is_suppressed || !pane.is_selectable { + if !pane.is_selectable { + continue; + } + // A suppressed PLUGIN is infrastructure -- zellij:link and + // friends are deliberately invisible, and focusing one shows an + // empty pane. Suppressed terminals are the opposite: in a + // collapsed/stacked layout every stack member except the visible + // one is suppressed, so skipping those left the finder able to + // find only the pane already on screen. Focusing one swaps it + // into view, switching tab if needed, via the host. + if pane.is_suppressed && pane.is_plugin { continue; } entries.push(PaneEntry { @@ -377,6 +392,7 @@ impl State { tab_name: tab_name.clone(), title: pane.title.clone(), is_floating: pane.is_floating, + is_hidden: pane.is_suppressed, is_focused_in_tab: pane.is_focused, exited: pane.exited, command: pane.terminal_command.clone(), |
