VSCode settings import refactor (#40513)

Conrad Irwin created

A small follow-up to the settings refactor of a few weeks ago to move
all the VSCode settings imports
to one place.

This should make it easier to spot missing imports, and easier to test
the importer.

Release Notes:

- N/A

Change summary

crates/agent_settings/src/agent_settings.rs        |  12 
crates/client/src/client.rs                        |  25 
crates/editor/src/editor_settings.rs               | 208 ----
crates/git_ui/src/git_panel_settings.rs            |  14 
crates/language/src/language_settings.rs           | 127 --
crates/outline_panel/src/outline_panel_settings.rs |  16 
crates/project/src/project.rs                      |   6 
crates/project/src/project_settings.rs             |  59 -
crates/project_panel/src/project_panel_settings.rs |  40 
crates/settings/src/base_keymap_setting.rs         |  11 
crates/settings/src/settings_store.rs              |  71 -
crates/settings/src/vscode_import.rs               | 812 ++++++++++++++-
crates/terminal/src/terminal_settings.rs           |  80 -
crates/theme/src/settings.rs                       |  11 
crates/vim_mode_setting/src/vim_mode_setting.rs    |   6 
crates/workspace/src/item.rs                       |  59 -
crates/workspace/src/workspace_settings.rs         | 110 --
crates/worktree/src/worktree_settings.rs           |  27 
crates/zlog_settings/src/zlog_settings.rs          |   2 
19 files changed, 773 insertions(+), 923 deletions(-)

Detailed changes

crates/agent_settings/src/agent_settings.rs 🔗

@@ -10,7 +10,7 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::{
     DefaultAgentView, DockPosition, LanguageModelParameters, LanguageModelSelection,
-    NotifyWhenAgentWaiting, Settings, SettingsContent,
+    NotifyWhenAgentWaiting, Settings,
 };
 
 pub use crate::agent_profile::*;
@@ -185,14 +185,4 @@ impl Settings for AgentSettings {
             message_editor_min_lines: agent.message_editor_min_lines.unwrap(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        if let Some(b) = vscode
-            .read_value("chat.agent.enabled")
-            .and_then(|b| b.as_bool())
-        {
-            current.agent.get_or_insert_default().enabled = Some(b);
-            current.agent.get_or_insert_default().button = Some(b);
-        }
-    }
 }

crates/client/src/client.rs 🔗

@@ -138,10 +138,6 @@ impl Settings for ProxySettings {
             proxy: content.proxy.clone(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        vscode.string_setting("http.proxy", &mut current.proxy);
-    }
 }
 
 pub fn init_settings(cx: &mut App) {
@@ -525,27 +521,6 @@ impl settings::Settings for TelemetrySettings {
             metrics: content.telemetry.as_ref().unwrap().metrics.unwrap(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        let mut telemetry = settings::TelemetrySettingsContent::default();
-        vscode.enum_setting("telemetry.telemetryLevel", &mut telemetry.metrics, |s| {
-            Some(s == "all")
-        });
-        vscode.enum_setting(
-            "telemetry.telemetryLevel",
-            &mut telemetry.diagnostics,
-            |s| Some(matches!(s, "all" | "error" | "crash")),
-        );
-        // we could translate telemetry.telemetryLevel, but just because users didn't want
-        // to send microsoft telemetry doesn't mean they don't want to send it to zed. their
-        // all/error/crash/off correspond to combinations of our "diagnostics" and "metrics".
-        if let Some(diagnostics) = telemetry.diagnostics {
-            current.telemetry.get_or_insert_default().diagnostics = Some(diagnostics)
-        }
-        if let Some(metrics) = telemetry.metrics {
-            current.telemetry.get_or_insert_default().metrics = Some(metrics)
-        }
-    }
 }
 
 impl Client {

crates/editor/src/editor_settings.rs 🔗

@@ -1,16 +1,14 @@
 use core::num;
-use std::num::NonZeroU32;
 
 use gpui::App;
 use language::CursorShape;
 use project::project_settings::DiagnosticSeverity;
+use settings::Settings;
 pub use settings::{
     CurrentLineHighlight, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer,
     GoToDefinitionFallback, HideMouseMode, MinimapThumb, MinimapThumbBorder, MultiCursorModifier,
     ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder,
-    VsCodeSettings,
 };
-use settings::{Settings, SettingsContent};
 use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
 
 /// Imports from the VSCode settings at
@@ -270,208 +268,4 @@ impl Settings for EditorSettings {
             minimum_contrast_for_highlights: editor.minimum_contrast_for_highlights.unwrap().0,
         }
     }
-
-    fn import_from_vscode(vscode: &VsCodeSettings, current: &mut SettingsContent) {
-        vscode.enum_setting(
-            "editor.cursorBlinking",
-            &mut current.editor.cursor_blink,
-            |s| match s {
-                "blink" | "phase" | "expand" | "smooth" => Some(true),
-                "solid" => Some(false),
-                _ => None,
-            },
-        );
-        vscode.enum_setting(
-            "editor.cursorStyle",
-            &mut current.editor.cursor_shape,
-            |s| match s {
-                "block" => Some(settings::CursorShape::Block),
-                "block-outline" => Some(settings::CursorShape::Hollow),
-                "line" | "line-thin" => Some(settings::CursorShape::Bar),
-                "underline" | "underline-thin" => Some(settings::CursorShape::Underline),
-                _ => None,
-            },
-        );
-
-        vscode.enum_setting(
-            "editor.renderLineHighlight",
-            &mut current.editor.current_line_highlight,
-            |s| match s {
-                "gutter" => Some(CurrentLineHighlight::Gutter),
-                "line" => Some(CurrentLineHighlight::Line),
-                "all" => Some(CurrentLineHighlight::All),
-                _ => None,
-            },
-        );
-
-        vscode.bool_setting(
-            "editor.selectionHighlight",
-            &mut current.editor.selection_highlight,
-        );
-        vscode.bool_setting(
-            "editor.roundedSelection",
-            &mut current.editor.rounded_selection,
-        );
-        vscode.bool_setting(
-            "editor.hover.enabled",
-            &mut current.editor.hover_popover_enabled,
-        );
-        vscode.u64_setting(
-            "editor.hover.delay",
-            &mut current.editor.hover_popover_delay,
-        );
-
-        let mut gutter = settings::GutterContent::default();
-        vscode.enum_setting(
-            "editor.showFoldingControls",
-            &mut gutter.folds,
-            |s| match s {
-                "always" | "mouseover" => Some(true),
-                "never" => Some(false),
-                _ => None,
-            },
-        );
-        vscode.enum_setting(
-            "editor.lineNumbers",
-            &mut gutter.line_numbers,
-            |s| match s {
-                "on" | "relative" => Some(true),
-                "off" => Some(false),
-                _ => None,
-            },
-        );
-        if let Some(old_gutter) = current.editor.gutter.as_mut() {
-            if gutter.folds.is_some() {
-                old_gutter.folds = gutter.folds
-            }
-            if gutter.line_numbers.is_some() {
-                old_gutter.line_numbers = gutter.line_numbers
-            }
-        } else if gutter != settings::GutterContent::default() {
-            current.editor.gutter = Some(gutter)
-        }
-        if let Some(b) = vscode.read_bool("editor.scrollBeyondLastLine") {
-            current.editor.scroll_beyond_last_line = Some(if b {
-                ScrollBeyondLastLine::OnePage
-            } else {
-                ScrollBeyondLastLine::Off
-            })
-        }
-
-        let mut scrollbar_axes = settings::ScrollbarAxesContent::default();
-        vscode.enum_setting(
-            "editor.scrollbar.horizontal",
-            &mut scrollbar_axes.horizontal,
-            |s| match s {
-                "auto" | "visible" => Some(true),
-                "hidden" => Some(false),
-                _ => None,
-            },
-        );
-        vscode.enum_setting(
-            "editor.scrollbar.vertical",
-            &mut scrollbar_axes.horizontal,
-            |s| match s {
-                "auto" | "visible" => Some(true),
-                "hidden" => Some(false),
-                _ => None,
-            },
-        );
-
-        if scrollbar_axes != settings::ScrollbarAxesContent::default() {
-            let scrollbar_settings = current.editor.scrollbar.get_or_insert_default();
-            let axes_settings = scrollbar_settings.axes.get_or_insert_default();
-
-            if let Some(vertical) = scrollbar_axes.vertical {
-                axes_settings.vertical = Some(vertical);
-            }
-            if let Some(horizontal) = scrollbar_axes.horizontal {
-                axes_settings.horizontal = Some(horizontal);
-            }
-        }
-
-        // TODO: check if this does the int->float conversion?
-        vscode.f32_setting(
-            "editor.cursorSurroundingLines",
-            &mut current.editor.vertical_scroll_margin,
-        );
-        vscode.f32_setting(
-            "editor.mouseWheelScrollSensitivity",
-            &mut current.editor.scroll_sensitivity,
-        );
-        vscode.f32_setting(
-            "editor.fastScrollSensitivity",
-            &mut current.editor.fast_scroll_sensitivity,
-        );
-        if Some("relative") == vscode.read_string("editor.lineNumbers") {
-            current.editor.relative_line_numbers = Some(true);
-        }
-
-        vscode.enum_setting(
-            "editor.find.seedSearchStringFromSelection",
-            &mut current.editor.seed_search_query_from_cursor,
-            |s| match s {
-                "always" => Some(SeedQuerySetting::Always),
-                "selection" => Some(SeedQuerySetting::Selection),
-                "never" => Some(SeedQuerySetting::Never),
-                _ => None,
-            },
-        );
-        vscode.bool_setting("search.smartCase", &mut current.editor.use_smartcase_search);
-        vscode.enum_setting(
-            "editor.multiCursorModifier",
-            &mut current.editor.multi_cursor_modifier,
-            |s| match s {
-                "ctrlCmd" => Some(MultiCursorModifier::CmdOrCtrl),
-                "alt" => Some(MultiCursorModifier::Alt),
-                _ => None,
-            },
-        );
-
-        vscode.bool_setting(
-            "editor.parameterHints.enabled",
-            &mut current.editor.auto_signature_help,
-        );
-        vscode.bool_setting(
-            "editor.parameterHints.enabled",
-            &mut current.editor.show_signature_help_after_edits,
-        );
-
-        if let Some(use_ignored) = vscode.read_bool("search.useIgnoreFiles") {
-            let search = current.editor.search.get_or_insert_default();
-            search.include_ignored = Some(use_ignored);
-        }
-
-        let mut minimap = settings::MinimapContent::default();
-        let minimap_enabled = vscode.read_bool("editor.minimap.enabled").unwrap_or(true);
-        let autohide = vscode.read_bool("editor.minimap.autohide");
-        let mut max_width_columns: Option<u32> = None;
-        vscode.u32_setting("editor.minimap.maxColumn", &mut max_width_columns);
-        if minimap_enabled {
-            if let Some(false) = autohide {
-                minimap.show = Some(ShowMinimap::Always);
-            } else {
-                minimap.show = Some(ShowMinimap::Auto);
-            }
-        } else {
-            minimap.show = Some(ShowMinimap::Never);
-        }
-        if let Some(max_width_columns) = max_width_columns {
-            minimap.max_width_columns = NonZeroU32::new(max_width_columns);
-        }
-
-        vscode.enum_setting(
-            "editor.minimap.showSlider",
-            &mut minimap.thumb,
-            |s| match s {
-                "always" => Some(MinimapThumb::Always),
-                "mouseover" => Some(MinimapThumb::Hover),
-                _ => None,
-            },
-        );
-
-        if minimap != settings::MinimapContent::default() {
-            current.editor.minimap = Some(minimap)
-        }
-    }
 }

crates/git_ui/src/git_panel_settings.rs 🔗

@@ -2,7 +2,7 @@ use editor::EditorSettings;
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsContent, StatusStyle};
+use settings::{Settings, StatusStyle};
 use ui::{
     px,
     scrollbars::{ScrollbarVisibility, ShowScrollbar},
@@ -58,16 +58,4 @@ impl Settings for GitPanelSettings {
             collapse_untracked_diff: git_panel.collapse_untracked_diff.unwrap(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        if let Some(git_enabled) = vscode.read_bool("git.enabled") {
-            current.git_panel.get_or_insert_default().button = Some(git_enabled);
-        }
-        if let Some(default_branch) = vscode.read_string("git.defaultBranchName") {
-            current
-                .git_panel
-                .get_or_insert_default()
-                .fallback_branch_name = Some(default_branch.to_string());
-        }
-    }
 }

crates/language/src/language_settings.rs 🔗

@@ -15,7 +15,7 @@ pub use settings::{
     Formatter, FormatterList, InlayHintKind, LanguageSettingsContent, LspInsertMode,
     RewrapBehavior, ShowWhitespaceSetting, SoftWrap, WordsCompletionMode,
 };
-use settings::{ExtendingVec, Settings, SettingsContent, SettingsLocation, SettingsStore};
+use settings::{Settings, SettingsLocation, SettingsStore};
 use shellexpand;
 use std::{borrow::Cow, num::NonZeroU32, path::Path, sync::Arc};
 
@@ -679,131 +679,6 @@ impl settings::Settings for AllLanguageSettings {
             file_types,
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        let d = &mut current.project.all_languages.defaults;
-        if let Some(size) = vscode
-            .read_value("editor.tabSize")
-            .and_then(|v| v.as_u64())
-            .and_then(|n| NonZeroU32::new(n as u32))
-        {
-            d.tab_size = Some(size);
-        }
-        if let Some(v) = vscode.read_bool("editor.insertSpaces") {
-            d.hard_tabs = Some(!v);
-        }
-
-        vscode.enum_setting("editor.wordWrap", &mut d.soft_wrap, |s| match s {
-            "on" => Some(SoftWrap::EditorWidth),
-            "wordWrapColumn" => Some(SoftWrap::PreferLine),
-            "bounded" => Some(SoftWrap::Bounded),
-            "off" => Some(SoftWrap::None),
-            _ => None,
-        });
-        vscode.u32_setting("editor.wordWrapColumn", &mut d.preferred_line_length);
-
-        if let Some(arr) = vscode
-            .read_value("editor.rulers")
-            .and_then(|v| v.as_array())
-            .map(|v| v.iter().map(|n| n.as_u64().map(|n| n as usize)).collect())
-        {
-            d.wrap_guides = arr;
-        }
-        if let Some(b) = vscode.read_bool("editor.guides.indentation") {
-            d.indent_guides.get_or_insert_default().enabled = Some(b);
-        }
-
-        if let Some(b) = vscode.read_bool("editor.guides.formatOnSave") {
-            d.format_on_save = Some(if b {
-                FormatOnSave::On
-            } else {
-                FormatOnSave::Off
-            });
-        }
-        vscode.bool_setting(
-            "editor.trimAutoWhitespace",
-            &mut d.remove_trailing_whitespace_on_save,
-        );
-        vscode.bool_setting(
-            "files.insertFinalNewline",
-            &mut d.ensure_final_newline_on_save,
-        );
-        vscode.bool_setting("editor.inlineSuggest.enabled", &mut d.show_edit_predictions);
-        vscode.enum_setting("editor.renderWhitespace", &mut d.show_whitespaces, |s| {
-            Some(match s {
-                "boundary" => ShowWhitespaceSetting::Boundary,
-                "trailing" => ShowWhitespaceSetting::Trailing,
-                "selection" => ShowWhitespaceSetting::Selection,
-                "all" => ShowWhitespaceSetting::All,
-                _ => ShowWhitespaceSetting::None,
-            })
-        });
-        vscode.enum_setting(
-            "editor.autoSurround",
-            &mut d.use_auto_surround,
-            |s| match s {
-                "languageDefined" | "quotes" | "brackets" => Some(true),
-                "never" => Some(false),
-                _ => None,
-            },
-        );
-        vscode.bool_setting("editor.formatOnType", &mut d.use_on_type_format);
-        vscode.bool_setting("editor.linkedEditing", &mut d.linked_edits);
-        vscode.bool_setting("editor.formatOnPaste", &mut d.auto_indent_on_paste);
-        vscode.bool_setting(
-            "editor.suggestOnTriggerCharacters",
-            &mut d.show_completions_on_input,
-        );
-        if let Some(b) = vscode.read_bool("editor.suggest.showWords") {
-            let mode = if b {
-                WordsCompletionMode::Enabled
-            } else {
-                WordsCompletionMode::Disabled
-            };
-            d.completions.get_or_insert_default().words = Some(mode);
-        }
-        // TODO: pull ^ out into helper and reuse for per-language settings
-
-        // vscodes file association map is inverted from ours, so we flip the mapping before merging
-        let mut associations: HashMap<Arc<str>, ExtendingVec<String>> = HashMap::default();
-        if let Some(map) = vscode
-            .read_value("files.associations")
-            .and_then(|v| v.as_object())
-        {
-            for (k, v) in map {
-                let Some(v) = v.as_str() else { continue };
-                associations.entry(v.into()).or_default().0.push(k.clone());
-            }
-        }
-
-        // TODO: do we want to merge imported globs per filetype? for now we'll just replace
-        current
-            .project
-            .all_languages
-            .file_types
-            .get_or_insert_default()
-            .extend(associations);
-
-        // cursor global ignore list applies to cursor-tab, so transfer it to edit_predictions.disabled_globs
-        if let Some(disabled_globs) = vscode
-            .read_value("cursor.general.globalCursorIgnoreList")
-            .and_then(|v| v.as_array())
-        {
-            current
-                .project
-                .all_languages
-                .edit_predictions
-                .get_or_insert_default()
-                .disabled_globs
-                .get_or_insert_default()
-                .extend(
-                    disabled_globs
-                        .iter()
-                        .filter_map(|glob| glob.as_str())
-                        .map(|s| s.to_string()),
-                );
-        }
-    }
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Eq)]

