feat(sidebar): visual-order ⌘N, persisted groups, deduped headers

Three follow-ups to the repo grouping:

- ⌘N now targets the N-th row as displayed (activate_visual over the
  same sections the render uses), so the badge digits read 1…9 top to
  bottom under grouping instead of scattering tab-vector indices.
- SessionTab persists the sticky sidebar group, so a restored session
  renders grouped on the first frame instead of starting flat and
  reshuffling as git probes land; reopen-closed-tab keeps its group too.
- Same-named repo roots disambiguate their headers by extending parent
  components until distinct (work/app vs fork/app); unique names stay
  short. Grouping/naming logic moved to pure functions with unit tests.
This commit is contained in:
l0ng-ai
2026-07-16 18:14:08 +08:00
parent e5ede1beb7
commit eec003e4e7
4 changed files with 252 additions and 75 deletions
+8
View File
@@ -77,6 +77,11 @@ pub struct SessionTab {
#[serde(default)]
pub name: Option<String>,
pub pane: SessionPane,
/// The tab's last-known sidebar repo group (its work-tree root), so a
/// restored session renders grouped immediately instead of starting flat
/// and reshuffling as git probes land. `None` = Scratch / never resolved.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sidebar_group: Option<std::path::PathBuf>,
}
/// The full saved session: the open tabs and which one was active.
@@ -179,6 +184,7 @@ mod tests {
tabs: vec![
SessionTab {
name: Some("build".into()),
sidebar_group: None,
pane: SessionPane::Leaf {
cwd: Some(PathBuf::from("/work")),
pane_id: Some(7),
@@ -189,6 +195,7 @@ mod tests {
},
SessionTab {
name: None,
sidebar_group: None,
pane: SessionPane::Split {
axis: SessionAxis::Vertical,
ratio: 0.3,
@@ -290,6 +297,7 @@ mod tests {
active: 0,
tabs: vec![SessionTab {
name: Some("main".into()),
sidebar_group: None,
pane: SessionPane::Leaf {
cwd: Some(PathBuf::from("/home/u")),
pane_id: Some(1),