VSCode settings import refactor (#40513)
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
This commit is contained in:
@@ -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> {
|
||||
fn read_string(&self, setting: &str) -> Option<String> {
|
||||
self.read_value(setting)
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_owned())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
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 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_u64(&self, setting: &str) -> Option<u64> {
|
||||
self.read_value(setting).and_then(|v| v.as_u64())
|
||||
}
|
||||
|
||||
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_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 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_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 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())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
let mut iter = fonts.into_iter();
|
||||
*font_family = iter.next();
|
||||
let fallbacks: Vec<_> = iter.collect();
|
||||
if !fallbacks.is_empty() {
|
||||
*font_fallbacks = Some(fallbacks);
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user