crates/outline_panel/src/outline_panel_settings.rs 🔗

@@ -62,20 +62,4 @@ impl Settings for OutlinePanelSettings {
             expand_outlines_with_depth: panel.expand_outlines_with_depth.unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if let Some(b) = vscode.read_bool("outline.icons") {
-            let outline_panel = current.outline_panel.get_or_insert_default();
-            outline_panel.file_icons = Some(b);
-            outline_panel.folder_icons = Some(b);
-        }
-
-        if let Some(b) = vscode.read_bool("git.decorations.enabled") {
-            let outline_panel = current.outline_panel.get_or_insert_default();
-            outline_panel.git_status = Some(b);
-        }
-    }
 }

crates/project/src/project.rs 🔗

@@ -985,12 +985,6 @@ impl settings::Settings for DisableAiSettings {
             disable_ai: content.disable_ai.unwrap().0,
         }
     }
-
-    fn import_from_vscode(
-        _vscode: &settings::VsCodeSettings,
-        _current: &mut settings::SettingsContent,
-    ) {
-    }
 }
 
 impl Project {

crates/project/src/project_settings.rs 🔗

@@ -522,65 +522,6 @@ impl Settings for ProjectSettings {
             },
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        // this just sets the binary name instead of a full path so it relies on path lookup
-        // resolving to the one you want
-        let npm_path = vscode.read_enum("npm.packageManager", |s| match s {
-            v @ ("npm" | "yarn" | "bun" | "pnpm") => Some(v.to_owned()),
-            _ => None,
-        });
-        if npm_path.is_some() {
-            current.node.get_or_insert_default().npm_path = npm_path;
-        }
-
-        if let Some(b) = vscode.read_bool("git.blame.editorDecoration.enabled") {
-            current
-                .git
-                .get_or_insert_default()
-                .inline_blame
-                .get_or_insert_default()
-                .enabled = Some(b);
-        }
-
-        #[derive(Deserialize)]
-        struct VsCodeContextServerCommand {
-            command: PathBuf,
-            args: Option<Vec<String>>,
-            env: Option<HashMap<String, String>>,
-            // note: we don't support envFile and type
-        }
-        if let Some(mcp) = vscode.read_value("mcp").and_then(|v| v.as_object()) {
-            current
-                .project
-                .context_servers
-                .extend(mcp.iter().filter_map(|(k, v)| {
-                    Some((
-                        k.clone().into(),
-                        settings::ContextServerSettingsContent::Custom {
-                            enabled: true,
-                            command: serde_json::from_value::<VsCodeContextServerCommand>(
-                                v.clone(),
-                            )
-                            .ok()
-                            .map(|cmd| {
-                                settings::ContextServerCommand {
-                                    path: cmd.command,
-                                    args: cmd.args.unwrap_or_default(),
-                                    env: cmd.env,
-                                    timeout: None,
-                                }
-                            })?,
-                        },
-                    ))
-                }));
-        }
-
-        // TODO: translate lsp settings for rust-analyzer and other popular ones to old.lsp
-    }
 }
 
 pub enum SettingsObserverMode {

crates/project_panel/src/project_panel_settings.rs 🔗

@@ -2,10 +2,7 @@ use editor::EditorSettings;
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{
-    DockSide, ProjectPanelEntrySpacing, Settings, SettingsContent, ShowDiagnostics,
-    ShowIndentGuides,
-};
+use settings::{DockSide, ProjectPanelEntrySpacing, Settings, ShowDiagnostics, ShowIndentGuides};
 use ui::{
     px,
     scrollbars::{ScrollbarVisibility, ShowScrollbar},
@@ -86,39 +83,4 @@ impl Settings for ProjectPanelSettings {
             open_file_on_paste: project_panel.open_file_on_paste.unwrap(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        if let Some(hide_gitignore) = vscode.read_bool("explorer.excludeGitIgnore") {
-            current.project_panel.get_or_insert_default().hide_gitignore = Some(hide_gitignore);
-        }
-        if let Some(auto_reveal) = vscode.read_bool("explorer.autoReveal") {
-            current
-                .project_panel
-                .get_or_insert_default()
-                .auto_reveal_entries = Some(auto_reveal);
-        }
-        if let Some(compact_folders) = vscode.read_bool("explorer.compactFolders") {
-            current.project_panel.get_or_insert_default().auto_fold_dirs = Some(compact_folders);
-        }
-
-        if Some(false) == vscode.read_bool("git.decorations.enabled") {
-            current.project_panel.get_or_insert_default().git_status = Some(false);
-        }
-        if Some(false) == vscode.read_bool("problems.decorations.enabled") {
-            current
-                .project_panel
-                .get_or_insert_default()
-                .show_diagnostics = Some(ShowDiagnostics::Off);
-        }
-        if let (Some(false), Some(false)) = (
-            vscode.read_bool("explorer.decorations.badges"),
-            vscode.read_bool("explorer.decorations.colors"),
-        ) {
-            current.project_panel.get_or_insert_default().git_status = Some(false);
-            current
-                .project_panel
-                .get_or_insert_default()
-                .show_diagnostics = Some(ShowDiagnostics::Off);
-        }
-    }
 }

crates/settings/src/base_keymap_setting.rs 🔗

@@ -1,12 +1,9 @@
 use std::fmt::{Display, Formatter};
 
-use crate::{
-    self as settings,
-    settings_content::{BaseKeymapContent, SettingsContent},
-};
+use crate::{self as settings, settings_content::BaseKeymapContent};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{Settings, VsCodeSettings};
+use settings::Settings;
 
 /// Base key bindings scheme. Base keymaps can be overridden with user keymaps.
 ///
@@ -133,8 +130,4 @@ impl Settings for BaseKeymap {
     fn from_settings(s: &crate::settings_content::SettingsContent) -> Self {
         s.base_keymap.unwrap().into()
     }
-
-    fn import_from_vscode(_vscode: &VsCodeSettings, current: &mut SettingsContent) {
-        current.base_keymap = Some(BaseKeymapContent::VSCode);
-    }
 }

crates/settings/src/settings_store.rs 🔗

@@ -70,10 +70,6 @@ pub trait Settings: 'static + Send + Sync + Sized {
     /// and you should add a default to default.json for documentation.
     fn from_settings(content: &SettingsContent) -> Self;
 
-    /// Use [the helpers in the vscode_import module](crate::vscode_import) to apply known
-    /// equivalent settings from a vscode config to our config
-    fn import_from_vscode(_vscode: &VsCodeSettings, _current: &mut SettingsContent) {}
-
     #[track_caller]
     fn register(cx: &mut App)
     where
@@ -208,11 +204,6 @@ trait AnySettingValue: 'static + Send + Sync {
     fn all_local_values(&self) -> Vec<(WorktreeId, Arc<RelPath>, &dyn Any)>;
     fn set_global_value(&mut self, value: Box<dyn Any>);
     fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<RelPath>, value: Box<dyn Any>);
-    fn import_from_vscode(
-        &self,
-        vscode_settings: &VsCodeSettings,
-        settings_content: &mut SettingsContent,
-    );
 }
 
 impl SettingsStore {
@@ -614,10 +605,8 @@ impl SettingsStore {
     }
 
     pub fn get_vscode_edits(&self, old_text: String, vscode: &VsCodeSettings) -> String {
-        self.new_text_for_update(old_text, |settings_content| {
-            for v in self.setting_values.values() {
-                v.import_from_vscode(vscode, settings_content)
-            }
+        self.new_text_for_update(old_text, |content| {
+            content.merge_from(&vscode.settings_content())
         })
     }
 
@@ -1129,14 +1118,6 @@ impl<T: Settings> AnySettingValue for SettingValue<T> {
             Err(ix) => self.local_values.insert(ix, (root_id, path, value)),
         }
     }
-
-    fn import_from_vscode(
-        &self,
-        vscode_settings: &VsCodeSettings,
-        settings_content: &mut SettingsContent,
-    ) {
-        T::import_from_vscode(vscode_settings, settings_content);
-    }
 }
 
 #[cfg(test)]
@@ -1179,19 +1160,6 @@ mod tests {
                 git_status: content.git_status.unwrap(),
             }
         }
