Cargo.lock π
@@ -13078,6 +13078,7 @@ dependencies = [
"settings",
"smallvec",
"telemetry",
+ "tempfile",
"theme",
"ui",
"util",
Miguel CΓ‘rdenas and Smit Barmase created
- Based on #40234, and improvement of #40331
Release Notes:
- Added granular settings to control when files auto-open in the project
panel (project_panel.auto_open.on_create, on_paste, on_drop)
<img width="662" height="367" alt="Screenshot_2025-10-16_17-28-31"
src="https://github.com/user-attachments/assets/930a0a50-fc89-4c5d-8d05-b1fa2279de8b"
/>
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Cargo.lock | 1
assets/settings/default.json | 11
crates/migrator/src/migrations.rs | 6
crates/migrator/src/migrations/m_2025_11_12/settings.rs | 84 +++
crates/migrator/src/migrator.rs | 53 ++
crates/project_panel/Cargo.toml | 1
crates/project_panel/src/project_panel.rs | 29
crates/project_panel/src/project_panel_settings.rs | 35 +
crates/project_panel/src/project_panel_tests.rs | 257 ++++++++++
crates/settings/src/settings_content/workspace.rs | 23
crates/settings/src/vscode_import.rs | 2
crates/settings_ui/src/page_data.rs | 48 +
docs/src/configuring-zed.md | 26 +
13 files changed, 542 insertions(+), 34 deletions(-)
@@ -13078,6 +13078,7 @@ dependencies = [
"settings",
"smallvec",
"telemetry",
+ "tempfile",
"theme",
"ui",
"util",
@@ -748,8 +748,15 @@
"hide_root": false,
// Whether to hide the hidden entries in the project panel.
"hide_hidden": false,
- // Whether to automatically open files when pasting them in the project panel.
- "open_file_on_paste": true
+ // Settings for automatically opening files.
+ "auto_open": {
+ // Whether to automatically open newly created files in the editor.
+ "on_create": true,
+ // Whether to automatically open files after pasting or duplicating them.
+ "on_paste": true,
+ // Whether to automatically open files dropped from external sources.
+ "on_drop": true
+ }
},
"outline_panel": {
// Whether to show the outline panel button in the status bar
@@ -135,3 +135,9 @@ pub(crate) mod m_2025_10_21 {
pub(crate) use settings::make_relative_line_numbers_an_enum;
}
+
+pub(crate) mod m_2025_11_12 {
+ mod settings;
+
+ pub(crate) use settings::SETTINGS_PATTERNS;
+}
@@ -0,0 +1,84 @@
+use std::ops::Range;
+use tree_sitter::{Query, QueryMatch};
+
+use crate::MigrationPatterns;
+use crate::patterns::SETTINGS_NESTED_KEY_VALUE_PATTERN;
+
+pub const SETTINGS_PATTERNS: MigrationPatterns = &[
+ (
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
+ rename_open_file_on_paste_setting,
+ ),
+ (
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
+ replace_open_file_on_paste_setting_value,
+ ),
+];
+
+fn rename_open_file_on_paste_setting(
+ contents: &str,
+ mat: &QueryMatch,
+ query: &Query,
+) -> Option<(Range<usize>, String)> {
+ if !is_project_panel_open_file_on_paste(contents, mat, query) {
+ return None;
+ }
+
+ let setting_name_ix = query.capture_index_for_name("setting_name")?;
+ let setting_name_range = mat
+ .nodes_for_capture_index(setting_name_ix)
+ .next()?
+ .byte_range();
+
+ Some((setting_name_range, "auto_open".to_string()))
+}
+
+fn replace_open_file_on_paste_setting_value(
+ contents: &str,
+ mat: &QueryMatch,
+ query: &Query,
+) -> Option<(Range<usize>, String)> {
+ if !is_project_panel_open_file_on_paste(contents, mat, query) {
+ return None;
+ }
+
+ let value_ix = query.capture_index_for_name("setting_value")?;
+ let value_node = mat.nodes_for_capture_index(value_ix).next()?;
+ let value_range = value_node.byte_range();
+ let value_text = contents.get(value_range.clone())?.trim();
+
+ let normalized_value = match value_text {
+ "true" => "true",
+ "false" => "false",
+ _ => return None,
+ };
+
+ Some((
+ value_range,
+ format!("{{ \"on_paste\": {normalized_value} }}"),
+ ))
+}
+
+fn is_project_panel_open_file_on_paste(contents: &str, mat: &QueryMatch, query: &Query) -> bool {
+ let parent_key_ix = match query.capture_index_for_name("parent_key") {
+ Some(ix) => ix,
+ None => return false,
+ };
+ let parent_range = match mat.nodes_for_capture_index(parent_key_ix).next() {
+ Some(node) => node.byte_range(),
+ None => return false,
+ };
+ if contents.get(parent_range) != Some("project_panel") {
+ return false;
+ }
+
+ let setting_name_ix = match query.capture_index_for_name("setting_name") {
+ Some(ix) => ix,
+ None => return false,
+ };
+ let setting_name_range = match mat.nodes_for_capture_index(setting_name_ix).next() {
+ Some(node) => node.byte_range(),
+ None => return false,
+ };
+ contents.get(setting_name_range) == Some("open_file_on_paste")
+}
@@ -215,6 +215,10 @@ pub fn migrate_settings(text: &str) -> Result<Option<String>> {
MigrationType::Json(migrations::m_2025_10_16::restore_code_actions_on_format),
MigrationType::Json(migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum),
MigrationType::Json(migrations::m_2025_10_21::make_relative_line_numbers_an_enum),
+ MigrationType::TreeSitter(
+ migrations::m_2025_11_12::SETTINGS_PATTERNS,
+ &SETTINGS_QUERY_2025_11_12,
+ ),
];
run_migrations(text, migrations)
}
@@ -333,6 +337,10 @@ define_query!(
SETTINGS_QUERY_2025_10_03,
migrations::m_2025_10_03::SETTINGS_PATTERNS
);
+define_query!(
+ SETTINGS_QUERY_2025_11_12,
+ migrations::m_2025_11_12::SETTINGS_PATTERNS
+);
// custom query
static EDIT_PREDICTION_SETTINGS_MIGRATION_QUERY: LazyLock<Query> = LazyLock::new(|| {
@@ -2193,4 +2201,49 @@ mod tests {
),
);
}
+
+ #[test]
+ fn test_project_panel_open_file_on_paste_migration() {
+ assert_migrate_settings(
+ &r#"
+ {
+ "project_panel": {
+ "open_file_on_paste": true
+ }
+ }
+ "#
+ .unindent(),
+ Some(
+ &r#"
+ {
+ "project_panel": {
+ "auto_open": { "on_paste": true }
+ }
+ }
+ "#
+ .unindent(),
+ ),
+ );
+
+ assert_migrate_settings(
+ &r#"
+ {
+ "project_panel": {
+ "open_file_on_paste": false
+ }
+ }
+ "#
+ .unindent(),
+ Some(
+ &r#"
+ {
+ "project_panel": {
+ "auto_open": { "on_paste": false }
+ }
+ }
+ "#
+ .unindent(),
+ ),
+ );
+ }
}
@@ -53,4 +53,5 @@ editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }
language = { workspace = true, features = ["test-support"] }
serde_json.workspace = true
+tempfile.workspace = true
workspace = { workspace = true, features = ["test-support"] }
@@ -1655,7 +1655,10 @@ impl ProjectPanel {
}
project_panel.update_visible_entries(None, false, false, window, cx);
if is_new_entry && !is_dir {
- project_panel.open_entry(new_entry.id, true, false, cx);
+ let settings = ProjectPanelSettings::get_global(cx);
+ if settings.auto_open.should_open_on_create() {
+ project_panel.open_entry(new_entry.id, true, false, cx);
+ }
}
cx.notify();
})?;
@@ -2709,15 +2712,16 @@ impl ProjectPanel {
if item_count == 1 {
// open entry if not dir, setting is enabled, and only focus if rename is not pending
- if !entry.is_dir()
- && ProjectPanelSettings::get_global(cx).open_file_on_paste
- {
- project_panel.open_entry(
- entry.id,
- disambiguation_range.is_none(),
- false,
- cx,
- );
+ if !entry.is_dir() {
+ let settings = ProjectPanelSettings::get_global(cx);
+ if settings.auto_open.should_open_on_paste() {
+ project_panel.open_entry(
+ entry.id,
+ disambiguation_range.is_none(),
+ false,
+ cx,
+ );
+ }
}
// if only one entry was pasted and it was disambiguated, open the rename editor
@@ -3593,7 +3597,10 @@ impl ProjectPanel {
let opened_entries = task.await.with_context(|| "failed to copy external paths")?;
this.update(cx, |this, cx| {
if open_file_after_drop && !opened_entries.is_empty() {
- this.open_entry(opened_entries[0], true, false, cx);
+ let settings = ProjectPanelSettings::get_global(cx);
+ if settings.auto_open.should_open_on_drop() {
+ this.open_entry(opened_entries[0], true, false, cx);
+ }
}
})
}
@@ -32,7 +32,7 @@ pub struct ProjectPanelSettings {
pub hide_root: bool,
pub hide_hidden: bool,
pub drag_and_drop: bool,
- pub open_file_on_paste: bool,
+ pub auto_open: AutoOpenSettings,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -48,6 +48,30 @@ pub struct ScrollbarSettings {
pub show: Option<ShowScrollbar>,
}
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+pub struct AutoOpenSettings {
+ pub on_create: bool,
+ pub on_paste: bool,
+ pub on_drop: bool,
+}
+
+impl AutoOpenSettings {
+ #[inline]
+ pub fn should_open_on_create(self) -> bool {
+ self.on_create
+ }
+
+ #[inline]
+ pub fn should_open_on_paste(self) -> bool {
+ self.on_paste
+ }
+
+ #[inline]
+ pub fn should_open_on_drop(self) -> bool {
+ self.on_drop
+ }
+}
+
impl ScrollbarVisibility for ProjectPanelSettings {
fn visibility(&self, cx: &ui::App) -> ShowScrollbar {
self.scrollbar
@@ -83,7 +107,14 @@ impl Settings for ProjectPanelSettings {
hide_root: project_panel.hide_root.unwrap(),
hide_hidden: project_panel.hide_hidden.unwrap(),
drag_and_drop: project_panel.drag_and_drop.unwrap(),
- open_file_on_paste: project_panel.open_file_on_paste.unwrap(),
+ auto_open: {
+ let auto_open = project_panel.auto_open.unwrap();
+ AutoOpenSettings {
+ on_create: auto_open.on_create.unwrap(),
+ on_paste: auto_open.on_paste.unwrap(),
+ on_drop: auto_open.on_drop.unwrap(),
+ }
+ },
}
}
}
@@ -4,7 +4,7 @@ use gpui::{Empty, Entity, TestAppContext, VisualTestContext, WindowHandle};
use pretty_assertions::assert_eq;
use project::FakeFs;
use serde_json::json;
-use settings::SettingsStore;
+use settings::{ProjectPanelAutoOpenSettings, SettingsStore};
use std::path::{Path, PathBuf};
use util::{path, paths::PathStyle, rel_path::rel_path};
use workspace::{
@@ -1998,6 +1998,248 @@ async fn test_remove_opened_file(cx: &mut gpui::TestAppContext) {
ensure_no_open_items_and_panes(&workspace, cx);
}
+#[gpui::test]
+async fn test_auto_open_new_file_when_enabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_create: Some(true),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(path!("/root"), json!({})).await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ panel.update_in(cx, |panel, window, cx| panel.new_file(&NewFile, window, cx));
+ cx.run_until_parked();
+ panel
+ .update_in(cx, |panel, window, cx| {
+ panel.filename_editor.update(cx, |editor, cx| {
+ editor.set_text("auto-open.rs", window, cx);
+ });
+ panel.confirm_edit(true, window, cx).unwrap()
+ })
+ .await
+ .unwrap();
+ cx.run_until_parked();
+
+ ensure_single_file_is_opened(&workspace, "auto-open.rs", cx);
+}
+
+#[gpui::test]
+async fn test_auto_open_new_file_when_disabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_create: Some(false),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(path!("/root"), json!({})).await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ panel.update_in(cx, |panel, window, cx| panel.new_file(&NewFile, window, cx));
+ cx.run_until_parked();
+ panel
+ .update_in(cx, |panel, window, cx| {
+ panel.filename_editor.update(cx, |editor, cx| {
+ editor.set_text("manual-open.rs", window, cx);
+ });
+ panel.confirm_edit(true, window, cx).unwrap()
+ })
+ .await
+ .unwrap();
+ cx.run_until_parked();
+
+ ensure_no_open_items_and_panes(&workspace, cx);
+}
+
+#[gpui::test]
+async fn test_auto_open_on_paste_when_enabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_paste: Some(true),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ path!("/root"),
+ json!({
+ "src": {
+ "original.rs": ""
+ },
+ "target": {}
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ toggle_expand_dir(&panel, "root/src", cx);
+ toggle_expand_dir(&panel, "root/target", cx);
+
+ select_path(&panel, "root/src/original.rs", cx);
+ panel.update_in(cx, |panel, window, cx| {
+ panel.copy(&Default::default(), window, cx);
+ });
+
+ select_path(&panel, "root/target", cx);
+ panel.update_in(cx, |panel, window, cx| {
+ panel.paste(&Default::default(), window, cx);
+ });
+ cx.executor().run_until_parked();
+
+ ensure_single_file_is_opened(&workspace, "target/original.rs", cx);
+}
+
+#[gpui::test]
+async fn test_auto_open_on_paste_when_disabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_paste: Some(false),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ path!("/root"),
+ json!({
+ "src": {
+ "original.rs": ""
+ },
+ "target": {}
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ toggle_expand_dir(&panel, "root/src", cx);
+ toggle_expand_dir(&panel, "root/target", cx);
+
+ select_path(&panel, "root/src/original.rs", cx);
+ panel.update_in(cx, |panel, window, cx| {
+ panel.copy(&Default::default(), window, cx);
+ });
+
+ select_path(&panel, "root/target", cx);
+ panel.update_in(cx, |panel, window, cx| {
+ panel.paste(&Default::default(), window, cx);
+ });
+ cx.executor().run_until_parked();
+
+ ensure_no_open_items_and_panes(&workspace, cx);
+ assert!(
+ find_project_entry(&panel, "root/target/original.rs", cx).is_some(),
+ "Pasted entry should exist even when auto-open is disabled"
+ );
+}
+
+#[gpui::test]
+async fn test_auto_open_on_drop_when_enabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_drop: Some(true),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(path!("/root"), json!({})).await;
+
+ let temp_dir = tempfile::tempdir().unwrap();
+ let external_path = temp_dir.path().join("dropped.rs");
+ std::fs::write(&external_path, "// dropped").unwrap();
+ fs.insert_tree_from_real_fs(temp_dir.path(), temp_dir.path())
+ .await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ let root_entry = find_project_entry(&panel, "root", cx).unwrap();
+ panel.update_in(cx, |panel, window, cx| {
+ panel.drop_external_files(std::slice::from_ref(&external_path), root_entry, window, cx);
+ });
+ cx.executor().run_until_parked();
+
+ ensure_single_file_is_opened(&workspace, "dropped.rs", cx);
+}
+
+#[gpui::test]
+async fn test_auto_open_on_drop_when_disabled(cx: &mut gpui::TestAppContext) {
+ init_test_with_editor(cx);
+ set_auto_open_settings(
+ cx,
+ ProjectPanelAutoOpenSettings {
+ on_drop: Some(false),
+ ..Default::default()
+ },
+ );
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(path!("/root"), json!({})).await;
+
+ let temp_dir = tempfile::tempdir().unwrap();
+ let external_path = temp_dir.path().join("manual.rs");
+ std::fs::write(&external_path, "// dropped").unwrap();
+ fs.insert_tree_from_real_fs(temp_dir.path(), temp_dir.path())
+ .await;
+
+ let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
+ let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*workspace, cx);
+ let panel = workspace.update(cx, ProjectPanel::new).unwrap();
+ cx.run_until_parked();
+
+ let root_entry = find_project_entry(&panel, "root", cx).unwrap();
+ panel.update_in(cx, |panel, window, cx| {
+ panel.drop_external_files(std::slice::from_ref(&external_path), root_entry, window, cx);
+ });
+ cx.executor().run_until_parked();
+
+ ensure_no_open_items_and_panes(&workspace, cx);
+ assert!(
+ find_project_entry(&panel, "root/manual.rs", cx).is_some(),
+ "Dropped entry should exist even when auto-open is disabled"
+ );
+}
+
#[gpui::test]
async fn test_create_duplicate_items(cx: &mut gpui::TestAppContext) {
init_test_with_editor(cx);
@@ -7368,6 +7610,19 @@ fn init_test_with_editor(cx: &mut TestAppContext) {
});
}
+fn set_auto_open_settings(
+ cx: &mut TestAppContext,
+ auto_open_settings: ProjectPanelAutoOpenSettings,
+) {
+ cx.update(|cx| {
+ cx.update_global::<SettingsStore, _>(|store, cx| {
+ store.update_user_settings(cx, |settings| {
+ settings.project_panel.get_or_insert_default().auto_open = Some(auto_open_settings);
+ });
+ })
+ });
+}
+
fn ensure_single_file_is_opened(
window: &WindowHandle<Workspace>,
expected_path: &str,
@@ -510,6 +510,23 @@ impl OnLastWindowClosed {
}
}
+#[skip_serializing_none]
+#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
+pub struct ProjectPanelAutoOpenSettings {
+ /// Whether to automatically open newly created files in the editor.
+ ///
+ /// Default: true
+ pub on_create: Option<bool>,
+ /// Whether to automatically open files after pasting or duplicating them.
+ ///
+ /// Default: true
+ pub on_paste: Option<bool>,
+ /// Whether to automatically open files dropped from external sources.
+ ///
+ /// Default: true
+ pub on_drop: Option<bool>,
+}
+
#[skip_serializing_none]
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)]
pub struct ProjectPanelSettingsContent {
@@ -590,10 +607,8 @@ pub struct ProjectPanelSettingsContent {
///
/// Default: true
pub drag_and_drop: Option<bool>,
- /// Whether to automatically open files when pasting them in the project panel.
- ///
- /// Default: true
- pub open_file_on_paste: Option<bool>,
+ /// Settings for automatically opening files.
+ pub auto_open: Option<ProjectPanelAutoOpenSettings>,
}
#[derive(
@@ -664,13 +664,13 @@ impl VsCodeSettings {
hide_root: None,
indent_guides: None,
indent_size: None,
- open_file_on_paste: None,
scrollbar: None,
show_diagnostics: self
.read_bool("problems.decorations.enabled")
.and_then(|b| if b { Some(ShowDiagnostics::Off) } else { None }),
starts_open: None,
sticky_scroll: None,
+ auto_open: None,
};
if let (Some(false), Some(false)) = (
@@ -3776,23 +3776,47 @@ pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
metadata: None,
files: USER,
}),
+ SettingsPageItem::SectionHeader("Auto Open Files"),
SettingsPageItem::SettingItem(SettingItem {
- title: "Open File on Paste",
- description: "Whether to automatically open files when pasting them in the project panel.",
+ title: "On Create",
+ description: "Whether to automatically open newly created files in the editor.",
field: Box::new(SettingField {
- json_path: Some("project_panel.open_file_on_paste"),
+ json_path: Some("project_panel.auto_open.on_create"),
pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .open_file_on_paste
- .as_ref()
+ settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_create.as_ref()
},
write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .open_file_on_paste = value;
+ settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_create = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Paste",
+ description: "Whether to automatically open files after pasting or duplicating them.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_open.on_paste"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_paste.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_paste = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Drop",
+ description: "Whether to automatically open files dropped from external sources.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_open.on_drop"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_drop.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_drop = value;
},
}),
metadata: None,
@@ -4280,7 +4280,11 @@ Run the {#action theme_selector::Toggle} action in the command palette to see a
"hide_root": false,
"hide_hidden": false,
"starts_open": true,
- "open_file_on_paste": true
+ "auto_open": {
+ "on_create": true,
+ "on_paste": true,
+ "on_drop": true
+ }
}
}
```
@@ -4489,6 +4493,26 @@ Run the {#action theme_selector::Toggle} action in the command palette to see a
}
```
+### Auto Open
+
+- Description: Control whether files are opened automatically after different creation flows in the project panel.
+- Setting: `auto_open`
+- Default:
+
+```json [settings]
+"auto_open": {
+ "on_create": true,
+ "on_paste": true,
+ "on_drop": true
+}
+```
+
+**Options**
+
+- `on_create`: Whether to automatically open newly created files in the editor.
+- `on_paste`: Whether to automatically open files after pasting or duplicating them.
+- `on_drop`: Whether to automatically open files dropped from external sources.
+
## Agent
Visit [the Configuration page](./ai/configuration.md) under the AI section to learn more about all the agent-related settings.