diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index 6c87ec5b5183bd5b37e9dd52d53c8fa0f8f28db1..0e23a69f075fc35b2f284c244a15428d57a354a4 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -269,7 +269,7 @@ async fn test_first_line_pattern(cx: &mut TestAppContext) { async fn test_language_for_file_with_custom_file_types(cx: &mut TestAppContext) { cx.update(|cx| { init_settings(cx, |settings| { - settings.file_types.extend([ + settings.file_types.get_or_insert_default().extend([ ("TypeScript".into(), vec!["js".into()].into()), ( "JavaScript".into(), diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index 445f227e13dbac81a9f83b4faa0104fb7fcade17..0fc28672edadf144916f44e4d642c82e81fc8470 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -623,7 +623,7 @@ impl settings::Settings for AllLanguageSettings { let mut file_types: FxHashMap, GlobSet> = FxHashMap::default(); - for (language, patterns) in &all_languages.file_types { + for (language, patterns) in all_languages.file_types.iter().flatten() { let mut builder = GlobSetBuilder::new(); for pattern in &patterns.0 { @@ -761,6 +761,7 @@ impl settings::Settings for AllLanguageSettings { .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 diff --git a/crates/settings/src/settings_content.rs b/crates/settings/src/settings_content.rs index 3599ac4110360c62071ea40bd2c73935fc5116ec..92493557eeeb5f28c6a4d25fca3f9e38f8eef6bb 100644 --- a/crates/settings/src/settings_content.rs +++ b/crates/settings/src/settings_content.rs @@ -234,7 +234,6 @@ impl UserSettingsContent { Eq, Default, strum::VariantArray, - strum::VariantNames, )] pub enum BaseKeymapContent { #[default] @@ -248,6 +247,19 @@ pub enum BaseKeymapContent { None, } +impl strum::VariantNames for BaseKeymapContent { + const VARIANTS: &'static [&'static str] = &[ + "VSCode", + "JetBrains", + "Sublime Text", + "Atom", + "TextMate", + "Emacs", + "Cursor", + "None", + ]; +} + #[skip_serializing_none] #[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom, Debug)] pub struct TitleBarSettingsContent { @@ -502,7 +514,18 @@ pub struct GitPanelSettingsContent { } #[derive( - Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq, + Default, + Copy, + Clone, + Debug, + Serialize, + Deserialize, + JsonSchema, + MergeFrom, + PartialEq, + Eq, + strum::VariantArray, + strum::VariantNames, )] #[serde(rename_all = "snake_case")] pub enum StatusStyle { @@ -512,7 +535,9 @@ pub enum StatusStyle { } #[skip_serializing_none] -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq)] +#[derive( + Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Eq, +)] pub struct ScrollbarSettings { pub show: Option, } @@ -814,7 +839,19 @@ pub struct ImageViewerSettingsContent { } #[skip_serializing_none] -#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, MergeFrom, Default, PartialEq)] +#[derive( + Clone, + Copy, + Debug, + Serialize, + Deserialize, + JsonSchema, + MergeFrom, + Default, + PartialEq, + strum::VariantArray, + strum::VariantNames, +)] #[serde(rename_all = "snake_case")] pub enum ImageFileSizeUnit { /// Displays file size in binary units (e.g., KiB, MiB). diff --git a/crates/settings/src/settings_content/editor.rs b/crates/settings/src/settings_content/editor.rs index 5bd1b0daf9206b6ea97374a0281c7f737e0fc2e0..171cb874fcdea23bd51ffa453b30c6d96587fe6a 100644 --- a/crates/settings/src/settings_content/editor.rs +++ b/crates/settings/src/settings_content/editor.rs @@ -334,7 +334,18 @@ pub struct GutterContent { /// How to render LSP `textDocument/documentColor` colors in the editor. #[derive( - Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom, + Copy, + Clone, + Debug, + Default, + Serialize, + Deserialize, + PartialEq, + Eq, + JsonSchema, + MergeFrom, + strum::VariantArray, + strum::VariantNames, )] #[serde(rename_all = "snake_case")] pub enum DocumentColorsRenderMode { diff --git a/crates/settings/src/settings_content/language.rs b/crates/settings/src/settings_content/language.rs index 1798098f4304412fe640a16ca8786385d11e0b96..049ab4255c0a276d85121079f6b1d9657f485aa7 100644 --- a/crates/settings/src/settings_content/language.rs +++ b/crates/settings/src/settings_content/language.rs @@ -27,8 +27,7 @@ pub struct AllLanguageSettingsContent { pub languages: LanguageToSettingsMap, /// Settings for associating file extensions and filenames /// with languages. - #[serde(default)] - pub file_types: HashMap, ExtendingVec>, + pub file_types: Option, ExtendingVec>>, } impl merge_from::MergeFrom for AllLanguageSettingsContent { diff --git a/crates/settings/src/settings_content/workspace.rs b/crates/settings/src/settings_content/workspace.rs index 511c883a4386c6b2ea634dc751c0f38fe5c8079c..b4302c9e5616cca99493ee9c4ac0e2ffc9dba6ef 100644 --- a/crates/settings/src/settings_content/workspace.rs +++ b/crates/settings/src/settings_content/workspace.rs @@ -12,7 +12,7 @@ use crate::{DockPosition, DockSide, ScrollbarSettingsContent, ShowIndentGuides}; #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] pub struct WorkspaceSettingsContent { /// Active pane styling settings. - pub active_pane_modifiers: Option, + pub active_pane_modifiers: Option, /// Layout mode for the bottom dock /// /// Default: contained @@ -243,7 +243,7 @@ pub enum ActivateOnClose { #[skip_serializing_none] #[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] #[serde(rename_all = "snake_case")] -pub struct ActivePanelModifiers { +pub struct ActivePaneModifiers { /// Size of the border surrounding the active pane. /// When set to 0, the active pane doesn't have any border. /// The border is drawn inset. @@ -403,14 +403,38 @@ impl AutosaveSetting { } } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)] +#[derive( + Copy, + Clone, + Debug, + Serialize, + Deserialize, + PartialEq, + Eq, + JsonSchema, + MergeFrom, + strum::VariantArray, + strum::VariantNames, +)] #[serde(rename_all = "snake_case")] pub enum PaneSplitDirectionHorizontal { Up, Down, } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)] +#[derive( + Copy, + Clone, + Debug, + Serialize, + Deserialize, + PartialEq, + Eq, + JsonSchema, + MergeFrom, + strum::VariantArray, + strum::VariantNames, +)] #[serde(rename_all = "snake_case")] pub enum PaneSplitDirectionVertical { Left, diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index 95c8e0a5a3b49841e120cbc0baa22e3608c7e6db..fe782e9c2ec0be1c54f298ba29b209ca745526db 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -24,18 +24,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), - SettingsPageItem::SettingItem(SettingItem { - title: "Restore On Startup", - description: "Restore previous session when opening Zed", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.restore_on_startup, - pick_mut: |settings_content| { - &mut settings_content.workspace.restore_on_startup - }, - }), - metadata: None, - files: USER, - }), SettingsPageItem::SettingItem(SettingItem { title: "When Closing With No Tabs", description: "What to do when using the 'close active item' action with no tabs", @@ -100,6 +88,54 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Private Files", + description: "Globs to match against file paths to determine if a file is private", + field: Box::new( + SettingField { + pick: |settings_content| { + &settings_content.project.worktree.private_files + }, + pick_mut: |settings_content| { + &mut settings_content.project.worktree.private_files + }, + } + .unimplemented(), + ), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("Workspace Restoration"), + SettingsPageItem::SettingItem(SettingItem { + title: "Restore Unsaved Buffers", + description: "Whether or not to restore unsaved buffers on restart", + field: Box::new(SettingField { + pick: |settings_content| match settings_content.session.as_ref() { + Some(session) => &session.restore_unsaved_buffers, + None => &None, + }, + pick_mut: |settings_content| { + &mut settings_content + .session + .get_or_insert_default() + .restore_unsaved_buffers + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Restore On Startup", + description: "What to restore from the previous session when opening Zed", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.restore_on_startup, + pick_mut: |settings_content| { + &mut settings_content.workspace.restore_on_startup + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SectionHeader("Scoped Settings"), SettingsPageItem::SettingItem(SettingItem { // todo(settings_ui): Implement another setting item type that just shows an edit in settings.json @@ -172,10 +208,21 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Auto Update"), + SettingsPageItem::SettingItem(SettingItem { + title: "Auto Update", + description: "Whether or not to automatically check for updates", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.auto_update, + pick_mut: |settings_content| &mut settings_content.auto_update, + }), + metadata: None, + files: USER, + }), ], }, SettingsPage { - title: "Appearance & Behavior", + title: "Appearance", items: vec![ SettingsPageItem::SectionHeader("Theme"), // todo(settings_ui): Figure out how we want to add these @@ -254,6 +301,36 @@ pub(crate) fn settings_data(cx: &App) -> Vec { ), metadata: None, }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "Buffer Font Features", + description: "The OpenType features to enable for rendering in text buffers.", + field: Box::new( + SettingField { + pick: |settings_content| &settings_content.theme.buffer_font_features, + pick_mut: |settings_content| { + &mut settings_content.theme.buffer_font_features + }, + } + .unimplemented(), + ), + metadata: None, + }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "Buffer Font Fallbacks", + description: "The font fallbacks to use for rendering in text buffers.", + field: Box::new( + SettingField { + pick: |settings_content| &settings_content.theme.buffer_font_fallbacks, + pick_mut: |settings_content| { + &mut settings_content.theme.buffer_font_fallbacks + }, + } + .unimplemented(), + ), + metadata: None, + }), SettingsPageItem::SettingItem(SettingItem { title: "UI Font Family", description: "Font family for UI elements", @@ -284,6 +361,36 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "UI Font Features", + description: "The OpenType features to enable for rendering in UI elements.", + field: Box::new( + SettingField { + pick: |settings_content| &settings_content.theme.ui_font_features, + pick_mut: |settings_content| { + &mut settings_content.theme.ui_font_features + }, + } + .unimplemented(), + ), + metadata: None, + }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "UI Font Fallbacks", + description: "The font fallbacks to use for rendering in the UI.", + field: Box::new( + SettingField { + pick: |settings_content| &settings_content.theme.ui_font_fallbacks, + pick_mut: |settings_content| { + &mut settings_content.theme.ui_font_fallbacks + }, + } + .unimplemented(), + ), + metadata: None, + }), SettingsPageItem::SettingItem(SettingItem { title: "Agent Panel UI Font Size", description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.", @@ -312,39 +419,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), - SettingsPageItem::SectionHeader("Keymap"), - SettingsPageItem::SettingItem(SettingItem { - title: "Base Keymap", - description: "The name of a base set of key bindings to use", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.base_keymap, - pick_mut: |settings_content| &mut settings_content.base_keymap, - }), - metadata: None, - files: USER, - }), - // todo(settings_ui): Vim/Helix Mode should be apart of one type because it's undefined - // behavior to have them both enabled at the same time - SettingsPageItem::SettingItem(SettingItem { - title: "Vim Mode", - description: "Enable vim modes and key bindings", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.vim_mode, - pick_mut: |settings_content| &mut settings_content.vim_mode, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Helix Mode", - description: "Enable helix modes and key bindings", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.helix_mode, - pick_mut: |settings_content| &mut settings_content.helix_mode, - }), - metadata: None, - files: USER, - }), SettingsPageItem::SettingItem(SettingItem { title: "Multi Cursor Modifier", description: "Modifier key for adding multiple cursors", @@ -490,87 +564,44 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER | LOCAL, }), - SettingsPageItem::SectionHeader("Layout"), - SettingsPageItem::SettingItem(SettingItem { - title: "Bottom Dock Layout", - description: "Layout mode for the bottom dock", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.bottom_dock_layout, - pick_mut: |settings_content| { - &mut settings_content.workspace.bottom_dock_layout - }, - }), - metadata: None, - files: USER, - }), + ], + }, + SettingsPage { + title: "Keymap", + items: vec![ + SettingsPageItem::SectionHeader("Base Keymap"), SettingsPageItem::SettingItem(SettingItem { - files: USER, - title: "Centered Layout Left Padding", - description: "Left padding for centered layout", + title: "Base Keymap", + description: "The name of a base set of key bindings to use", field: Box::new(SettingField { - pick: |settings_content| { - if let Some(centered_layout) = - &settings_content.workspace.centered_layout - { - ¢ered_layout.left_padding - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .workspace - .centered_layout - .get_or_insert_default() - .left_padding - }, + pick: |settings_content| &settings_content.base_keymap, + pick_mut: |settings_content| &mut settings_content.base_keymap, }), - metadata: None, - }), - SettingsPageItem::SettingItem(SettingItem { + metadata: Some(Box::new(SettingsFieldMetadata { + should_do_titlecase: Some(false), + ..Default::default() + })), files: USER, - title: "Centered Layout Right Padding", - description: "Right padding for centered layout", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(centered_layout) = - &settings_content.workspace.centered_layout - { - ¢ered_layout.right_padding - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .workspace - .centered_layout - .get_or_insert_default() - .right_padding - }, - }), - metadata: None, }), + SettingsPageItem::SectionHeader("Modal Editing"), + // todo(settings_ui): Vim/Helix Mode should be apart of one type because it's undefined + // behavior to have them both enabled at the same time SettingsPageItem::SettingItem(SettingItem { - title: "Zoomed Padding", - description: "Show padding for zoomed panels", + title: "Vim Mode", + description: "Enable vim modes and key bindings", field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.zoomed_padding, - pick_mut: |settings_content| &mut settings_content.workspace.zoomed_padding, + pick: |settings_content| &settings_content.vim_mode, + pick_mut: |settings_content| &mut settings_content.vim_mode, }), metadata: None, files: USER, }), - SettingsPageItem::SectionHeader("Window"), - // todo(settings_ui): Should we filter by platform? SettingsPageItem::SettingItem(SettingItem { - title: "Use System Window Tabs", - description: "(macOS only) Whether to allow windows to tab together", + title: "Helix Mode", + description: "Enable helix modes and key bindings", field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.use_system_window_tabs, - pick_mut: |settings_content| { - &mut settings_content.workspace.use_system_window_tabs - }, + pick: |settings_content| &settings_content.helix_mode, + pick_mut: |settings_content| &mut settings_content.helix_mode, }), metadata: None, files: USER, @@ -581,6 +612,22 @@ pub(crate) fn settings_data(cx: &App) -> Vec { title: "Editor", items: { let mut items = vec![ + SettingsPageItem::SectionHeader("Auto Save"), + SettingsPageItem::SettingItem(SettingItem { + title: "Auto Save Mode", + description: "When to Auto Save Buffer Changes", + field: Box::new( + SettingField { + pick: |settings_content| &settings_content.workspace.autosave, + pick_mut: |settings_content| { + &mut settings_content.workspace.autosave + }, + } + .unimplemented(), + ), + metadata: None, + files: USER, + }), SettingsPageItem::SectionHeader("Multibuffer"), SettingsPageItem::SettingItem(SettingItem { title: "Double Click In Multibuffer", @@ -620,6 +667,27 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Expand Outlines With Depth", + description: "Default depth to expand outline items in the current file", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(outline_panel) = &settings_content.outline_panel { + &outline_panel.expand_outlines_with_depth + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .outline_panel + .get_or_insert_default() + .expand_outlines_with_depth + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SectionHeader("Scrolling"), SettingsPageItem::SettingItem(SettingItem { title: "Scroll Beyond Last Line", @@ -1409,6 +1477,242 @@ pub(crate) fn settings_data(cx: &App) -> Vec { items: { let mut items = vec![]; items.extend(non_editor_language_settings_data()); + items.extend([ + SettingsPageItem::SectionHeader("File Types"), + SettingsPageItem::SettingItem(SettingItem { + title: "File Type Associations", + description: "A Mapping from Languages to files and file extensions that should be treated as that language", + field: Box::new( + SettingField { + pick: |settings_content| { + &settings_content.project.all_languages.file_types + }, + pick_mut: |settings_content| { + &mut settings_content.project.all_languages.file_types + }, + } + .unimplemented(), + ), + metadata: None, + files: USER | LOCAL, + }), + ]); + + items.extend([ + SettingsPageItem::SectionHeader("Diagnostics"), + SettingsPageItem::SettingItem(SettingItem { + title: "Max Severity", + description: "Which level to use to filter out diagnostics displayed in the editor", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.editor.diagnostics_max_severity, + pick_mut: |settings_content| { + &mut settings_content.editor.diagnostics_max_severity + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Include Warnings", + description: "Whether to show warnings or not by default", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + &diagnostics.include_warnings + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .include_warnings + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("Inline Diagnostics"), + SettingsPageItem::SettingItem(SettingItem { + title: "Enabled", + description: "Whether to show diagnostics inline or not", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(inline) = &diagnostics.inline { + &inline.enabled + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .inline + .get_or_insert_default() + .enabled + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Update Debounce", + description: "The delay in milliseconds to show inline diagnostics after the last diagnostic update", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(inline) = &diagnostics.inline { + &inline.update_debounce_ms + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .inline + .get_or_insert_default() + .update_debounce_ms + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Padding", + description: "The amount of padding between the end of the source line and the start of the inline diagnostic", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(inline) = &diagnostics.inline { + &inline.padding + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .inline + .get_or_insert_default() + .padding + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Minimum Column", + description: "The minimum column at which to display inline diagnostics", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(inline) = &diagnostics.inline { + &inline.min_column + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .inline + .get_or_insert_default() + .min_column + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("LSP Pull Diagnostics"), + SettingsPageItem::SettingItem(SettingItem { + title: "Enabled", + description: "Whether to pull for language server-powered diagnostics or not", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(lsp_pull) = &diagnostics.lsp_pull_diagnostics { + &lsp_pull.enabled + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .lsp_pull_diagnostics + .get_or_insert_default() + .enabled + }, + }), + metadata: None, + files: USER, + }), + // todo(settings_ui): Needs unit + SettingsPageItem::SettingItem(SettingItem { + title: "Debounce", + description: "Minimum time to wait before pulling diagnostics from the language server(s)", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(diagnostics) = &settings_content.diagnostics { + if let Some(lsp_pull) = &diagnostics.lsp_pull_diagnostics { + &lsp_pull.debounce_ms + } else { + &None + } + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .diagnostics + .get_or_insert_default() + .lsp_pull_diagnostics + .get_or_insert_default() + .debounce_ms + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("LSP Highlights"), + SettingsPageItem::SettingItem(SettingItem { + title: "Debounce", + description: "The debounce delay before querying highlights from the language", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.editor.lsp_highlight_debounce, + pick_mut: |settings_content| { + &mut settings_content.editor.lsp_highlight_debounce + }, + }), + metadata: None, + files: USER, + }), + ]); + // todo(settings_ui): Refresh on extension (un)/installed // Note that `crates/json_schema_store` solves the same problem, there is probably a way to unify the two items.push(SettingsPageItem::SectionHeader(LANGUAGES_SECTION_HEADER)); @@ -1482,15 +1786,27 @@ pub(crate) fn settings_data(cx: &App) -> Vec { files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Include Ignored", - description: "Include ignored files in search results by default", + title: "Use Smartcase Search", + description: "Whether to automatically enable case-sensitive search based on the search query", field: Box::new(SettingField { - pick: |settings_content| { - if let Some(search) = &settings_content.editor.search { - &search.include_ignored - } else { - &None - } + pick: |settings_content| &settings_content.editor.use_smartcase_search, + pick_mut: |settings_content| { + &mut settings_content.editor.use_smartcase_search + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Include Ignored", + description: "Include ignored files in search results by default", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(search) = &settings_content.editor.search { + &search.include_ignored + } else { + &None + } }, pick_mut: |settings_content| { &mut settings_content @@ -1521,31 +1837,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), - // todo: null by default - SettingsPageItem::SettingItem(SettingItem { - title: "Include Ignored in Search", - description: "Use gitignored files when searching", - field: Box::new( - SettingField { - pick: |settings_content| { - if let Some(file_finder) = &settings_content.file_finder { - &file_finder.include_ignored - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .file_finder - .get_or_insert_default() - .include_ignored - }, - } - .unimplemented(), - ), - metadata: None, - files: USER, - }), SettingsPageItem::SettingItem(SettingItem { title: "Search Wrap", description: "Whether the editor search results will loop", @@ -1570,19 +1861,32 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("File Finder"), + // todo: null by default SettingsPageItem::SettingItem(SettingItem { - title: "Use Smartcase Search", - description: "Use smartcase (i.e., case-sensitive) search", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.editor.use_smartcase_search, - pick_mut: |settings_content| { - &mut settings_content.editor.use_smartcase_search - }, - }), + title: "Include Ignored in Search", + description: "Use gitignored files when searching", + field: Box::new( + SettingField { + pick: |settings_content| { + if let Some(file_finder) = &settings_content.file_finder { + &file_finder.include_ignored + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .file_finder + .get_or_insert_default() + .include_ignored + }, + } + .unimplemented(), + ), metadata: None, files: USER, }), - SettingsPageItem::SectionHeader("File Management"), SettingsPageItem::SettingItem(SettingItem { title: "File Icons", description: "Show file icons in the file finder", @@ -1625,30 +1929,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), - SettingsPageItem::SettingItem(SettingItem { - title: "Restore File State", - description: "Restore previous file state when reopening", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.restore_on_file_reopen, - pick_mut: |settings_content| { - &mut settings_content.workspace.restore_on_file_reopen - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Close on File Delete", - description: "Automatically close files that have been deleted", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.workspace.close_on_file_delete, - pick_mut: |settings_content| { - &mut settings_content.workspace.close_on_file_delete - }, - }), - metadata: None, - files: USER, - }), SettingsPageItem::SettingItem(SettingItem { title: "Skip Focus For Active In Search", description: "Whether the file finder should skip focus for the active file in search results", @@ -1692,10 +1972,68 @@ pub(crate) fn settings_data(cx: &App) -> Vec { files: USER, }), SettingsPageItem::SectionHeader("File Scan"), + SettingsPageItem::SettingItem(SettingItem { + title: "File Scan Exclusions", + description: "Files or globs of files that will be excluded by Zed entirely. They will be skipped during file scans, file searches, and not be displayed in the project file tree. Takes precedence over \"File Scan Inclusions\"", + field: Box::new( + SettingField { + pick: |settings_content| { + &settings_content.project.worktree.file_scan_exclusions + }, + pick_mut: |settings_content| { + &mut settings_content.project.worktree.file_scan_exclusions + }, + } + .unimplemented(), + ), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "File Scan Inclusions", + description: "Files or globs of files that will be included by Zed, even when ignored by git. This is useful for files that are not tracked by git, but are still important to your project. Note that globs that are overly broad can slow down Zed's file scanning. \"File Scan Exclusions\" takes precedence over these inclusions", + field: Box::new( + SettingField { + pick: |settings_content| { + &settings_content.project.worktree.file_scan_exclusions + }, + pick_mut: |settings_content| { + &mut settings_content.project.worktree.file_scan_exclusions + }, + } + .unimplemented(), + ), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Restore File State", + description: "Restore previous file state when reopening", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.restore_on_file_reopen, + pick_mut: |settings_content| { + &mut settings_content.workspace.restore_on_file_reopen + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Close on File Delete", + description: "Automatically close files that have been deleted", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.close_on_file_delete, + pick_mut: |settings_content| { + &mut settings_content.workspace.close_on_file_delete + }, + }), + metadata: None, + files: USER, + }), ], }, SettingsPage { - title: "Workbench & Window", + title: "Window & Layout", items: vec![ SettingsPageItem::SectionHeader("Status Bar"), SettingsPageItem::SettingItem(SettingItem { @@ -2004,24 +2342,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), - SettingsPageItem::SettingItem(SettingItem { - title: "Editor Tabs", - description: "Show the tab bar in the editor", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(tab_bar) = &settings_content.tab_bar { - &tab_bar.show - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content.tab_bar.get_or_insert_default().show - }, - }), - metadata: None, - files: USER, - }), SettingsPageItem::SettingItem(SettingItem { title: "Show Git Status In Tabs", description: "Show the Git file status on a tab item", @@ -2240,6 +2560,167 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Layout"), + SettingsPageItem::SettingItem(SettingItem { + title: "Bottom Dock Layout", + description: "Layout mode for the bottom dock", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.bottom_dock_layout, + pick_mut: |settings_content| { + &mut settings_content.workspace.bottom_dock_layout + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "Centered Layout Left Padding", + description: "Left padding for centered layout", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(centered_layout) = + &settings_content.workspace.centered_layout + { + ¢ered_layout.left_padding + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .workspace + .centered_layout + .get_or_insert_default() + .left_padding + }, + }), + metadata: None, + }), + SettingsPageItem::SettingItem(SettingItem { + files: USER, + title: "Centered Layout Right Padding", + description: "Right padding for centered layout", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(centered_layout) = + &settings_content.workspace.centered_layout + { + ¢ered_layout.right_padding + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .workspace + .centered_layout + .get_or_insert_default() + .right_padding + }, + }), + metadata: None, + }), + SettingsPageItem::SectionHeader("Window"), + // todo(settings_ui): Should we filter by platform? + SettingsPageItem::SettingItem(SettingItem { + title: "Use System Window Tabs", + description: "(macOS only) Whether to allow windows to tab together", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.use_system_window_tabs, + pick_mut: |settings_content| { + &mut settings_content.workspace.use_system_window_tabs + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("Pane Modifiers"), + SettingsPageItem::SettingItem(SettingItem { + title: "Inactive Opacity", + description: "Opacity of inactive panels (0.0 - 1.0)", + field: Box::new(SettingField { + pick: |settings_content| match settings_content + .workspace + .active_pane_modifiers + .as_ref() + { + Some(modifiers) => &modifiers.inactive_opacity, + None => &None, + }, + pick_mut: |settings_content| { + &mut settings_content + .workspace + .active_pane_modifiers + .get_or_insert_default() + .inactive_opacity + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Border Size", + description: "Size of the border surrounding the active pane", + field: Box::new(SettingField { + pick: |settings_content| match settings_content + .workspace + .active_pane_modifiers + .as_ref() + { + Some(modifiers) => &modifiers.border_size, + None => &None, + }, + pick_mut: |settings_content| { + &mut settings_content + .workspace + .active_pane_modifiers + .get_or_insert_default() + .border_size + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Zoomed Padding", + description: "Show padding for zoomed panes", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.workspace.zoomed_padding, + pick_mut: |settings_content| &mut settings_content.workspace.zoomed_padding, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SectionHeader("Pane Split Direction"), + SettingsPageItem::SettingItem(SettingItem { + title: "Vertical Split Direction", + description: "Direction to split vertically", + field: Box::new(SettingField { + pick: |settings_content| { + &settings_content.workspace.pane_split_direction_vertical + }, + pick_mut: |settings_content| { + &mut settings_content.workspace.pane_split_direction_vertical + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Horizontal Split Direction", + description: "Direction to split horizontally", + field: Box::new(SettingField { + pick: |settings_content| { + &settings_content.workspace.pane_split_direction_horizontal + }, + pick_mut: |settings_content| { + &mut settings_content.workspace.pane_split_direction_horizontal + }, + }), + metadata: None, + files: USER, + }), ], }, SettingsPage { @@ -2852,50 +3333,134 @@ pub(crate) fn settings_data(cx: &App) -> Vec { ), metadata: None, }), - SettingsPageItem::SectionHeader("Git Panel"), + SettingsPageItem::SectionHeader("Git Panel"), + SettingsPageItem::SettingItem(SettingItem { + title: "Git Panel Button", + description: "Show the Git panel button in the status bar", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(git_panel) = &settings_content.git_panel { + &git_panel.button + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content.git_panel.get_or_insert_default().button + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Git Panel Dock", + description: "Where to dock the Git panel", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(git_panel) = &settings_content.git_panel { + &git_panel.dock + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content.git_panel.get_or_insert_default().dock + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Git Panel Default Width", + description: "Default width of the Git panel in pixels", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(git_panel) = &settings_content.git_panel { + &git_panel.default_width + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .git_panel + .get_or_insert_default() + .default_width + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Git Panel Status Style", + description: "How entry statuses are displayed", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(git_panel) = &settings_content.git_panel { + &git_panel.status_style + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content + .git_panel + .get_or_insert_default() + .status_style + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SettingItem(SettingItem { - title: "Git Panel Button", - description: "Show the Git panel button in the status bar", + title: "Fallback Branch Name", + description: "Default branch name will be when init.defaultBranch is not set in git", field: Box::new(SettingField { pick: |settings_content| { if let Some(git_panel) = &settings_content.git_panel { - &git_panel.button + &git_panel.fallback_branch_name } else { &None } }, pick_mut: |settings_content| { - &mut settings_content.git_panel.get_or_insert_default().button + &mut settings_content + .git_panel + .get_or_insert_default() + .fallback_branch_name }, }), metadata: None, files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Git Panel Dock", - description: "Where to dock the Git panel", + title: "Sort By Path", + description: "Enable to sort entries in the panel by path, disable to sort by status", field: Box::new(SettingField { pick: |settings_content| { if let Some(git_panel) = &settings_content.git_panel { - &git_panel.dock + &git_panel.sort_by_path } else { &None } }, pick_mut: |settings_content| { - &mut settings_content.git_panel.get_or_insert_default().dock + &mut settings_content + .git_panel + .get_or_insert_default() + .sort_by_path }, }), metadata: None, files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Git Panel Default Width", - description: "Default width of the Git panel in pixels", + title: "Collapse Untracked Diff", + description: "Whether to collapse untracked files in the diff panel", field: Box::new(SettingField { pick: |settings_content| { if let Some(git_panel) = &settings_content.git_panel { - &git_panel.default_width + &git_panel.collapse_untracked_diff } else { &None } @@ -2904,7 +3469,30 @@ pub(crate) fn settings_data(cx: &App) -> Vec { &mut settings_content .git_panel .get_or_insert_default() - .default_width + .collapse_untracked_diff + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Scroll Bar", + description: "How and when the scrollbar should be displayed", + field: Box::new(SettingField { + pick: |settings_content| match &settings_content.git_panel { + Some(settings::GitPanelSettingsContent { + scrollbar: Some(scrollbar), + .. + }) => &scrollbar.show, + _ => &None, + }, + pick_mut: |settings_content| { + &mut settings_content + .git_panel + .get_or_insert_default() + .scrollbar + .get_or_insert_default() + .show }, }), metadata: None, @@ -3764,9 +4352,9 @@ pub(crate) fn settings_data(cx: &App) -> Vec { SettingsPage { title: "Version Control", items: vec![ - SettingsPageItem::SectionHeader("Git"), + SettingsPageItem::SectionHeader("Git Gutter"), SettingsPageItem::SettingItem(SettingItem { - title: "Git Gutter", + title: "Visibilility", description: "Control whether git status is shown in the editor's gutter", field: Box::new(SettingField { pick: |settings_content| { @@ -3785,7 +4373,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { }), // todo(settings_ui): Figure out the right default for this value in default.json SettingsPageItem::SettingItem(SettingItem { - title: "Gutter Debounce", + title: "Debounce", description: "Debounce threshold in milliseconds after which changes are reflected in the git gutter", field: Box::new(SettingField { pick: |settings_content| { @@ -3802,8 +4390,9 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Inline Git Blame"), SettingsPageItem::SettingItem(SettingItem { - title: "Inline Git Blame", + title: "Enabled", description: "Whether or not to show git blame data inline in the currently focused line", field: Box::new(SettingField { pick: |settings_content| { @@ -3830,7 +4419,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Inline Git Blame Delay", + title: "Delay", description: "The delay after which the inline blame information is shown", field: Box::new(SettingField { pick: |settings_content| { @@ -3857,7 +4446,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Inline Git Blame Padding", + title: "Padding", description: "Padding between the end of the source line and the start of the inline blame in columns", field: Box::new(SettingField { pick: |settings_content| { @@ -3884,19 +4473,15 @@ pub(crate) fn settings_data(cx: &App) -> Vec { files: USER, }), SettingsPageItem::SettingItem(SettingItem { - title: "Inline Git Blame Min Column", - description: "The minimum column number to show the inline blame information at", + title: "Minimum Column", + description: "The minimum column number at which to show the inline blame information", field: Box::new(SettingField { - pick: |settings_content| { - if let Some(git) = &settings_content.git { - if let Some(inline_blame) = &git.inline_blame { - &inline_blame.min_column - } else { - &None - } - } else { - &None - } + pick: |settings_content| match &settings_content.git { + Some(settings::GitSettings { + inline_blame: Some(inline_blame), + .. + }) => &inline_blame.min_column, + _ => &None, }, pick_mut: |settings_content| { &mut settings_content @@ -3937,6 +4522,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Git Blame View"), SettingsPageItem::SettingItem(SettingItem { title: "Show Avatar", description: "Show the avatar of the author of the commit", @@ -3964,8 +4550,9 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Branch Picker"), SettingsPageItem::SettingItem(SettingItem { - title: "Show Author Name In Branch Picker", + title: "Show Author Name", description: "Show author name as part of the commit information in branch picker", field: Box::new(SettingField { pick: |settings_content| { @@ -3991,6 +4578,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SectionHeader("Git Hunks"), SettingsPageItem::SettingItem(SettingItem { title: "Hunk Style", description: "How git hunks are displayed visually in the editor", @@ -4011,210 +4599,6 @@ pub(crate) fn settings_data(cx: &App) -> Vec { }), ], }, - SettingsPage { - title: "Diagnostics & Errors", - items: vec![ - SettingsPageItem::SectionHeader("Filtering"), - SettingsPageItem::SettingItem(SettingItem { - title: "Max Severity", - description: "Which level to use to filter out diagnostics displayed in the editor", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.editor.diagnostics_max_severity, - pick_mut: |settings_content| { - &mut settings_content.editor.diagnostics_max_severity - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Include Warnings", - description: "Whether to show warnings or not by default", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - &diagnostics.include_warnings - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .include_warnings - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SectionHeader("Inline"), - SettingsPageItem::SettingItem(SettingItem { - title: "Inline Diagnostics Enabled", - description: "Whether to show diagnostics inline or not", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(inline) = &diagnostics.inline { - &inline.enabled - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .inline - .get_or_insert_default() - .enabled - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Inline Update Debounce", - description: "The delay in milliseconds to show inline diagnostics after the last diagnostic update", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(inline) = &diagnostics.inline { - &inline.update_debounce_ms - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .inline - .get_or_insert_default() - .update_debounce_ms - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Inline Padding", - description: "The amount of padding between the end of the source line and the start of the inline diagnostic", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(inline) = &diagnostics.inline { - &inline.padding - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .inline - .get_or_insert_default() - .padding - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SettingItem(SettingItem { - title: "Inline Min Column", - description: "The minimum column to display inline diagnostics", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(inline) = &diagnostics.inline { - &inline.min_column - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .inline - .get_or_insert_default() - .min_column - }, - }), - metadata: None, - files: USER, - }), - SettingsPageItem::SectionHeader("Performance"), - SettingsPageItem::SettingItem(SettingItem { - title: "LSP Pull Diagnostics Enabled", - description: "Whether to pull for language server-powered diagnostics or not", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(lsp_pull) = &diagnostics.lsp_pull_diagnostics { - &lsp_pull.enabled - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .lsp_pull_diagnostics - .get_or_insert_default() - .enabled - }, - }), - metadata: None, - files: USER, - }), - // todo(settings_ui): Needs unit - SettingsPageItem::SettingItem(SettingItem { - title: "LSP Pull Debounce", - description: "Minimum time to wait before pulling diagnostics from the language server(s)", - field: Box::new(SettingField { - pick: |settings_content| { - if let Some(diagnostics) = &settings_content.diagnostics { - if let Some(lsp_pull) = &diagnostics.lsp_pull_diagnostics { - &lsp_pull.debounce_ms - } else { - &None - } - } else { - &None - } - }, - pick_mut: |settings_content| { - &mut settings_content - .diagnostics - .get_or_insert_default() - .lsp_pull_diagnostics - .get_or_insert_default() - .debounce_ms - }, - }), - metadata: None, - files: USER, - }), - ], - }, SettingsPage { title: "Collaboration", items: vec![ @@ -4564,7 +4948,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { ], }, SettingsPage { - title: "System & Network", + title: "Network", items: vec![ SettingsPageItem::SectionHeader("Network"), // todo(settings_ui): Proxy needs a default @@ -4580,6 +4964,7 @@ pub(crate) fn settings_data(cx: &App) -> Vec { ), metadata: Some(Box::new(SettingsFieldMetadata { placeholder: Some("socks5h://localhost:10808"), + ..Default::default() })), files: USER, }), @@ -4592,20 +4977,10 @@ pub(crate) fn settings_data(cx: &App) -> Vec { }), metadata: Some(Box::new(SettingsFieldMetadata { placeholder: Some("https://zed.dev"), + ..Default::default() })), files: USER, }), - SettingsPageItem::SectionHeader("System"), - SettingsPageItem::SettingItem(SettingItem { - title: "Auto Update", - description: "Whether or not to automatically check for updates", - field: Box::new(SettingField { - pick: |settings_content| &settings_content.auto_update, - pick_mut: |settings_content| &mut settings_content.auto_update, - }), - metadata: None, - files: USER, - }), ], }, ] @@ -4654,7 +5029,7 @@ fn language_settings_field_mut( } fn language_settings_data() -> Vec { - vec![ + let mut items = vec![ SettingsPageItem::SectionHeader("Indentation"), SettingsPageItem::SettingItem(SettingItem { title: "Tab Size", @@ -5504,6 +5879,20 @@ fn language_settings_data() -> Vec { metadata: None, files: USER | LOCAL, }), + ]; + if current_language().is_none() { + items.push(SettingsPageItem::SettingItem(SettingItem { + title: "LSP Document Colors", + description: "How to render LSP color previews in the editor", + field: Box::new(SettingField { + pick: |settings_content| &settings_content.editor.lsp_document_colors, + pick_mut: |settings_content| &mut settings_content.editor.lsp_document_colors, + }), + metadata: None, + files: USER, + })) + } + items.extend([ SettingsPageItem::SectionHeader("Tasks"), SettingsPageItem::SettingItem(SettingItem { title: "Enabled", @@ -5622,7 +6011,63 @@ fn language_settings_data() -> Vec { metadata: None, files: USER | LOCAL, }), - ] + ]); + + if current_language().is_none() { + items.extend([ + SettingsPageItem::SettingItem(SettingItem { + title: "Image Viewer", + description: "The unit for image file sizes", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(image_viewer) = settings_content.image_viewer.as_ref() { + &image_viewer.unit + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content.image_viewer.get_or_insert_default().unit + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Auto Replace Emoji Shortcode", + description: "Whether to automatically replace emoji shortcodes with emoji characters", + field: Box::new(SettingField { + pick: |settings_content| { + if let Some(message_editor) = settings_content.message_editor.as_ref() { + &message_editor.auto_replace_emoji_shortcode + } else { + &None + } + }, + pick_mut: |settings_content| { + &mut settings_content.message_editor.get_or_insert_default().auto_replace_emoji_shortcode + }, + }), + metadata: None, + files: USER, + }), + SettingsPageItem::SettingItem(SettingItem { + title: "Drop Size Target", + description: "Relative size of the drop target in the editor that will open dropped file as a split pane", + field: Box::new(SettingField { + pick: |settings_content| { + &settings_content.workspace.drop_target_size + }, + pick_mut: |settings_content| { + &mut settings_content.workspace.drop_target_size + }, + }), + metadata: None, + files: USER, + }), + ]); + } + items } /// LanguageSettings items that should be included in the "Languages & Tools" page diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 8dba6ff9886cb4acb14437955a0513fabbf84d87..039b47dfd97023bc43b606b322e12ffc7226e80e 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -1,4 +1,3 @@ -//! # settings_ui mod components; mod page_data; @@ -16,10 +15,7 @@ use heck::ToTitleCase as _; use project::WorktreeId; use schemars::JsonSchema; use serde::Deserialize; -use settings::{ - BottomDockLayout, CloseWindowWhenNoItems, CodeFade, CursorShape, OnLastWindowClosed, - RestoreOnStartupBehavior, SaturatingBool, SettingsContent, SettingsStore, -}; +use settings::{SettingsContent, SettingsStore}; use std::{ any::{Any, TypeId, type_name}, cell::RefCell, @@ -330,8 +326,10 @@ impl Focusable for NonFocusableHandle { } } +#[derive(Default)] struct SettingsFieldMetadata { placeholder: Option<&'static str>, + should_do_titlecase: Option, } pub struct SettingsUiFeatureFlag; @@ -369,12 +367,12 @@ fn init_renderers(cx: &mut App) { }) .add_basic_renderer::(render_toggle_button) .add_basic_renderer::(render_text_field) - .add_basic_renderer::(render_toggle_button) - .add_basic_renderer::(render_dropdown) - .add_basic_renderer::(render_dropdown) - .add_basic_renderer::(render_dropdown) - .add_basic_renderer::(render_dropdown) - .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_toggle_button) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_font_picker) // todo(settings_ui): This needs custom ui // .add_renderer::(|settings_field, file, _, window, cx| { @@ -421,7 +419,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_number_field) .add_basic_renderer::>(render_number_field) .add_basic_renderer::(render_number_field) - .add_basic_renderer::(render_number_field) + .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_dropdown) @@ -431,7 +429,15 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) - .add_basic_renderer::(render_dropdown); + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) + // please semicolon stay on next line + ; // .add_renderer::(|settings_field, file, _, window, cx| { // render_dropdown(*settings_field, file, window, cx) // }); @@ -1838,7 +1844,7 @@ impl SettingsWindow { return; }; self.page_scroll_handle - .scroll_to_top_of_item(selected_item_index); + .scroll_to_top_of_item(selected_item_index + 1); if focus_content { self.focus_content_element(entry_item_index, window, cx); @@ -2531,7 +2537,7 @@ fn render_number_field( fn render_dropdown( field: SettingField, file: SettingsUiFile, - _metadata: Option<&SettingsFieldMetadata>, + metadata: Option<&SettingsFieldMetadata>, window: &mut Window, cx: &mut App, ) -> AnyElement @@ -2540,6 +2546,9 @@ where { let variants = || -> &'static [T] { ::VARIANTS }; let labels = || -> &'static [&'static str] { ::VARIANTS }; + let should_do_titlecase = metadata + .and_then(|metadata| metadata.should_do_titlecase) + .unwrap_or(true); let (_, current_value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); @@ -2550,12 +2559,20 @@ where DropdownMenu::new( "dropdown", - current_value_label.to_title_case(), + if should_do_titlecase { + current_value_label.to_title_case() + } else { + current_value_label.to_string() + }, ContextMenu::build(window, cx, move |mut menu, _, _| { for (&value, &label) in std::iter::zip(variants(), labels()) { let file = file.clone(); menu = menu.toggleable_entry( - label.to_title_case(), + if should_do_titlecase { + label.to_title_case() + } else { + label.to_string() + }, value == current_value, IconPosition::End, None,