-
-        fn import_from_vscode(vscode: &VsCodeSettings, content: &mut SettingsContent) {
-            let mut show = None;
-
-            vscode.bool_setting("workbench.editor.decorations.colors", &mut show);
-            if let Some(show) = show {
-                content
-                    .tabs
-                    .get_or_insert_default()
-                    .git_status
-                    .replace(show);
-            }
-        }
     }
 
     #[derive(Debug, PartialEq)]
@@ -1208,18 +1176,6 @@ mod tests {
                 preferred_line_length: content.preferred_line_length.unwrap(),
             }
         }
-
-        fn import_from_vscode(vscode: &VsCodeSettings, content: &mut SettingsContent) {
-            let content = &mut content.project.all_languages.defaults;
-
-            if let Some(size) = vscode
-                .read_value("editor.tabSize")
-                .and_then(|v| v.as_u64())
-                .and_then(|n| NonZeroU32::new(n as u32))
-            {
-                content.tab_size = Some(size);
-            }
-        }
     }
 
     #[derive(Debug, PartialEq)]
@@ -1236,16 +1192,6 @@ mod tests {
                 buffer_font_fallbacks: content.buffer_font_fallbacks.unwrap(),
             }
         }
-
-        fn import_from_vscode(vscode: &VsCodeSettings, content: &mut SettingsContent) {
-            let content = &mut content.theme;
-
-            vscode.font_family_setting(
-                "editor.fontFamily",
-                &mut content.buffer_font_family,
-                &mut content.buffer_font_fallbacks,
-            );
-        }
     }
 
     #[gpui::test]
@@ -1581,6 +1527,7 @@ mod tests {
             .unindent(),
             r#" { "editor.tabSize": 37 } "#.to_owned(),
             r#"{
+              "base_keymap": "VSCode",
               "tab_size": 37
             }
             "#
@@ -1598,6 +1545,7 @@ mod tests {
             .unindent(),
             r#"{ "editor.tabSize": 42 }"#.to_owned(),
             r#"{
+                "base_keymap": "VSCode",
                 "tab_size": 42,
                 "preferred_line_length": 99,
             }
