aboutsummaryrefslogtreecommitdiffstats
path: root/sl0p/zj-pane-finder
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-12 13:36:50 +0200
committeruser <user@clank>2026-08-12 13:36:50 +0200
commit3d936e2b4f6fafb3b319e609cc74a4340ce675bf (patch)
treeaa046fab99384e8d1dbc1d7738ac72e3899a91f2 /sl0p/zj-pane-finder
parentsl0p: add close_if_focused to LaunchOrFocusPlugin (diff)
downloadsl0ppij-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.md10
-rw-r--r--sl0p/zj-pane-finder/src/main.rs20
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(),