Add a setting for Threads Sidebar auto-open (#64259)
Closes https://github.com/zed-industries/zed/discussions/64266 Opening a folder in an existing window force-opens the Threads Sidebar, and there is no way to prevent it. `open_paths` called `MultiWorkspace::open_sidebar` unconditionally on the reused window, so the sidebar reopened on every such open regardless of whether the user had closed it. This adds `agent.threads_sidebar_auto_open`, defaulting to `true` so current behavior is unchanged. With `false`, the folder still opens in the existing window, but the sidebar stays closed. This path is reached when `default_open_behavior` or `cli_default_open_behavior` is set to `existing_window`. `open_sidebar` was doing double duty: besides showing the sidebar, it pinned the workspace being navigated away from so it survives the switch. When the setting is disabled, `retain_active_workspace` is called instead, so only sidebar visibility changes. https://github.com/user-attachments/assets/fc299df0-27e2-4ac6-98cb-d817d5f71d0e ## Tests Two tests in `multi_workspace_tests.rs` cover both branches: the sidebar opens by default, and stays closed when the setting is disabled while the folder still opens in the same window. Release Notes: - Added `agent.threads_sidebar_auto_open` to control whether opening a folder in an existing window also opens the Threads Sidebar
This commit is contained in:
1 parent
2433f1d15d
commit
d9abcde22a
9 files changed
+161
-2
No files matched your search
@@ -1157,6 +1157,10 @@
|
||||
"sidebar_side": "left",
|
||||
// Default width of the Threads Sidebar.
|
||||
"threads_sidebar_default_width": 300,
|
||||
// Whether opening a folder in an existing window automatically opens the
|
||||
// Threads Sidebar. Applies when `default_open_behavior` or
|
||||
// `cli_default_open_behavior` is set to "existing_window".
|
||||
"threads_sidebar_auto_open": true,
|
||||
// Default fixed width when the agent panel is docked to the left or right and
|
||||
// `flexible` is false.
|
||||
"default_width": 640,
|
||||
|
||||
@@ -610,6 +610,7 @@ mod tests {
|
||||
show_merge_conflict_indicator: true,
|
||||
sidebar_side: Default::default(),
|
||||
threads_sidebar_default_width: px(300.),
|
||||
threads_sidebar_auto_open: true,
|
||||
thinking_display: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +215,7 @@ pub struct AgentSettings {
|
||||
pub flexible: bool,
|
||||
pub sidebar_side: SidebarDockPosition,
|
||||
pub threads_sidebar_default_width: Pixels,
|
||||
pub threads_sidebar_auto_open: bool,
|
||||
pub default_width: Pixels,
|
||||
pub default_height: Pixels,
|
||||
pub max_content_width: Option<Pixels>,
|
||||
@@ -774,6 +775,7 @@ impl Settings for AgentSettings {
|
||||
.unwrap()
|
||||
.into_gpui()
|
||||
.clamp(THREADS_LIST_MIN_WIDTH, THREADS_LIST_MAX_WIDTH),
|
||||
threads_sidebar_auto_open: agent.threads_sidebar_auto_open.unwrap(),
|
||||
default_width: agent.default_width.unwrap().into_gpui(),
|
||||
default_height: agent.default_height.unwrap().into_gpui(),
|
||||
max_content_width: if agent.limit_content_width.unwrap() {
|
||||
|
||||
@@ -1012,6 +1012,7 @@ mod tests {
|
||||
show_merge_conflict_indicator: true,
|
||||
sidebar_side: Default::default(),
|
||||
threads_sidebar_default_width: px(300.),
|
||||
threads_sidebar_auto_open: true,
|
||||
thinking_display: Default::default(),
|
||||
};
|
||||
|
||||
|
||||
@@ -226,6 +226,17 @@ pub struct AgentSettingsContent {
|
||||
/// Default: 300
|
||||
#[schemars(range(min = 200, max = 800))]
|
||||
pub threads_sidebar_default_width: Option<crate::PixelSetting>,
|
||||
/// Whether opening a folder in an existing window automatically opens the
|
||||
/// Threads Sidebar.
|
||||
///
|
||||
/// This applies when a folder opens in an existing window instead of a new
|
||||
/// one, which happens when `default_open_behavior` or
|
||||
/// `cli_default_open_behavior` is set to `existing_window`. When disabled,
|
||||
/// the folder still opens in that window, but the sidebar stays closed
|
||||
/// until you open it.
|
||||
///
|
||||
/// Default: true
|
||||
pub threads_sidebar_auto_open: Option<bool>,
|
||||
/// Default fixed width in pixels when the agent panel is docked to the left or right and
|
||||
/// `flexible` is false.
|
||||
///
|
||||
|
||||
@@ -6829,7 +6829,7 @@ fn panels_page() -> SettingsPage {
|
||||
]
|
||||
}
|
||||
|
||||
fn agent_panel_section() -> [SettingsPageItem; 8] {
|
||||
fn agent_panel_section() -> [SettingsPageItem; 9] {
|
||||
[
|
||||
SettingsPageItem::SectionHeader("Agent Panel"),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
@@ -6913,6 +6913,29 @@ fn panels_page() -> SettingsPage {
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Threads Sidebar Auto Open",
|
||||
description: "Whether opening a folder in an existing window automatically opens the Threads Sidebar.",
|
||||
field: Box::new(SettingField {
|
||||
organization_override: None,
|
||||
json_path: Some("agent.threads_sidebar_auto_open"),
|
||||
pick: |settings_content| {
|
||||
settings_content
|
||||
.agent
|
||||
.as_ref()?
|
||||
.threads_sidebar_auto_open
|
||||
.as_ref()
|
||||
},
|
||||
write: |settings_content, value, _| {
|
||||
settings_content
|
||||
.agent
|
||||
.get_or_insert_default()
|
||||
.threads_sidebar_auto_open = value;
|
||||
},
|
||||
}),
|
||||
metadata: None,
|
||||
files: USER,
|
||||
}),
|
||||
SettingsPageItem::SettingItem(SettingItem {
|
||||
title: "Agent Panel Default Height",
|
||||
description: "Default height when the agent panel is docked to the bottom.",
|
||||
|
||||
@@ -316,6 +316,93 @@ async fn test_open_new_window_does_not_open_sidebar_on_existing_window(cx: &mut
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_directory_in_existing_window_opens_sidebar(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let app_state = cx.update(AppState::test);
|
||||
let fs = app_state.fs.as_fake();
|
||||
fs.insert_tree(path!("/project_a"), json!({ "file.txt": "" }))
|
||||
.await;
|
||||
fs.insert_tree(path!("/project_b"), json!({ "file.txt": "" }))
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/project_a").as_ref()], cx).await;
|
||||
let window = cx.add_window(|window, cx| MultiWorkspace::test_new(project, window, cx));
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
&[PathBuf::from(path!("/project_b"))],
|
||||
app_state,
|
||||
OpenOptions::default(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
window
|
||||
.read_with(cx, |mw, _cx| {
|
||||
assert!(
|
||||
mw.sidebar_open(),
|
||||
"adding a directory to an existing window opens the sidebar by default",
|
||||
);
|
||||
assert_eq!(mw.workspaces().count(), 2);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_directory_in_existing_window_respects_auto_open_setting(
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let app_state = cx.update(AppState::test);
|
||||
let fs = app_state.fs.as_fake();
|
||||
fs.insert_tree(path!("/project_a"), json!({ "file.txt": "" }))
|
||||
.await;
|
||||
fs.insert_tree(path!("/project_b"), json!({ "file.txt": "" }))
|
||||
.await;
|
||||
|
||||
cx.update(|cx| {
|
||||
let mut settings = AgentSettings::get_global(cx).clone();
|
||||
settings.threads_sidebar_auto_open = false;
|
||||
AgentSettings::override_global(settings, cx);
|
||||
});
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/project_a").as_ref()], cx).await;
|
||||
let window = cx.add_window(|window, cx| MultiWorkspace::test_new(project, window, cx));
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update(|cx| {
|
||||
open_paths(
|
||||
&[PathBuf::from(path!("/project_b"))],
|
||||
app_state,
|
||||
OpenOptions::default(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
window
|
||||
.read_with(cx, |mw, _cx| {
|
||||
assert!(
|
||||
!mw.sidebar_open(),
|
||||
"the sidebar must stay closed when `threads_sidebar_auto_open` is disabled",
|
||||
);
|
||||
assert_eq!(
|
||||
mw.workspaces().count(),
|
||||
2,
|
||||
"the directory is still added to the existing window, and the workspace it \
|
||||
replaces is retained",
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_directory_in_empty_workspace_does_not_open_sidebar(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
@@ -43,6 +43,7 @@ pub use remote::{
|
||||
};
|
||||
pub use toast_layer::{ToastAction, ToastLayer, ToastView};
|
||||
|
||||
use agent_settings::AgentSettings;
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use client::{
|
||||
ChannelId, Client, ErrorExt, ParticipantIndex, Status, TypedEnvelope, User, UserStore,
|
||||
@@ -11168,7 +11169,14 @@ pub fn open_paths(
|
||||
open_options.requesting_window = Some(window);
|
||||
window
|
||||
.update(cx, |multi_workspace, _, cx| {
|
||||
multi_workspace.open_sidebar(cx);
|
||||
if AgentSettings::get_global(cx).threads_sidebar_auto_open {
|
||||
multi_workspace.open_sidebar(cx);
|
||||
} else {
|
||||
// Opening the sidebar is also what pins the
|
||||
// workspace we are about to navigate away from,
|
||||
// so pin it here to keep it in this window.
|
||||
multi_workspace.retain_active_workspace(cx);
|
||||
}
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
@@ -145,6 +145,28 @@ If you haven’t manually resized the sidebar, its width follows changes to this
|
||||
|
||||
Widths saved by older versions of Zed are preserved if they differ from the previous default of 300 pixels. A saved width of 300 pixels uses this setting instead.
|
||||
|
||||
### Threads Sidebar Auto Open {#agent-threads-sidebar-auto-open}
|
||||
|
||||
- Description: Whether opening a folder in an existing window automatically opens the [Threads Sidebar](../ai/parallel-agents.md#threads-sidebar).
|
||||
- Setting: `agent.threads_sidebar_auto_open`
|
||||
- Default: `true`
|
||||
|
||||
**Options**
|
||||
|
||||
`true` or `false`.
|
||||
|
||||
This applies when a folder opens in an existing window instead of a new one, which happens when `default_open_behavior` or `cli_default_open_behavior` is set to `existing_window`. With `false`, the folder still opens in that window, but the sidebar stays closed until you open it with {#action multi_workspace::ToggleWorkspaceSidebar}.
|
||||
|
||||
Open the Settings Editor and search for “Threads Sidebar Auto Open”. Or add this to your `settings.json`:
|
||||
|
||||
```json [settings]
|
||||
{
|
||||
"agent": {
|
||||
"threads_sidebar_auto_open": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Agent UI Font Size
|
||||
|
||||
- Description: The font size for text in the agent panel. Inherits the UI font size if unset.
|
||||
|
||||
Reference in new issue
Block a user