@@ -1617,6 +1565,7 @@ mod tests {
             .unindent(),
             r#"{}"#.to_owned(),
             r#"{
+                "base_keymap": "VSCode",
                 "preferred_line_length": 99,
                 "tab_size": 42
             }
@@ -1632,8 +1581,15 @@ mod tests {
             }
             "#
             .unindent(),
-            r#"{ "workbench.editor.decorations.colors": true }"#.to_owned(),
+            r#"{ "git.decorations.enabled": true }"#.to_owned(),
             r#"{
+              "project_panel": {
+                "git_status": true
+              },
+              "outline_panel": {
+                "git_status": true
+              },
+              "base_keymap": "VSCode",
               "tabs": {
                 "git_status": true
               }
@@ -1652,6 +1608,7 @@ mod tests {
             .unindent(),
             r#"{ "editor.fontFamily": "Cascadia Code, 'Consolas', Courier New" }"#.to_owned(),
             r#"{
+              "base_keymap": "VSCode",
               "buffer_font_fallbacks": [
                 "Consolas",
                 "Courier New"

crates/settings/src/vscode_import.rs 🔗

@@ -1,10 +1,15 @@
+use crate::*;
 use anyhow::{Context as _, Result, anyhow};
+use collections::HashMap;
 use fs::Fs;
 use paths::{cursor_settings_file_paths, vscode_settings_file_paths};
+use serde::Deserialize;
 use serde_json::{Map, Value};
-use std::{path::Path, sync::Arc};
-
-use crate::FontFamilyName;
+use std::{
+    num::{NonZeroU32, NonZeroUsize},
+    path::{Path, PathBuf},
+    sync::Arc,
+};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum VsCodeSettingsSource {
@@ -79,83 +84,53 @@ impl VsCodeSettings {
         })
     }
 
-    pub fn read_value(&self, setting: &str) -> Option<&Value> {
+    fn read_value(&self, setting: &str) -> Option<&Value> {
         self.content.get(setting)
     }
 
-    pub fn read_string(&self, setting: &str) -> Option<&str> {
+    fn read_str(&self, setting: &str) -> Option<&str> {
         self.read_value(setting).and_then(|v| v.as_str())
     }
 
-    pub fn read_bool(&self, setting: &str) -> Option<bool> {
-        self.read_value(setting).and_then(|v| v.as_bool())
-    }
-
-    pub fn string_setting(&self, key: &str, setting: &mut Option<String>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_str) {
-            *setting = Some(s.to_owned())
-        }
-    }
-
-    pub fn bool_setting(&self, key: &str, setting: &mut Option<bool>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_bool) {
-            *setting = Some(s)
-        }
+    fn read_string(&self, setting: &str) -> Option<String> {
+        self.read_value(setting)
+            .and_then(|v| v.as_str())
+            .map(|s| s.to_owned())
     }
 
-    pub fn u32_setting(&self, key: &str, setting: &mut Option<u32>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
-            *setting = Some(s as u32)
-        }
+    fn read_bool(&self, setting: &str) -> Option<bool> {
+        self.read_value(setting).and_then(|v| v.as_bool())
     }
 
-    pub fn u64_setting(&self, key: &str, setting: &mut Option<u64>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
-            *setting = Some(s)
-        }
+    fn read_f32(&self, setting: &str) -> Option<f32> {
+        self.read_value(setting)
+            .and_then(|v| v.as_f64())
+            .map(|v| v as f32)
     }
 
-    pub fn usize_setting(&self, key: &str, setting: &mut Option<usize>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_u64) {
-            *setting = Some(s.try_into().unwrap())
-        }
+    fn read_u64(&self, setting: &str) -> Option<u64> {
+        self.read_value(setting).and_then(|v| v.as_u64())
     }
 
-    pub fn f32_setting(&self, key: &str, setting: &mut Option<f32>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_f64) {
-            *setting = Some(s as f32)
-        }
+    fn read_usize(&self, setting: &str) -> Option<usize> {
+        self.read_value(setting)
+            .and_then(|v| v.as_u64())
+            .and_then(|v| v.try_into().ok())
     }
 
-    pub fn from_f32_setting<T: From<f32>>(&self, key: &str, setting: &mut Option<T>) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_f64) {
-            *setting = Some(T::from(s as f32))
-        }
+    fn read_u32(&self, setting: &str) -> Option<u32> {
+        self.read_value(setting)
+            .and_then(|v| v.as_u64())
+            .and_then(|v| v.try_into().ok())
     }
 
-    pub fn enum_setting<T>(
-        &self,
-        key: &str,
-        setting: &mut Option<T>,
-        f: impl FnOnce(&str) -> Option<T>,
-    ) {
-        if let Some(s) = self.content.get(key).and_then(Value::as_str).and_then(f) {
-            *setting = Some(s)
-        }
-    }
-
-    pub fn read_enum<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
+    fn read_enum<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
         self.content.get(key).and_then(Value::as_str).and_then(f)
     }
 
