diff options
| author | akbash <akbash@herdr.dev> | 2026-09-09 23:56:53 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-09 23:56:53 +0300 |
| commit | 120c682008a85dc17d7a13cc619a2fd5d25f3924 (patch) | |
| tree | 0119dfbe37bba91053f985ba60f3ee399d2ea797 /src/client/shell/overlays.rs | |
| parent | 985d3442b4b8a6f2e25a62821aab58d63d8ce2cf (diff) | |
fix: restore connected session navigator tree glyphs (#3861)
refs #3843
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Diffstat (limited to 'src/client/shell/overlays.rs')
| -rw-r--r-- | src/client/shell/overlays.rs | 76 |
1 files changed, 46 insertions, 30 deletions
diff --git a/src/client/shell/overlays.rs b/src/client/shell/overlays.rs index faf252a8..4418c2c3 100644 --- a/src/client/shell/overlays.rs +++ b/src/client/shell/overlays.rs @@ -673,6 +673,24 @@ fn render_rename_overlay( }) } +/// Mark following siblings in preorder without rescanning descendants for each row. +/// The reverse stack contains at most one entry per depth; every entry is pushed +/// and popped at most once, so this pass is linear in the number of rows. +fn navigator_following_siblings(rows: &[ClientNavigatorRow]) -> Vec<bool> { + let mut following = vec![false; rows.len()]; + let mut depths = Vec::new(); + for (index, row) in rows.iter().enumerate().rev() { + while depths.last().is_some_and(|depth| *depth > row.depth) { + depths.pop(); + } + following[index] = depths.last() == Some(&row.depth); + if !following[index] { + depths.push(row.depth); + } + } + following +} + fn render_navigator_overlay( b: &mut Buffer, n: &ClientNavigatorOverlay, @@ -746,15 +764,17 @@ fn render_navigator_overlay( .max(selected.saturating_sub(body.height.saturating_sub(1) as usize)) .min(selected) .min(max); + let following_siblings = navigator_following_siblings(&rows); + let mut ancestor_siblings = Vec::new(); + let federated = endpoints.len() > 1; let mut row_hits = Vec::new(); - for (vis, (ix, r)) in rows - .iter() - .enumerate() - .skip(scroll) - .take(body.height as usize) - .enumerate() - { - let rect = Rect::new(body.x, body.y + vis as u16, body.width, 1); + for (ix, r) in rows.iter().enumerate().take(scroll + body.height as usize) { + ancestor_siblings.truncate(usize::from(r.depth)); + ancestor_siblings.push(following_siblings[ix]); + if ix < scroll { + continue; + } + let rect = Rect::new(body.x, body.y + (ix - scroll) as u16, body.width, 1); row_hits.push((rect, r.target.clone())); let st = if r.stale { Style::default() @@ -777,7 +797,7 @@ fn render_navigator_overlay( }; b.set_style(rect, st); let tree = match &r.target { - ClientNavigatorTarget::Machine { .. } => "▾", + ClientNavigatorTarget::Machine { .. } => "▾".to_owned(), ClientNavigatorTarget::Workspace { endpoint_id, workspace_id, @@ -785,32 +805,28 @@ fn render_navigator_overlay( .expanded_workspaces .contains(&(endpoint_id.clone(), workspace_id.clone())) => { - if r.depth == 0 { - "▾" - } else { - " ▾" - } + if r.depth == 0 { "▾" } else { " ▾" }.to_owned() } ClientNavigatorTarget::Workspace { .. } => { - if r.depth == 0 { - "▸" - } else { - " ▸" - } + if r.depth == 0 { "▸" } else { " ▸" }.to_owned() } - ClientNavigatorTarget::Tab { .. } => { - if r.depth == 1 { - "└──" - } else { - " └──" + ClientNavigatorTarget::Tab { .. } | ClientNavigatorTarget::Pane { .. } => { + // Machines and workspaces keep their existing caret decoration. + // Connected branches begin below each workspace. + let mut prefix = if federated { " " } else { "" }.to_owned(); + for &following in ancestor_siblings + .iter() + .take(usize::from(r.depth)) + .skip(if federated { 2 } else { 1 }) + { + prefix.push_str(if following { "│ " } else { " " }); } - } - ClientNavigatorTarget::Pane { .. } => { - if r.depth == 2 { - " └──" + prefix.push_str(if following_siblings[ix] { + "├──" } else { - " └──" - } + "└──" + }); + prefix } }; let current = if r.current { "◆ " } else { "" }; |
