aboutsummaryrefslogtreecommitdiff
path: root/src/persist
diff options
context:
space:
mode:
Diffstat (limited to 'src/persist')
-rw-r--r--src/persist/io.rs1
-rw-r--r--src/persist/restore.rs31
-rw-r--r--src/persist/snapshot.rs38
3 files changed, 69 insertions, 1 deletions
diff --git a/src/persist/io.rs b/src/persist/io.rs
index f8525bc5..1b589b09 100644
--- a/src/persist/io.rs
+++ b/src/persist/io.rs
@@ -133,6 +133,7 @@ mod tests {
agent_panel_scope: AgentPanelScope::CurrentWorkspace,
sidebar_width: Some(26),
sidebar_section_split: Some(0.5),
+ collapsed_space_keys: std::collections::HashSet::new(),
}
}
diff --git a/src/persist/restore.rs b/src/persist/restore.rs
index f558761d..ebad2f16 100644
--- a/src/persist/restore.rs
+++ b/src/persist/restore.rs
@@ -99,6 +99,8 @@ fn restore_workspace(
return None;
}
+ let worktree_space = restored_worktree_space_membership(snap.worktree_space.clone());
+
Some((
Workspace {
id: snap
@@ -107,8 +109,10 @@ fn restore_workspace(
.unwrap_or_else(crate::workspace::generate_workspace_id),
custom_name: snap.custom_name.clone(),
identity_cwd: snap.identity_cwd.clone(),
- cached_git_branch: None,
+ cached_git_branch: crate::workspace::git_branch(&snap.identity_cwd),
cached_git_ahead_behind: None,
+ cached_git_space: crate::workspace::git_space_metadata(&snap.identity_cwd),
+ worktree_space,
public_pane_numbers,
next_public_pane_number,
active_tab: snap.active_tab.min(tabs.len().saturating_sub(1)),
@@ -121,6 +125,16 @@ fn restore_workspace(
))
}
+fn restored_worktree_space_membership(
+ space: Option<crate::workspace::WorktreeSpaceMembership>,
+) -> Option<crate::workspace::WorktreeSpaceMembership> {
+ space.filter(|space| {
+ space.checkout_path.exists()
+ && crate::workspace::git_space_metadata(&space.checkout_path)
+ .is_some_and(|current| current.key == space.key)
+ })
+}
+
fn restore_tab(
snap: &TabSnapshot,
number: usize,
@@ -407,4 +421,19 @@ mod tests {
Some(first)
);
}
+
+ #[test]
+ fn restored_worktree_space_membership_drops_missing_checkout() {
+ let missing =
+ std::env::temp_dir().join(format!("herdr-missing-worktree-{}", std::process::id()));
+ let membership = crate::workspace::WorktreeSpaceMembership {
+ key: "repo-key".into(),
+ label: "herdr".into(),
+ repo_root: missing.join("repo"),
+ checkout_path: missing.join("checkout"),
+ is_linked_worktree: true,
+ };
+
+ assert_eq!(restored_worktree_space_membership(Some(membership)), None);
+ }
}
diff --git a/src/persist/snapshot.rs b/src/persist/snapshot.rs
index a3811c36..79d5c406 100644
--- a/src/persist/snapshot.rs
+++ b/src/persist/snapshot.rs
@@ -26,6 +26,8 @@ pub struct SessionSnapshot {
pub sidebar_width: Option<u16>,
#[serde(default)]
pub sidebar_section_split: Option<f32>,
+ #[serde(default)]
+ pub collapsed_space_keys: std::collections::HashSet<String>,
}
#[derive(Serialize, Deserialize)]
@@ -35,6 +37,8 @@ pub struct WorkspaceSnapshot {
#[serde(default)]
pub custom_name: Option<String>,
pub identity_cwd: PathBuf,
+ #[serde(default, skip_serializing_if = "Option::is_none")]
+ pub worktree_space: Option<crate::workspace::WorktreeSpaceMembership>,
pub tabs: Vec<TabSnapshot>,
#[serde(default)]
pub active_tab: usize,
@@ -109,6 +113,7 @@ impl From<LegacyWorkspaceSnapshot> for WorkspaceSnapshot {
id: None,
custom_name: snap.custom_name,
identity_cwd,
+ worktree_space: None,
tabs: vec![tab],
active_tab: 0,
}
@@ -131,6 +136,8 @@ struct RawSessionSnapshot {
sidebar_width: Option<u16>,
#[serde(default)]
sidebar_section_split: Option<f32>,
+ #[serde(default)]
+ collapsed_space_keys: std::collections::HashSet<String>,
}
fn migrate_snapshot(raw: RawSessionSnapshot) -> Result<SessionSnapshot, String> {
@@ -146,6 +153,7 @@ fn migrate_snapshot(raw: RawSessionSnapshot) -> Result<SessionSnapshot, String>
agent_panel_scope: raw.agent_panel_scope,
sidebar_width: raw.sidebar_width,
sidebar_section_split: raw.sidebar_section_split,
+ collapsed_space_keys: raw.collapsed_space_keys,
})
}
@@ -208,6 +216,7 @@ pub fn capture(
agent_panel_scope: crate::app::state::AgentPanelScope,
sidebar_width: u16,
sidebar_section_split: f32,
+ collapsed_space_keys: std::collections::HashSet<String>,
) -> SessionSnapshot {
SessionSnapshot {
version: SNAPSHOT_VERSION,
@@ -220,6 +229,7 @@ pub fn capture(
agent_panel_scope,
sidebar_width: Some(sidebar_width),
sidebar_section_split: Some(sidebar_section_split),
+ collapsed_space_keys,
}
}
@@ -237,6 +247,7 @@ fn capture_workspace(
identity_cwd: ws
.resolved_identity_cwd_from(terminals, terminal_runtimes)
.unwrap_or_else(|| ws.identity_cwd.clone()),
+ worktree_space: ws.worktree_space.clone(),
tabs: ws
.tabs
.iter()
@@ -375,6 +386,7 @@ mod tests {
state.agent_panel_scope,
state.sidebar_width,
state.sidebar_section_split,
+ state.collapsed_space_keys.clone(),
)
}
@@ -395,6 +407,7 @@ mod tests {
agent_panel_scope: AgentPanelScope::CurrentWorkspace,
sidebar_width: Some(26),
sidebar_section_split: Some(0.5),
+ collapsed_space_keys: std::collections::HashSet::new(),
};
let json = serde_json::to_string(&snap).unwrap();
let restored = parse_snapshot(&json).unwrap();
@@ -451,6 +464,7 @@ mod tests {
id: Some("wproj".to_string()),
custom_name: Some("pi-mono".to_string()),
identity_cwd: PathBuf::from("/home/can/Projects/herdr"),
+ worktree_space: None,
tabs: vec![TabSnapshot {
custom_name: Some("api".to_string()),
layout: LayoutSnapshot::Split {
@@ -471,6 +485,7 @@ mod tests {
agent_panel_scope: AgentPanelScope::CurrentWorkspace,
sidebar_width: Some(26),
sidebar_section_split: Some(0.5),
+ collapsed_space_keys: std::collections::HashSet::new(),
version: SNAPSHOT_VERSION,
};
@@ -622,11 +637,32 @@ mod tests {
state.sidebar_width = 31;
state.sidebar_section_split = 0.4;
state.agent_panel_scope = AgentPanelScope::AllWorkspaces;
+ state.collapsed_space_keys.insert("repo-key".into());
let snapshot = capture_from_state(&state);
assert_eq!(snapshot.sidebar_width, Some(31));
assert_eq!(snapshot.sidebar_section_split, Some(0.4));
assert_eq!(snapshot.agent_panel_scope, AgentPanelScope::AllWorkspaces);
+ assert!(snapshot.collapsed_space_keys.contains("repo-key"));
+ }
+
+ #[test]
+ fn capture_contract_tracks_worktree_space_membership() {
+ let mut state = state_with_workspaces(&["main"]);
+ state.workspaces[0].worktree_space = Some(crate::workspace::WorktreeSpaceMembership {
+ key: "repo-key".into(),
+ label: "herdr".into(),
+ repo_root: PathBuf::from("/repo/herdr"),
+ checkout_path: PathBuf::from("/repo/herdr/worktree-a"),
+ is_linked_worktree: true,
+ });
+
+ let snapshot = capture_from_state(&state);
+
+ assert_eq!(
+ snapshot.workspaces[0].worktree_space,
+ state.workspaces[0].worktree_space
+ );
}
#[test]
@@ -776,6 +812,7 @@ mod tests {
id: Some("test-ws".to_string()),
custom_name: Some("fallback test".to_string()),
identity_cwd: PathBuf::from("/tmp"),
+ worktree_space: None,
tabs: vec![TabSnapshot {
custom_name: None,
layout: LayoutSnapshot::Split {
@@ -796,6 +833,7 @@ mod tests {
agent_panel_scope: AgentPanelScope::CurrentWorkspace,
sidebar_width: Some(26),
sidebar_section_split: Some(0.5),
+ collapsed_space_keys: std::collections::HashSet::new(),
};
let json = serde_json::to_string(&snap).unwrap();