-    pub fn font_family_setting(
-        &self,
-        key: &str,
-        font_family: &mut Option<FontFamilyName>,
-        font_fallbacks: &mut Option<Vec<FontFamilyName>>,
-    ) {
+    fn read_fonts(&self, key: &str) -> (Option<FontFamilyName>, Option<Vec<FontFamilyName>>) {
         let Some(css_name) = self.content.get(key).and_then(Value::as_str) else {
-            return;
+            return (None, None);
         };
 
         let mut name_buffer = String::new();
@@ -188,12 +163,723 @@ impl VsCodeSettings {
         }
 
         add_font(&mut name_buffer);
+        if fonts.is_empty() {
+            return (None, None);
+        }
+        (Some(fonts.remove(0)), skip_default(fonts))
+    }
+
+    pub fn settings_content(&self) -> SettingsContent {
+        SettingsContent {
+            agent: self.agent_settings_content(),
+            agent_servers: None,
+            audio: None,
+            auto_update: None,
+            base_keymap: Some(BaseKeymapContent::VSCode),
+            calls: None,
+            collaboration_panel: None,
+            debugger: None,
+            diagnostics: None,
+            disable_ai: None,
+            editor: self.editor_settings_content(),
+            extension: ExtensionSettingsContent::default(),
+            file_finder: None,
+            git: self.git_settings_content(),
+            git_panel: self.git_panel_settings_content(),
+            global_lsp_settings: None,
+            helix_mode: None,
+            image_viewer: None,
+            journal: None,
+            language_models: None,
+            line_indicator_format: None,
+            log: None,
+            message_editor: None,
+            node: self.node_binary_settings(),
+            notification_panel: None,
+            outline_panel: self.outline_panel_settings_content(),
+            preview_tabs: self.preview_tabs_settings_content(),
+            project: self.project_settings_content(),
+            project_panel: self.project_panel_settings_content(),
+            proxy: self.read_string("http.proxy"),
+            remote: RemoteSettingsContent::default(),
+            repl: None,
+            server_url: None,
+            session: None,
+            status_bar: self.status_bar_settings_content(),
+            tab_bar: self.tab_bar_settings_content(),
+            tabs: self.item_settings_content(),
+            telemetry: self.telemetry_settings_content(),
+            terminal: self.terminal_settings_content(),
+            theme: Box::new(self.theme_settings_content()),
+            title_bar: None,
+            vim: None,
+            vim_mode: None,
+            workspace: self.workspace_settings_content(),
+        }
+    }
+
+    fn agent_settings_content(&self) -> Option<AgentSettingsContent> {
+        let enabled = self.read_bool("chat.agent.enabled");
+        skip_default(AgentSettingsContent {
+            enabled: enabled,
+            button: enabled,
+            ..Default::default()
+        })
+    }
+
+    fn editor_settings_content(&self) -> EditorSettingsContent {
+        EditorSettingsContent {
+            auto_signature_help: self.read_bool("editor.parameterHints.enabled"),
+            autoscroll_on_clicks: None,
+            cursor_blink: self.read_enum("editor.cursorBlinking", |s| match s {
+                "blink" | "phase" | "expand" | "smooth" => Some(true),
+                "solid" => Some(false),
+                _ => None,
+            }),
+            cursor_shape: self.read_enum("editor.cursorStyle", |s| match s {
+                "block" => Some(CursorShape::Block),
+                "block-outline" => Some(CursorShape::Hollow),
+                "line" | "line-thin" => Some(CursorShape::Bar),
+                "underline" | "underline-thin" => Some(CursorShape::Underline),
+                _ => None,
+            }),
+            current_line_highlight: self.read_enum("editor.renderLineHighlight", |s| match s {
+                "gutter" => Some(CurrentLineHighlight::Gutter),
+                "line" => Some(CurrentLineHighlight::Line),
+                "all" => Some(CurrentLineHighlight::All),
+                _ => None,
+            }),
+            diagnostics_max_severity: None,
+            double_click_in_multibuffer: None,
+            drag_and_drop_selection: None,
+            excerpt_context_lines: None,
+            expand_excerpt_lines: None,
+            fast_scroll_sensitivity: self.read_f32("editor.fastScrollSensitivity"),
+            go_to_definition_fallback: None,
+            gutter: self.gutter_content(),
+            hide_mouse: None,
+            horizontal_scroll_margin: None,
+            hover_popover_delay: self.read_u64("editor.hover.delay"),
+            hover_popover_enabled: self.read_bool("editor.hover.enabled"),
+            inline_code_actions: None,
+            jupyter: None,
+            lsp_document_colors: None,
+            lsp_highlight_debounce: None,
+            middle_click_paste: None,
+            minimap: self.minimap_content(),
+            minimum_contrast_for_highlights: None,
+            multi_cursor_modifier: self.read_enum("editor.multiCursorModifier", |s| match s {
+                "ctrlCmd" => Some(MultiCursorModifier::CmdOrCtrl),
+                "alt" => Some(MultiCursorModifier::Alt),
+                _ => None,
+            }),
+            redact_private_values: None,
+            relative_line_numbers: self.read_enum("editor.lineNumbers", |s| match s {
+                "relative" => Some(true),
+                _ => None,
+            }),
+            rounded_selection: self.read_bool("editor.roundedSelection"),
+            scroll_beyond_last_line: None,
+            scroll_sensitivity: self.read_f32("editor.mouseWheelScrollSensitivity"),
+            scrollbar: self.scrollbar_content(),
+            search: self.search_content(),
+            search_wrap: None,
+            seed_search_query_from_cursor: self.read_enum(
+                "editor.find.seedSearchStringFromSelection",
+                |s| match s {
+                    "always" => Some(SeedQuerySetting::Always),
+                    "selection" => Some(SeedQuerySetting::Selection),
+                    "never" => Some(SeedQuerySetting::Never),
+                    _ => None,
+                },
+            ),
+            selection_highlight: self.read_bool("editor.selectionHighlight"),
+            show_signature_help_after_edits: self.read_bool("editor.parameterHints.enabled"),
+            snippet_sort_order: None,
+            toolbar: None,
+            use_smartcase_search: self.read_bool("search.smartCase"),
+            vertical_scroll_margin: self.read_f32("editor.cursorSurroundingLines"),
+        }
+    }
+
+    fn gutter_content(&self) -> Option<GutterContent> {
+        skip_default(GutterContent {
+            line_numbers: self.read_enum("editor.lineNumbers", |s| match s {
+                "on" | "relative" => Some(true),
+                "off" => Some(false),
+                _ => None,
+            }),
+            min_line_number_digits: None,
+            runnables: None,
+            breakpoints: None,
+            folds: self.read_enum("editor.showFoldingControls", |s| match s {
+                "always" | "mouseover" => Some(true),
+                "never" => Some(false),
+                _ => None,
+            }),
+        })
+    }
+
+    fn scrollbar_content(&self) -> Option<ScrollbarContent> {
+        let scrollbar_axes = skip_default(ScrollbarAxesContent {
+            horizontal: self.read_enum("editor.scrollbar.horizontal", |s| match s {
+                "auto" | "visible" => Some(true),
+                "hidden" => Some(false),
+                _ => None,
+            }),
+            vertical: self.read_enum("editor.scrollbar.vertical", |s| match s {
+                "auto" | "visible" => Some(true),
+                "hidden" => Some(false),
+                _ => None,
+            }),
+        })?;
+
+        Some(ScrollbarContent {
+            axes: Some(scrollbar_axes),
+            ..Default::default()
+        })
+    }
+
+    fn search_content(&self) -> Option<SearchSettingsContent> {
+        skip_default(SearchSettingsContent {
+            include_ignored: self.read_bool("search.useIgnoreFiles"),
+            ..Default::default()
+        })
+    }
+
+    fn minimap_content(&self) -> Option<MinimapContent> {
+        let minimap_enabled = self.read_bool("editor.minimap.enabled");
+        let autohide = self.read_bool("editor.minimap.autohide");
+        let show = match (minimap_enabled, autohide) {
+            (Some(true), Some(false)) => Some(ShowMinimap::Always),
+            (Some(true), _) => Some(ShowMinimap::Auto),
+            (Some(false), _) => Some(ShowMinimap::Never),
+            _ => None,
+        };
+
+        skip_default(MinimapContent {
+            show,
+            thumb: self.read_enum("editor.minimap.showSlider", |s| match s {
+                "always" => Some(MinimapThumb::Always),
+                "mouseover" => Some(MinimapThumb::Hover),
+                _ => None,
+            }),
+            max_width_columns: self
+                .read_u32("editor.minimap.maxColumn")
+                .and_then(|v| NonZeroU32::new(v)),
+            ..Default::default()
+        })
+    }
 
-        let mut iter = fonts.into_iter();
-        *font_family = iter.next();
-        let fallbacks: Vec<_> = iter.collect();
-        if !fallbacks.is_empty() {
-            *font_fallbacks = Some(fallbacks);
+    fn git_panel_settings_content(&self) -> Option<GitPanelSettingsContent> {
+        skip_default(GitPanelSettingsContent {
+            button: self.read_bool("git.enabled"),
+            fallback_branch_name: self.read_string("git.defaultBranchName"),
+            ..Default::default()
+        })
+    }
+
+    fn project_settings_content(&self) -> ProjectSettingsContent {
+        ProjectSettingsContent {
+            all_languages: AllLanguageSettingsContent {
+                features: None,
+                edit_predictions: self.edit_predictions_settings_content(),
+                defaults: self.default_language_settings_content(),
+                languages: Default::default(),
+                file_types: self.file_types(),
+            },
+            worktree: self.worktree_settings_content(),
+            lsp: Default::default(),
+            terminal: None,
+            dap: Default::default(),
+            context_servers: self.context_servers(),
+            load_direnv: None,
+            slash_commands: None,
+            git_hosting_providers: None,
+        }
+    }
+
+    fn default_language_settings_content(&self) -> LanguageSettingsContent {
+        LanguageSettingsContent {
+            allow_rewrap: None,
+            always_treat_brackets_as_autoclosed: None,
+            auto_indent: None,
+            auto_indent_on_paste: self.read_bool("editor.formatOnPaste"),
+            code_actions_on_format: None,
+            completions: skip_default(CompletionSettingsContent {
+                words: self.read_bool("editor.suggest.showWords").map(|b| {
+                    if b {
+                        WordsCompletionMode::Enabled
+                    } else {
+                        WordsCompletionMode::Disabled
+                    }
+                }),
+                ..Default::default()
+            }),
+            debuggers: None,
+            edit_predictions_disabled_in: None,
+            enable_language_server: None,
+            ensure_final_newline_on_save: self.read_bool("files.insertFinalNewline"),
+            extend_comment_on_newline: None,
+            format_on_save: self.read_bool("editor.guides.formatOnSave").map(|b| {
+                if b {
+                    FormatOnSave::On
+                } else {
+                    FormatOnSave::Off
+                }
+            }),
+            formatter: None,
+            hard_tabs: self.read_bool("editor.insertSpaces").map(|v| !v),
+            indent_guides: skip_default(IndentGuideSettingsContent {
+                enabled: self.read_bool("editor.guides.indentation"),
+                ..Default::default()
+            }),
+            inlay_hints: None,
+            jsx_tag_auto_close: None,
+            language_servers: None,
+            linked_edits: self.read_bool("editor.linkedEditing"),
+            preferred_line_length: self.read_u32("editor.wordWrapColumn"),
+            prettier: None,
+            remove_trailing_whitespace_on_save: self.read_bool("editor.trimAutoWhitespace"),
+            show_completion_documentation: None,
+            show_completions_on_input: self.read_bool("editor.suggestOnTriggerCharacters"),
+            show_edit_predictions: self.read_bool("editor.inlineSuggest.enabled"),
+            show_whitespaces: self.read_enum("editor.renderWhitespace", |s| {
+                Some(match s {
+                    "boundary" => ShowWhitespaceSetting::Boundary,
+                    "trailing" => ShowWhitespaceSetting::Trailing,
+                    "selection" => ShowWhitespaceSetting::Selection,
+                    "all" => ShowWhitespaceSetting::All,
+                    _ => ShowWhitespaceSetting::None,
+                })
+            }),
+            show_wrap_guides: None,
+            soft_wrap: self.read_enum("editor.wordWrap", |s| match s {
+                "on" => Some(SoftWrap::EditorWidth),
+                "wordWrapColumn" => Some(SoftWrap::PreferLine),
+                "bounded" => Some(SoftWrap::Bounded),
+                "off" => Some(SoftWrap::None),
+                _ => None,
+            }),
+            tab_size: self
+                .read_u32("editor.tabSize")
+                .and_then(|n| NonZeroU32::new(n)),
+            tasks: None,
+            use_auto_surround: self.read_enum("editor.autoSurround", |s| match s {
+                "languageDefined" | "quotes" | "brackets" => Some(true),
+                "never" => Some(false),
+                _ => None,
+            }),
+            use_autoclose: None,
+            use_on_type_format: self.read_bool("editor.formatOnType"),
+            whitespace_map: None,
+            wrap_guides: self
+                .read_value("editor.rulers")
+                .and_then(|v| v.as_array())
+                .map(|v| {
+                    v.iter()
+                        .flat_map(|n| n.as_u64().map(|n| n as usize))
+                        .collect()
+                }),
         }
     }
+
+    fn file_types(&self) -> Option<HashMap<Arc<str>, ExtendingVec<String>>> {
+        // vscodes file association map is inverted from ours, so we flip the mapping before merging
+        let mut associations: HashMap<Arc<str>, ExtendingVec<String>> = HashMap::default();
+        let map = self.read_value("files.associations")?.as_object()?;
+        for (k, v) in map {
+            let Some(v) = v.as_str() else { continue };
+            associations.entry(v.into()).or_default().0.push(k.clone());
+        }
+        skip_default(associations)
+    }
+
+    fn edit_predictions_settings_content(&self) -> Option<EditPredictionSettingsContent> {
+        let disabled_globs = self
+            .read_value("cursor.general.globalCursorIgnoreList")?
+            .as_array()?;
+
+        skip_default(EditPredictionSettingsContent {
+            disabled_globs: skip_default(
+                disabled_globs
+                    .iter()
+                    .filter_map(|glob| glob.as_str())
+                    .map(|s| s.to_string())
+                    .collect(),
+            ),
+            ..Default::default()
+        })
+    }
+
+    fn outline_panel_settings_content(&self) -> Option<OutlinePanelSettingsContent> {
+        skip_default(OutlinePanelSettingsContent {
+            file_icons: self.read_bool("outline.icons"),
+            folder_icons: self.read_bool("outline.icons"),
+            git_status: self.read_bool("git.decorations.enabled"),
+            ..Default::default()
+        })
+    }
+
+    fn node_binary_settings(&self) -> Option<NodeBinarySettings> {
+        // this just sets the binary name instead of a full path so it relies on path lookup
+        // resolving to the one you want
+        skip_default(NodeBinarySettings {
+            npm_path: self.read_enum("npm.packageManager", |s| match s {
+                v @ ("npm" | "yarn" | "bun" | "pnpm") => Some(v.to_owned()),
+                _ => None,
+            }),
+            ..Default::default()
+        })
+    }
+
+    fn git_settings_content(&self) -> Option<GitSettings> {
+        let inline_blame = self.read_bool("git.blame.editorDecoration.enabled")?;
+        skip_default(GitSettings {
+            inline_blame: Some(InlineBlameSettings {
+                enabled: Some(inline_blame),
+                ..Default::default()
+            }),
+            ..Default::default()
+        })
+    }
+
+    fn context_servers(&self) -> HashMap<Arc<str>, ContextServerSettingsContent> {
+        #[derive(Deserialize)]
+        struct VsCodeContextServerCommand {
+            command: PathBuf,
+            args: Option<Vec<String>>,
+            env: Option<HashMap<String, String>>,
+            // note: we don't support envFile and type
+        }
+        let Some(mcp) = self.read_value("mcp").and_then(|v| v.as_object()) else {
+            return Default::default();
+        };
+        mcp.iter()
+            .filter_map(|(k, v)| {
+                Some((
+                    k.clone().into(),
+                    ContextServerSettingsContent::Custom {
+                        enabled: true,
+                        command: serde_json::from_value::<VsCodeContextServerCommand>(v.clone())
+                            .ok()
+                            .map(|cmd| ContextServerCommand {
+                                path: cmd.command,
+                                args: cmd.args.unwrap_or_default(),
+                                env: cmd.env,
+                                timeout: None,
+                            })?,
+                    },
+                ))
+            })
+            .collect()
+    }
+
+    fn item_settings_content(&self) -> Option<ItemSettingsContent> {
+        skip_default(ItemSettingsContent {
+            git_status: self.read_bool("git.decorations.enabled"),
+            close_position: self.read_enum("workbench.editor.tabActionLocation", |s| match s {
+                "right" => Some(ClosePosition::Right),
+                "left" => Some(ClosePosition::Left),
+                _ => None,
+            }),
+            file_icons: self.read_bool("workbench.editor.showIcons"),
+            activate_on_close: self
+                .read_bool("workbench.editor.focusRecentEditorAfterClose")
+                .map(|b| {
+                    if b {
+                        ActivateOnClose::History
+                    } else {
+                        ActivateOnClose::LeftNeighbour
+                    }
+                }),
+            show_diagnostics: None,
+            show_close_button: self
+                .read_bool("workbench.editor.tabActionCloseVisibility")
+                .map(|b| {
+                    if b {
+                        ShowCloseButton::Always
+                    } else {
+                        ShowCloseButton::Hidden
+                    }
+                }),
+        })
+    }
+
+    fn preview_tabs_settings_content(&self) -> Option<PreviewTabsSettingsContent> {
+        skip_default(PreviewTabsSettingsContent {
+            enabled: self.read_bool("workbench.editor.enablePreview"),
+            enable_preview_from_file_finder: self
+                .read_bool("workbench.editor.enablePreviewFromQuickOpen"),
+            enable_preview_from_code_navigation: self
+                .read_bool("workbench.editor.enablePreviewFromCodeNavigation"),
+        })
+    }
+
+    fn tab_bar_settings_content(&self) -> Option<TabBarSettingsContent> {
+        skip_default(TabBarSettingsContent {
+            show: self.read_enum("workbench.editor.showTabs", |s| match s {
+                "multiple" => Some(true),
+                "single" | "none" => Some(false),
+                _ => None,
+            }),
+            show_nav_history_buttons: None,
+            show_tab_bar_buttons: self
+                .read_str("workbench.editor.editorActionsLocation")
+                .and_then(|str| if str == "hidden" { Some(false) } else { None }),
+        })
+    }
+
+    fn status_bar_settings_content(&self) -> Option<StatusBarSettingsContent> {
+        skip_default(StatusBarSettingsContent {
+            show: self.read_bool("workbench.statusBar.visible"),
+            active_language_button: None,
+            cursor_position_button: None,
+        })
+    }
+
+    fn project_panel_settings_content(&self) -> Option<ProjectPanelSettingsContent> {
+        let mut project_panel_settings = ProjectPanelSettingsContent {
+            auto_fold_dirs: self.read_bool("explorer.compactFolders"),
+            auto_reveal_entries: self.read_bool("explorer.autoReveal"),
+            button: None,
+            default_width: None,
+            dock: None,
+            drag_and_drop: None,
+            entry_spacing: None,
+            file_icons: None,
+            folder_icons: None,
+            git_status: self.read_bool("git.decorations.enabled"),
+            hide_gitignore: self.read_bool("explorer.excludeGitIgnore"),
+            hide_hidden: None,
+            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,
+        };
+
+        if let (Some(false), Some(false)) = (
+            self.read_bool("explorer.decorations.badges"),
+            self.read_bool("explorer.decorations.colors"),
+        ) {
+            project_panel_settings.git_status = Some(false);
+            project_panel_settings.show_diagnostics = Some(ShowDiagnostics::Off);
+        }
+
+        skip_default(project_panel_settings)
+    }
+
+    fn telemetry_settings_content(&self) -> Option<TelemetrySettingsContent> {
+        self.read_enum("telemetry.telemetryLevel", |level| {
+            let (metrics, diagnostics) = match level {
+                "all" => (true, true),
+                "error" | "crash" => (false, true),
+                "off" => (false, false),
+                _ => return None,
+            };
+            Some(TelemetrySettingsContent {
+                metrics: Some(metrics),
+                diagnostics: Some(diagnostics),
+            })
+        })
+    }
+
+    fn terminal_settings_content(&self) -> Option<TerminalSettingsContent> {
+        let (font_family, font_fallbacks) = self.read_fonts("terminal.integrated.fontFamily");
+        skip_default(TerminalSettingsContent {
+            alternate_scroll: None,
+            blinking: self
+                .read_bool("terminal.integrated.cursorBlinking")
+                .map(|b| {
+                    if b {
+                        TerminalBlink::On
+                    } else {
+                        TerminalBlink::Off
+                    }
+                }),
+            button: None,
+            copy_on_select: self.read_bool("terminal.integrated.copyOnSelection"),
+            cursor_shape: self.read_enum("terminal.integrated.cursorStyle", |s| match s {
+                "block" => Some(CursorShapeContent::Block),
+                "line" => Some(CursorShapeContent::Bar),
+                "underline" => Some(CursorShapeContent::Underline),
+                _ => None,
+            }),
+            default_height: None,
+            default_width: None,
+            dock: None,
+            font_fallbacks,
+            font_family,
+            font_features: None,
+            font_size: self.read_f32("terminal.integrated.fontSize"),
+            font_weight: None,
+            keep_selection_on_copy: None,
+            line_height: self
+                .read_f32("terminal.integrated.lineHeight")
+                .map(|lh| TerminalLineHeight::Custom(lh)),
+            max_scroll_history_lines: self.read_usize("terminal.integrated.scrollback"),
+            minimum_contrast: None,
+            option_as_meta: self.read_bool("terminal.integrated.macOptionIsMeta"),
+            project: self.project_terminal_settings_content(),
+            scrollbar: None,
+            toolbar: None,
+        })
+    }
+
+    fn project_terminal_settings_content(&self) -> ProjectTerminalSettingsContent {
+        #[cfg(target_os = "windows")]
+        let platform = "windows";
+        #[cfg(target_os = "linux")]
+        let platform = "linux";
+        #[cfg(target_os = "macos")]
+        let platform = "osx";
+        #[cfg(target_os = "freebsd")]
+        let platform = "freebsd";
+        let env = self
+            .read_value(&format!("terminal.integrated.env.{platform}"))
+            .and_then(|v| v.as_object())
+            .map(|v| v.iter().map(|(k, v)| (k.clone(), v.to_string())).collect());
+
+        ProjectTerminalSettingsContent {
+            // TODO: handle arguments
+            shell: self
+                .read_string(&format!("terminal.integrated.{platform}Exec"))
+                .map(|s| Shell::Program(s)),
+            working_directory: None,
+            env,
+            detect_venv: None,
+        }
+    }
+
+    fn theme_settings_content(&self) -> ThemeSettingsContent {
+        let (buffer_font_family, buffer_font_fallbacks) = self.read_fonts("editor.fontFamily");
+        ThemeSettingsContent {
+            ui_font_size: None,
+            ui_font_family: None,
+            ui_font_fallbacks: None,
+            ui_font_features: None,
+            ui_font_weight: None,
+            buffer_font_family,
+            buffer_font_fallbacks,
+            buffer_font_size: self.read_f32("editor.fontSize"),
+            buffer_font_weight: self.read_f32("editor.fontWeight").map(|w| w.into()),
+            buffer_line_height: None,
+            buffer_font_features: None,
+            agent_ui_font_size: None,
+            agent_buffer_font_size: None,
+            theme: None,
+            icon_theme: None,
+            ui_density: None,
+            unnecessary_code_fade: None,
+            experimental_theme_overrides: None,
+            theme_overrides: Default::default(),
+        }
+    }
+
+    fn workspace_settings_content(&self) -> WorkspaceSettingsContent {
+        WorkspaceSettingsContent {
+            active_pane_modifiers: self.active_pane_modifiers(),
+            autosave: self.read_enum("files.autoSave", |s| match s {
+                "off" => Some(AutosaveSetting::Off),
+                "afterDelay" => Some(AutosaveSetting::AfterDelay {
+                    milliseconds: self
+                        .read_value("files.autoSaveDelay")
+                        .and_then(|v| v.as_u64())
+                        .unwrap_or(1000),
+                }),
+                "onFocusChange" => Some(AutosaveSetting::OnFocusChange),
+                "onWindowChange" => Some(AutosaveSetting::OnWindowChange),
+                _ => None,
+            }),
+            bottom_dock_layout: None,
+            centered_layout: None,
+            close_on_file_delete: None,
+            command_aliases: Default::default(),
+            confirm_quit: self.read_enum("window.confirmBeforeClose", |s| match s {
+                "always" | "keyboardOnly" => Some(true),
+                "never" => Some(false),
+                _ => None,
+            }),
+            drop_target_size: None,
+            // workbench.editor.limit contains "enabled", "value", and "perEditorGroup"
+            // our semantics match if those are set to true, some N, and true respectively.
+            // we'll ignore "perEditorGroup" for now since we only support a global max
+            max_tabs: if self.read_bool("workbench.editor.limit.enabled") == Some(true) {
+                self.read_usize("workbench.editor.limit.value")
+                    .and_then(|n| NonZeroUsize::new(n))
+            } else {
+                None
+            },
+            on_last_window_closed: None,
+            pane_split_direction_horizontal: None,
+            pane_split_direction_vertical: None,
+            resize_all_panels_in_dock: None,
+            restore_on_file_reopen: self.read_bool("workbench.editor.restoreViewState"),
+            restore_on_startup: None,
+            show_call_status_icon: None,
+            use_system_path_prompts: self.read_bool("files.simpleDialog.enable"),
+            use_system_prompts: None,
+            use_system_window_tabs: self.read_bool("window.nativeTabs"),
+            when_closing_with_no_tabs: self.read_bool("window.closeWhenEmpty").map(|b| {
+                if b {
+                    CloseWindowWhenNoItems::CloseWindow
+                } else {
+                    CloseWindowWhenNoItems::KeepWindowOpen
+                }
+            }),
+            zoomed_padding: None,
+        }
+    }
+
+    fn active_pane_modifiers(&self) -> Option<ActivePaneModifiers> {
+        if self.read_bool("accessibility.dimUnfocused.enabled") == Some(true)
+            && let Some(opacity) = self.read_f32("accessibility.dimUnfocused.opacity")
+        {
+            Some(ActivePaneModifiers {
+                border_size: None,
+                inactive_opacity: Some(opacity),
+            })
+        } else {
+            None
+        }
+    }
+
+    fn worktree_settings_content(&self) -> WorktreeSettingsContent {
+        WorktreeSettingsContent {
+            project_name: None,
+            file_scan_exclusions: self
+                .read_value("files.watcherExclude")
+                .and_then(|v| v.as_array())
+                .map(|v| {
+                    v.iter()
+                        .filter_map(|n| n.as_str().map(str::to_owned))
+                        .collect::<Vec<_>>()
+                })
+                .filter(|r| !r.is_empty()),
+            file_scan_inclusions: self
+                .read_value("files.watcherInclude")
+                .and_then(|v| v.as_array())
+                .map(|v| {
+                    v.iter()
+                        .filter_map(|n| n.as_str().map(str::to_owned))
+                        .collect::<Vec<_>>()
+                })
+                .filter(|r| !r.is_empty()),
+            private_files: None,
+        }
+    }
+}
+
+fn skip_default<T: Default + PartialEq>(value: T) -> Option<T> {
+    if value == T::default() {
+        None
+    } else {
+        Some(value)
+    }
 }

crates/terminal/src/terminal_settings.rs 🔗

@@ -8,9 +8,8 @@ use serde::{Deserialize, Serialize};
 
 pub use settings::AlternateScroll;
 use settings::{
-    CursorShapeContent, SettingsContent, ShowScrollbar, TerminalBlink, TerminalDockPosition,
-    TerminalLineHeight, TerminalSettingsContent, VenvSettings, WorkingDirectory,
-    merge_from::MergeFrom,
+    ShowScrollbar, TerminalBlink, TerminalDockPosition, TerminalLineHeight, VenvSettings,
+    WorkingDirectory, merge_from::MergeFrom,
 };
 use task::Shell;
 use theme::FontFamilyName;
@@ -116,81 +115,6 @@ impl settings::Settings for TerminalSettings {
             minimum_contrast: user_content.minimum_contrast.unwrap(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, content: &mut SettingsContent) {
-        let mut default = TerminalSettingsContent::default();
-        let current = content.terminal.as_mut().unwrap_or(&mut default);
-        let name = |s| format!("terminal.integrated.{s}");
-
-        vscode.f32_setting(&name("fontSize"), &mut current.font_size);
-        vscode.font_family_setting(
-            &name("fontFamily"),
-            &mut current.font_family,
-            &mut current.font_fallbacks,
-        );
-        vscode.bool_setting(&name("copyOnSelection"), &mut current.copy_on_select);
-        vscode.bool_setting("macOptionIsMeta", &mut current.option_as_meta);
-        vscode.usize_setting("scrollback", &mut current.max_scroll_history_lines);
-        match vscode.read_bool(&name("cursorBlinking")) {
-            Some(true) => current.blinking = Some(TerminalBlink::On),
-            Some(false) => current.blinking = Some(TerminalBlink::Off),
-            None => {}
-        }
-        vscode.enum_setting(
-            &name("cursorStyle"),
-            &mut current.cursor_shape,
-            |s| match s {
-                "block" => Some(CursorShapeContent::Block),
-                "line" => Some(CursorShapeContent::Bar),
-                "underline" => Some(CursorShapeContent::Underline),
-                _ => None,
-            },
-        );
-        // they also have "none" and "outline" as options but just for the "Inactive" variant
-        if let Some(height) = vscode
-            .read_value(&name("lineHeight"))
-            .and_then(|v| v.as_f64())
-        {
-            current.line_height = Some(TerminalLineHeight::Custom(height as f32))
-        }
-
-        #[cfg(target_os = "windows")]
-        let platform = "windows";
-        #[cfg(target_os = "linux")]
-        let platform = "linux";
-        #[cfg(target_os = "macos")]
-        let platform = "osx";
-        #[cfg(target_os = "freebsd")]
-        let platform = "freebsd";
-
-        // TODO: handle arguments
-        let shell_name = format!("{platform}Exec");
-        if let Some(s) = vscode.read_string(&name(&shell_name)) {
-            current.project.shell = Some(settings::Shell::Program(s.to_owned()))
-        }
-
-        if let Some(env) = vscode
-            .read_value(&name(&format!("env.{platform}")))
-            .and_then(|v| v.as_object())
-        {
-            for (k, v) in env {
-                if v.is_null()
-                    && let Some(zed_env) = current.project.env.as_mut()
-                {
-                    zed_env.remove(k);
-                }
-                let Some(v) = v.as_str() else { continue };
-                if let Some(zed_env) = current.project.env.as_mut() {
-                    zed_env.insert(k.clone(), v.to_owned());
-                } else {
-                    current.project.env = Some([(k.clone(), v.to_owned())].into_iter().collect())
-                }
-            }
-        }
-        if content.terminal.is_none() && default != TerminalSettingsContent::default() {
-            content.terminal = Some(default)
-        }
-    }
 }
 
 #[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]

crates/theme/src/settings.rs 🔗

@@ -727,15 +727,4 @@ impl settings::Settings for ThemeSettings {
             unnecessary_code_fade: content.unnecessary_code_fade.unwrap().0.clamp(0.0, 0.9),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        vscode.from_f32_setting("editor.fontWeight", &mut current.theme.buffer_font_weight);
-        vscode.from_f32_setting("editor.fontSize", &mut current.theme.buffer_font_size);
-        vscode.font_family_setting(
-            "editor.fontFamily",
-            &mut current.theme.buffer_font_family,
-            &mut current.theme.buffer_font_fallbacks,
-        )
-        // TODO: possibly map editor.fontLigatures to buffer_font_features?
-    }
 }

