aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-06 22:53:56 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-06 22:53:56 +0300
commit34df89ae655076b0493a1d8833f6790ca9d5c3ff (patch)
tree3b2246673fbf12f4c68a2d6528932a71a9b40b85 /src/app
parent9f94974de704646ba9b45b1cfc09cba6139e8924 (diff)
fix: persist agent panel scope in config
Diffstat (limited to 'src/app')
-rw-r--r--src/app/config_io.rs26
-rw-r--r--src/app/input/mod.rs4
-rw-r--r--src/app/input/sidebar.rs10
-rw-r--r--src/app/mod.rs71
-rw-r--r--src/app/state.rs4
5 files changed, 109 insertions, 6 deletions
diff --git a/src/app/config_io.rs b/src/app/config_io.rs
index 6c51ad9f..a9199561 100644
--- a/src/app/config_io.rs
+++ b/src/app/config_io.rs
@@ -5,6 +5,11 @@ impl App {
where
F: FnOnce(&str) -> String,
{
+ #[cfg(test)]
+ if std::env::var_os(crate::config::CONFIG_PATH_ENV_VAR).is_none() {
+ return false;
+ }
+
let path = crate::config::config_path();
if let Some(parent) = path.parent() {
if let Err(err) = std::fs::create_dir_all(parent) {
@@ -66,4 +71,25 @@ impl App {
self.apply_config_from_disk(false);
}
}
+
+ pub(super) fn save_agent_panel_scope(&mut self, scope: crate::app::state::AgentPanelScope) {
+ let value = match scope {
+ crate::app::state::AgentPanelScope::CurrentWorkspace => {
+ crate::config::AgentPanelScopeConfig::Current.as_str()
+ }
+ crate::app::state::AgentPanelScope::AllWorkspaces => {
+ crate::config::AgentPanelScopeConfig::All.as_str()
+ }
+ };
+ if self.update_config_file("agent panel scope", |content| {
+ crate::config::upsert_section_value(
+ content,
+ "ui",
+ "agent_panel_scope",
+ &format!("\"{value}\""),
+ )
+ }) {
+ self.apply_config_from_disk(false);
+ }
+ }
}
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs
index 3beeac6b..56ad09a9 100644
--- a/src/app/input/mod.rs
+++ b/src/app/input/mod.rs
@@ -148,6 +148,7 @@ impl App {
}
}
+ let previous_agent_panel_scope = self.state.agent_panel_scope;
if let Some(action) = self.state.handle_mouse(mouse) {
match action {
SettingsAction::SaveTheme(name) => self.save_theme(&name),
@@ -155,6 +156,9 @@ impl App {
SettingsAction::SaveToastDelivery(delivery) => self.save_toast_delivery(delivery),
}
}
+ if self.state.agent_panel_scope != previous_agent_panel_scope {
+ self.save_agent_panel_scope(self.state.agent_panel_scope);
+ }
if let Some(content) = self.state.request_clipboard_write.take() {
if self
diff --git a/src/app/input/sidebar.rs b/src/app/input/sidebar.rs
index fe8f14c1..8f6c7792 100644
--- a/src/app/input/sidebar.rs
+++ b/src/app/input/sidebar.rs
@@ -686,10 +686,16 @@ mod tests {
toggle.y,
));
- assert_eq!(app.state.agent_panel_scope, AgentPanelScope::AllWorkspaces);
+ assert_eq!(
+ app.state.agent_panel_scope,
+ AgentPanelScope::CurrentWorkspace
+ );
assert_eq!(app.state.agent_panel_scroll, 0);
let snapshot = capture_snapshot(&app.state);
- assert_eq!(snapshot.agent_panel_scope, AgentPanelScope::AllWorkspaces);
+ assert_eq!(
+ snapshot.agent_panel_scope,
+ AgentPanelScope::CurrentWorkspace
+ );
}
#[test]
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 35f502a5..ffef6600 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -115,6 +115,15 @@ fn auto_updates_enabled(no_session: bool) -> bool {
!no_session && !cfg!(debug_assertions)
}
+fn agent_panel_scope_from_config(
+ scope: crate::config::AgentPanelScopeConfig,
+) -> state::AgentPanelScope {
+ match scope {
+ crate::config::AgentPanelScopeConfig::Current => state::AgentPanelScope::CurrentWorkspace,
+ crate::config::AgentPanelScopeConfig::All => state::AgentPanelScope::AllWorkspaces,
+ }
+}
+
/// Resolve the palette from config: base theme + optional custom overrides.
fn resolve_palette(config: &crate::config::Config) -> state::Palette {
resolve_palette_with_legacy_accent(config, true)
@@ -174,7 +183,7 @@ impl App {
workspaces,
active,
selected,
- agent_panel_scope,
+ _restored_agent_panel_scope,
sidebar_width,
sidebar_width_source,
sidebar_section_split,
@@ -243,6 +252,8 @@ impl App {
)
};
+ let agent_panel_scope = agent_panel_scope_from_config(config.ui.agent_panel_scope);
+
info!(
pane_scrollback_limit_bytes = config.advanced.scrollback_limit_bytes,
"using pane scrollback configuration"
@@ -635,6 +646,9 @@ impl App {
self.state.sidebar_width = config.ui.sidebar_width;
}
self.state.confirm_close = config.ui.confirm_close;
+ self.state.agent_panel_scope =
+ agent_panel_scope_from_config(config.ui.agent_panel_scope);
+ self.state.agent_panel_scroll = 0;
self.state.accent = crate::config::parse_color(&config.ui.accent);
if !self.state.local_sound_playback && self.state.sound != config.ui.sound {
self.state.request_client_sound_config_reload = true;
@@ -892,6 +906,27 @@ mod tests {
}
#[test]
+ fn startup_uses_configured_agent_panel_scope() {
+ let mut config = Config::default();
+ config.ui.agent_panel_scope = crate::config::AgentPanelScopeConfig::Current;
+ let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel();
+
+ let app = App::new(
+ &config,
+ true,
+ None,
+ None,
+ api_rx,
+ crate::api::EventHub::default(),
+ );
+
+ assert_eq!(
+ app.state.agent_panel_scope,
+ state::AgentPanelScope::CurrentWorkspace
+ );
+ }
+
+ #[test]
fn startup_restores_preview_update_available_from_saved_notes() {
let _guard = config_env_lock().lock().unwrap();
let path = temp_config_path("startup-preview-update-available");
@@ -933,7 +968,7 @@ mod tests {
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(
&path,
- "[keys]\nnew_workspace = \"g\"\nprefix = \"ctrl+a\"\n[ui.toast]\ndelivery = \"herdr\"\n",
+ "[keys]\nnew_workspace = \"g\"\nprefix = \"ctrl+a\"\n[ui]\nagent_panel_scope = \"current\"\n[ui.toast]\ndelivery = \"herdr\"\n",
)
.unwrap();
std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path);
@@ -952,6 +987,10 @@ mod tests {
app.state.toast_config.delivery,
crate::config::ToastDelivery::Herdr
);
+ assert_eq!(
+ app.state.agent_panel_scope,
+ state::AgentPanelScope::CurrentWorkspace
+ );
assert!(app.state.config_diagnostic.is_none());
let toast = app.state.toast.as_ref().unwrap();
assert_eq!(toast.kind, crate::app::state::ToastKind::UpdateInstalled);
@@ -1097,6 +1136,34 @@ mod tests {
}
#[test]
+ fn save_agent_panel_scope_persists_then_applies_live_config() {
+ let _guard = config_env_lock().lock().unwrap();
+ let path = temp_config_path("save-agent-panel-scope");
+ std::fs::create_dir_all(path.parent().unwrap()).unwrap();
+ std::fs::write(&path, "onboarding = false\n").unwrap();
+ std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path);
+
+ let mut app = test_app();
+ assert_eq!(
+ app.state.agent_panel_scope,
+ state::AgentPanelScope::AllWorkspaces
+ );
+
+ app.save_agent_panel_scope(state::AgentPanelScope::CurrentWorkspace);
+
+ assert_eq!(
+ app.state.agent_panel_scope,
+ state::AgentPanelScope::CurrentWorkspace
+ );
+ let content = std::fs::read_to_string(&path).unwrap();
+ assert!(content.contains("agent_panel_scope = \"current\""));
+ assert!(app.state.config_diagnostic.is_none());
+
+ std::env::remove_var(crate::config::CONFIG_PATH_ENV_VAR);
+ let _ = std::fs::remove_dir_all(path.parent().unwrap());
+ }
+
+ #[test]
fn reload_config_keeps_current_state_on_invalid_toml() {
let _guard = config_env_lock().lock().unwrap();
let path = temp_config_path("reload-config-invalid-toml");
diff --git a/src/app/state.rs b/src/app/state.rs
index 97f87f3c..95caa3fe 100644
--- a/src/app/state.rs
+++ b/src/app/state.rs
@@ -398,7 +398,7 @@ pub enum AgentPanelScope {
impl Default for AgentPanelScope {
fn default() -> Self {
- Self::CurrentWorkspace
+ Self::AllWorkspaces
}
}
@@ -815,7 +815,7 @@ impl AppState {
sidebar_width_auto: false,
sidebar_collapsed: false,
sidebar_section_split: 0.5,
- agent_panel_scope: AgentPanelScope::CurrentWorkspace,
+ agent_panel_scope: AgentPanelScope::AllWorkspaces,
confirm_close: true,
pane_scrollback_limit_bytes: crate::config::DEFAULT_SCROLLBACK_LIMIT_BYTES,
accent: Color::Cyan,