diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-06 19:36:23 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-06 19:36:23 +0300 |
| commit | d859cf21f565e23503c6ba351c62c32c33153d77 (patch) | |
| tree | 27bac56973e903da8d81820948c2a771e8d42ffe /src | |
| parent | cbe5c150baa147649912bb1bfad40522dc3c25f3 (diff) | |
fix: keep sidebar width stable and persist user resize
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/input.rs | 12 | ||||
| -rw-r--r-- | src/app/mod.rs | 26 | ||||
| -rw-r--r-- | src/app/state.rs | 4 | ||||
| -rw-r--r-- | src/persist.rs | 9 | ||||
| -rw-r--r-- | src/ui.rs | 38 |
5 files changed, 38 insertions, 51 deletions
diff --git a/src/app/input.rs b/src/app/input.rs index 6af7cf0e..64731bf3 100644 --- a/src/app/input.rs +++ b/src/app/input.rs @@ -318,7 +318,8 @@ impl App { self.last_sidebar_divider_click = Some(now); if is_double_click { - self.state.sidebar_width_auto = true; + self.state.sidebar_width = self.state.default_sidebar_width; + self.state.sidebar_width_auto = false; self.state.drag = None; return; } @@ -1918,7 +1919,6 @@ impl AppState { self.drag = Some(DragState { target: DragTarget::SidebarDivider, }); - self.sidebar_width_auto = false; self.set_manual_sidebar_width(mouse.column); return None; } @@ -2154,7 +2154,6 @@ impl AppState { } } DragTarget::SidebarDivider => { - self.sidebar_width_auto = false; self.set_manual_sidebar_width(mouse.column); } DragTarget::ReleaseNotesScrollbar { .. } @@ -3734,21 +3733,20 @@ mod tests { app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), 25, 5)); app.handle_mouse(mouse(MouseEventKind::Drag(MouseButton::Left), 30, 5)); - assert!(!app.state.sidebar_width_auto); assert_eq!(app.state.sidebar_width, 31); } #[test] - fn double_clicking_sidebar_divider_resets_auto_width() { + fn double_clicking_sidebar_divider_resets_default_width() { let mut app = app_for_mouse_test(); - app.state.sidebar_width_auto = false; + app.state.default_sidebar_width = 26; app.state.sidebar_width = 30; app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), 25, 5)); app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), 25, 5)); app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), 25, 5)); - assert!(app.state.sidebar_width_auto); + assert_eq!(app.state.sidebar_width, 26); assert!(app.state.drag.is_none()); } diff --git a/src/app/mod.rs b/src/app/mod.rs index f06bbb19..6d677b0c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -157,12 +157,13 @@ impl App { let render_dirty = Arc::new(AtomicBool::new(false)); // Try to restore previous session - let (workspaces, active, selected, agent_panel_scope) = if no_session { + let (workspaces, active, selected, agent_panel_scope, sidebar_width) = if no_session { ( Vec::new(), None, 0, state::AgentPanelScope::CurrentWorkspace, + config.ui.sidebar_width, ) } else if let Some(snap) = crate::persist::load() { let ws = crate::persist::restore( @@ -175,12 +176,24 @@ impl App { ); if ws.is_empty() { info!("session file found but no workspaces restored"); - (Vec::new(), None, 0, snap.agent_panel_scope) + ( + Vec::new(), + None, + 0, + snap.agent_panel_scope, + snap.sidebar_width.unwrap_or(config.ui.sidebar_width), + ) } else { info!(count = ws.len(), "session restored"); let active = snap.active.filter(|&i| i < ws.len()); let selected = snap.selected.min(ws.len().saturating_sub(1)); - (ws, active, selected, snap.agent_panel_scope) + ( + ws, + active, + selected, + snap.agent_panel_scope, + snap.sidebar_width.unwrap_or(config.ui.sidebar_width), + ) } } else { ( @@ -188,6 +201,7 @@ impl App { None, 0, state::AgentPanelScope::CurrentWorkspace, + config.ui.sidebar_width, ) }; @@ -247,8 +261,9 @@ impl App { toast: None, prefix_code, prefix_mods, - sidebar_width: config.ui.sidebar_width, - sidebar_width_auto: true, + default_sidebar_width: config.ui.sidebar_width, + sidebar_width, + sidebar_width_auto: false, sidebar_collapsed: false, agent_panel_scope, confirm_close: config.ui.confirm_close, @@ -434,6 +449,7 @@ impl App { self.state.active, self.state.selected, self.state.agent_panel_scope, + self.state.sidebar_width, ); crate::persist::save(&snap); } diff --git a/src/app/state.rs b/src/app/state.rs index 60cb0511..84920131 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -595,6 +595,7 @@ pub struct AppState { // Config pub prefix_code: KeyCode, pub prefix_mods: KeyModifiers, + pub default_sidebar_width: u16, pub sidebar_width: u16, pub sidebar_width_auto: bool, pub sidebar_collapsed: bool, @@ -703,8 +704,9 @@ impl AppState { toast: None, prefix_code: KeyCode::Char('b'), prefix_mods: KeyModifiers::CONTROL, + default_sidebar_width: 26, sidebar_width: 26, - sidebar_width_auto: true, + sidebar_width_auto: false, sidebar_collapsed: false, agent_panel_scope: AgentPanelScope::CurrentWorkspace, confirm_close: true, diff --git a/src/persist.rs b/src/persist.rs index 72ac9bef..292af92d 100644 --- a/src/persist.rs +++ b/src/persist.rs @@ -32,6 +32,8 @@ pub struct SessionSnapshot { pub selected: usize, #[serde(default)] pub agent_panel_scope: crate::app::state::AgentPanelScope, + #[serde(default)] + pub sidebar_width: Option<u16>, } #[derive(Serialize)] @@ -218,6 +220,7 @@ pub fn capture( active: Option<usize>, selected: usize, agent_panel_scope: crate::app::state::AgentPanelScope, + sidebar_width: u16, ) -> SessionSnapshot { SessionSnapshot { version: SNAPSHOT_VERSION, @@ -225,6 +228,7 @@ pub fn capture( active, selected, agent_panel_scope, + sidebar_width: Some(sidebar_width), } } @@ -561,11 +565,13 @@ mod tests { active: None, selected: 0, agent_panel_scope: crate::app::state::AgentPanelScope::CurrentWorkspace, + sidebar_width: Some(26), }; let json = serde_json::to_string(&snap).unwrap(); let restored: SessionSnapshot = serde_json::from_str(&json).unwrap(); assert!(restored.workspaces.is_empty()); assert_eq!(restored.active, None); + assert_eq!(restored.sidebar_width, Some(26)); } #[test] @@ -630,6 +636,7 @@ mod tests { active: Some(0), selected: 0, agent_panel_scope: crate::app::state::AgentPanelScope::CurrentWorkspace, + sidebar_width: Some(26), version: SNAPSHOT_VERSION, }; @@ -652,6 +659,7 @@ mod tests { restored.agent_panel_scope, crate::app::state::AgentPanelScope::CurrentWorkspace ); + assert_eq!(restored.sidebar_width, Some(26)); } #[test] @@ -670,6 +678,7 @@ mod tests { restored.agent_panel_scope, crate::app::state::AgentPanelScope::CurrentWorkspace ); + assert_eq!(restored.sidebar_width, None); } #[test] @@ -208,8 +208,6 @@ fn format_agent_panel_primary_label(entry: &AgentPanelEntry, max_width: usize) - pub fn compute_view(app: &mut AppState, area: Rect) { let sidebar_w = if app.sidebar_collapsed { COLLAPSED_WIDTH - } else if app.sidebar_width_auto { - compute_sidebar_width(app) } else { app.sidebar_width .clamp(MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH) @@ -588,42 +586,6 @@ fn compute_pane_infos(app: &AppState, area: Rect) -> Vec<PaneInfo> { } /// Auto-scale sidebar width based on workspace identity + agent summary. -fn compute_sidebar_width(app: &AppState) -> u16 { - if app.workspaces.is_empty() { - return app - .sidebar_width - .clamp(MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH); - } - let max_workspace_line = app - .workspaces - .iter() - .enumerate() - .map(|(i, ws)| { - let name_len = ws.display_name().len(); - let number_len = (i + 1).to_string().len(); - // marker + number + space + name + spaces + aggregate dot - let line1 = 3 + number_len + name_len + 3; - // branch line: " branch" - let line2 = ws.branch().map(|b| 3 + b.len()).unwrap_or(0); - line1.max(line2) - }) - .max() - .unwrap_or(12); - let max_agent_line = app - .workspaces - .iter() - .flat_map(|ws| ws.pane_details().into_iter()) - .map(|detail| { - let name_line = 3 + detail.label.len(); // " icon name" - let state_line = 2 + state_label(detail.state, detail.seen).len(); // " state" - name_line.max(state_line) - }) - .max() - .unwrap_or(0); - ((max_workspace_line.max(max_agent_line) as u16) + 2) - .clamp(MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH) -} - pub(crate) fn collapsed_sidebar_sections(area: Rect) -> (Rect, Option<u16>, Rect) { let content = Rect::new(area.x, area.y, area.width.saturating_sub(1), area.height); if content.width == 0 || content.height == 0 { |