crates/vim_mode_setting/src/vim_mode_setting.rs 🔗

@@ -19,10 +19,6 @@ impl Settings for VimModeSetting {
     fn from_settings(content: &SettingsContent) -> Self {
         Self(content.vim_mode.unwrap())
     }
-
-    fn import_from_vscode(_vscode: &settings::VsCodeSettings, _content: &mut SettingsContent) {
-        // TODO: could possibly check if any of the `vim.<foo>` keys are set?
-    }
 }
 
 pub struct HelixModeSetting(pub bool);
@@ -31,6 +27,4 @@ impl Settings for HelixModeSetting {
     fn from_settings(content: &SettingsContent) -> Self {
         Self(content.helix_mode.unwrap())
     }
-
-    fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut SettingsContent) {}
 }

crates/workspace/src/item.rs 🔗

@@ -76,40 +76,6 @@ impl Settings for ItemSettings {
             show_close_button: tabs.show_close_button.unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if let Some(b) = vscode.read_bool("workbench.editor.tabActionCloseVisibility") {
-            current.tabs.get_or_insert_default().show_close_button = Some(if b {
-                ShowCloseButton::Always
-            } else {
-                ShowCloseButton::Hidden
-            })
-        }
-        if let Some(s) = vscode.read_enum("workbench.editor.tabActionLocation", |s| match s {
-            "right" => Some(ClosePosition::Right),
-            "left" => Some(ClosePosition::Left),
-            _ => None,
-        }) {
-            current.tabs.get_or_insert_default().close_position = Some(s)
-        }
-        if let Some(b) = vscode.read_bool("workbench.editor.focusRecentEditorAfterClose") {
-            current.tabs.get_or_insert_default().activate_on_close = Some(if b {
-                ActivateOnClose::History
-            } else {
-                ActivateOnClose::LeftNeighbour
-            })
-        }
-
-        if let Some(b) = vscode.read_bool("workbench.editor.showIcons") {
-            current.tabs.get_or_insert_default().file_icons = Some(b);
-        };
-        if let Some(b) = vscode.read_bool("git.decorations.enabled") {
-            current.tabs.get_or_insert_default().git_status = Some(b);
-        }
-    }
 }
 
 impl Settings for PreviewTabsSettings {
@@ -123,31 +89,6 @@ impl Settings for PreviewTabsSettings {
                 .unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if let Some(enabled) = vscode.read_bool("workbench.editor.enablePreview") {
-            current.preview_tabs.get_or_insert_default().enabled = Some(enabled);
-        }
-        if let Some(enable_preview_from_code_navigation) =
-            vscode.read_bool("workbench.editor.enablePreviewFromCodeNavigation")
-        {
-            current
-                .preview_tabs
-                .get_or_insert_default()
-                .enable_preview_from_code_navigation = Some(enable_preview_from_code_navigation)
-        }
-        if let Some(enable_preview_from_file_finder) =
-            vscode.read_bool("workbench.editor.enablePreviewFromQuickOpen")
-        {
-            current
-                .preview_tabs
-                .get_or_insert_default()
-                .enable_preview_from_file_finder = Some(enable_preview_from_file_finder)
-        }
-    }
 }
 
 #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]

