From 2f1b9fcd5d38b790a6774dcb03b28719672f38fb Mon Sep 17 00:00:00 2001 From: Tom You Date: Mon, 6 Jul 2026 23:59:11 -0500 Subject: [PATCH] feat(core): serialize workspace state --- Cargo.lock | 4 ++++ rabby-core/Cargo.toml | 6 ++++++ rabby-core/src/config/mod.rs | 5 +++-- rabby-core/src/workspace/mod.rs | 33 +++++++++++++++++++++++++++------ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8ee02a..32fd097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2300,6 +2300,10 @@ dependencies = [ [[package]] name = "rabby-core" version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] [[package]] name = "raw-window-handle" diff --git a/rabby-core/Cargo.toml b/rabby-core/Cargo.toml index a477778..1dc722a 100644 --- a/rabby-core/Cargo.toml +++ b/rabby-core/Cargo.toml @@ -7,3 +7,9 @@ repository.workspace = true [lib] path = "src/lib.rs" + +[dependencies] +serde = { version = "1", features = ["derive"] } + +[dev-dependencies] +serde_json = "1" diff --git a/rabby-core/src/config/mod.rs b/rabby-core/src/config/mod.rs index 88768e4..8dff42d 100644 --- a/rabby-core/src/config/mod.rs +++ b/rabby-core/src/config/mod.rs @@ -1,13 +1,14 @@ use crate::{ConnectionKind, Profile}; +use serde::{Deserialize, Serialize}; use std::collections::HashSet; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ShortcutBinding { pub command: String, pub binding: String, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct AppConfig { pub profiles: Vec, pub theme_id: String, diff --git a/rabby-core/src/workspace/mod.rs b/rabby-core/src/workspace/mod.rs index bdb7201..ec8fd41 100644 --- a/rabby-core/src/workspace/mod.rs +++ b/rabby-core/src/workspace/mod.rs @@ -1,6 +1,7 @@ use crate::slug; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum ConnectionKind { LocalShell, Ssh, @@ -8,7 +9,7 @@ pub enum ConnectionKind { Serial, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Profile { pub id: String, pub name: String, @@ -38,7 +39,7 @@ impl Profile { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum PaneNode { Leaf { profile_id: String, @@ -51,7 +52,7 @@ pub enum PaneNode { }, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum SplitAxis { Horizontal, Vertical, @@ -89,14 +90,14 @@ impl PaneNode { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Tab { pub title: String, pub root: PaneNode, pub progress: Option, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Workspace { pub profiles: Vec, pub tabs: Vec, @@ -239,4 +240,24 @@ mod tests { assert_eq!(ws.tabs[0].progress, Some(42)); assert!(ws.set_tab_progress(0, Some(101)).is_err()); } + + #[test] + fn workspace_round_trips_nested_splits() { + let mut ws = Workspace::default_linux(); + ws.add_profile( + Profile::new("ssh-prod", "Prod SSH", ConnectionKind::Ssh, "ssh prod").unwrap(), + ) + .unwrap(); + ws.tabs[0].root = PaneNode::leaf("local") + .split(SplitAxis::Horizontal, PaneNode::leaf("ssh-prod"), 55) + .unwrap(); + ws.set_quake_mode(true); + + let encoded = serde_json::to_string(&ws).unwrap(); + let decoded: Workspace = serde_json::from_str(&encoded).unwrap(); + + assert_eq!(decoded, ws); + assert_eq!(decoded.tabs[0].root.leaf_count(), 2); + assert!(decoded.quake_mode); + } }