Detailed changes
@@ -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);
- }
- }
}
@@ -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 {
@@ -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)
- }
- }
}
@@ -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());
- }
- }
}
@@ -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)]
@@ -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);
- }
- }
}
@@ -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 {
@@ -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 {
@@ -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);
- }
- }
}
@@ -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);
- }
}
@@ -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"
@@ -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)
+ }
}
@@ -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)]
@@ -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?
- }
}
@@ -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) {}
}
@@ -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)]
@@ -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);
- }
- }
}
@@ -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> {
@@ -29,6 +29,4 @@ impl Settings for ZlogSettings {
scopes: content.log.clone().unwrap(),
}
}
-
- fn import_from_vscode(_: &settings::VsCodeSettings, _: &mut settings::SettingsContent) {}
}