crates/workspace/src/workspace_settings.rs 🔗

@@ -108,91 +108,6 @@ impl Settings for WorkspaceSettings {
             zoomed_padding: workspace.zoomed_padding.unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if vscode
-            .read_bool("accessibility.dimUnfocused.enabled")
-            .unwrap_or_default()
-            && let Some(opacity) = vscode
-                .read_value("accessibility.dimUnfocused.opacity")
-                .and_then(|v| v.as_f64())
-        {
-            current
-                .workspace
-                .active_pane_modifiers
-                .get_or_insert_default()
-                .inactive_opacity = Some(opacity as f32);
-        }
-
-        vscode.enum_setting(
-            "window.confirmBeforeClose",
-            &mut current.workspace.confirm_quit,
-            |s| match s {
-                "always" | "keyboardOnly" => Some(true),
-                "never" => Some(false),
-                _ => None,
-            },
-        );
-
-        vscode.bool_setting(
-            "workbench.editor.restoreViewState",
-            &mut current.workspace.restore_on_file_reopen,
-        );
-
-        if let Some(b) = vscode.read_bool("window.closeWhenEmpty") {
-            current.workspace.when_closing_with_no_tabs = Some(if b {
-                settings::CloseWindowWhenNoItems::CloseWindow
-            } else {
-                settings::CloseWindowWhenNoItems::KeepWindowOpen
-            });
-        }
-
-        if let Some(b) = vscode.read_bool("files.simpleDialog.enable") {
-            current.workspace.use_system_path_prompts = Some(!b);
-        }
-
-        if let Some(v) = vscode.read_enum("files.autoSave", |s| match s {
-            "off" => Some(AutosaveSetting::Off),
-            "afterDelay" => Some(AutosaveSetting::AfterDelay {
-                milliseconds: vscode
-                    .read_value("files.autoSaveDelay")
-                    .and_then(|v| v.as_u64())
-                    .unwrap_or(1000),
-            }),
-            "onFocusChange" => Some(AutosaveSetting::OnFocusChange),
-            "onWindowChange" => Some(AutosaveSetting::OnWindowChange),
-            _ => None,
-        }) {
-            current.workspace.autosave = Some(v);
-        }
-
-        // workbench.editor.limit contains "enabled", "value", and "perEditorGroup"
-        // our semantics match if those are set to true, some N, and true respectively.
-        // we'll ignore "perEditorGroup" for now since we only support a global max
-        if let Some(n) = vscode
-            .read_value("workbench.editor.limit.value")
-            .and_then(|v| v.as_u64())
-            .and_then(|n| NonZeroUsize::new(n as usize))
-            && vscode
-                .read_bool("workbench.editor.limit.enabled")
-                .unwrap_or_default()
-        {
-            current.workspace.max_tabs = Some(n)
-        }
-
-        if let Some(b) = vscode.read_bool("window.nativeTabs") {
-            current.workspace.use_system_window_tabs = Some(b);
-        }
-
-        // some combination of "window.restoreWindows" and "workbench.startupEditor" might
-        // map to our "restore_on_startup"
-
-        // there doesn't seem to be a way to read whether the bottom dock's "justified"
-        // setting is enabled in vscode. that'd be our equivalent to "bottom_dock_layout"
-    }
 }
 
 impl Settings for TabBarSettings {
@@ -204,22 +119,6 @@ impl Settings for TabBarSettings {
             show_tab_bar_buttons: tab_bar.show_tab_bar_buttons.unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if let Some(b) = vscode.read_enum("workbench.editor.showTabs", |s| match s {
-            "multiple" => Some(true),
-            "single" | "none" => Some(false),
-            _ => None,
-        }) {
-            current.tab_bar.get_or_insert_default().show = Some(b);
-        }
-        if Some("hidden") == vscode.read_string("workbench.editor.editorActionsLocation") {
-            current.tab_bar.get_or_insert_default().show_tab_bar_buttons = Some(false)
-        }
-    }
 }
 
 #[derive(Deserialize)]
@@ -238,13 +137,4 @@ impl Settings for StatusBarSettings {
             cursor_position_button: status_bar.cursor_position_button.unwrap(),
         }
     }
-
-    fn import_from_vscode(
-        vscode: &settings::VsCodeSettings,
-        current: &mut settings::SettingsContent,
-    ) {
-        if let Some(show) = vscode.read_bool("workbench.statusBar.visible") {
-            current.status_bar.get_or_insert_default().show = Some(show);
-        }
-    }
 }

crates/worktree/src/worktree_settings.rs 🔗

@@ -1,7 +1,7 @@
 use std::path::Path;
 
 use anyhow::Context as _;
-use settings::{Settings, SettingsContent};
+use settings::Settings;
 use util::{
     ResultExt,
     paths::{PathMatcher, PathStyle},
@@ -64,31 +64,6 @@ impl Settings for WorktreeSettings {
                 .unwrap_or_default(),
         }
     }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
-        if let Some(inclusions) = vscode
-            .read_value("files.watcherInclude")
-            .and_then(|v| v.as_array())
-            .and_then(|v| v.iter().map(|n| n.as_str().map(str::to_owned)).collect())
-        {
-            if let Some(old) = current.project.worktree.file_scan_inclusions.as_mut() {
-                old.extend(inclusions)
-            } else {
-                current.project.worktree.file_scan_inclusions = Some(inclusions)
-            }
-        }
-        if let Some(exclusions) = vscode
-            .read_value("files.watcherExclude")
-            .and_then(|v| v.as_array())
-            .and_then(|v| v.iter().map(|n| n.as_str().map(str::to_owned)).collect())
-        {
-            if let Some(old) = current.project.worktree.file_scan_exclusions.as_mut() {
-                old.extend(exclusions)
-            } else {
-                current.project.worktree.file_scan_exclusions = Some(exclusions)
-            }
-        }
-    }
 }
 
 fn path_matchers(mut values: Vec<String>, context: &'static str) -> anyhow::Result<PathMatcher> {

crates/zlog_settings/src/zlog_settings.rs 🔗

@@ -29,6 +29,4 @@ impl Settings for ZlogSettings {
             scopes: content.log.clone().unwrap(),
         }
     }
-
-    fn import_from_vscode(_: &settings::VsCodeSettings, _: &mut settings::SettingsContent) {}
 }