@@ -19,4803 +19,5223 @@ const DEFAULT_SHARED_STRING: SharedString = SharedString::new_static("");
/// to avoid the "NO DEFAULT" case.
const DEFAULT_EMPTY_SHARED_STRING: Option<&SharedString> = Some(&DEFAULT_SHARED_STRING);
+macro_rules! concat_sections {
+ (@vec, $($arr:expr),+ $(,)?) => {{
+ let total_len = 0_usize $(+ $arr.len())+;
+ let mut out = Vec::with_capacity(total_len);
+
+ $(
+ out.extend($arr);
+ )+
+
+ out
+ }};
+
+ ($($arr:expr),+ $(,)?) => {{
+ let total_len = 0_usize $(+ $arr.len())+;
+
+ let mut out: Box<[std::mem::MaybeUninit<_>]> = Box::new_uninit_slice(total_len);
+
+ let mut index = 0usize;
+ $(
+ let array = $arr;
+ for item in array {
+ out[index].write(item);
+ index += 1;
+ }
+ )+
+
+ debug_assert_eq!(index, total_len);
+
+ // SAFETY: we wrote exactly `total_len` elements.
+ unsafe { out.assume_init() }
+ }};
+}
+
pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
vec![
- SettingsPage {
- title: "General",
- items: vec![
- SettingsPageItem::SectionHeader("General Settings"),
- SettingsPageItem::SettingItem(SettingItem {
- files: PROJECT,
- title: "Project Name",
- description: "The displayed name of this project. If left empty, the root directory name will be displayed.",
- field: Box::new(
- SettingField {
- json_path: Some("project_name"),
- pick: |settings_content| {
- settings_content.project.worktree.project_name.as_ref().or(DEFAULT_EMPTY_STRING)
- },
- write: |settings_content, value| {
- settings_content.project.worktree.project_name = value.filter(|name| !name.is_empty());
- },
- }
- ),
- metadata: Some(Box::new(SettingsFieldMetadata { placeholder: Some("Project Name"), ..Default::default() })),
+ general_page(),
+ appearance_page(),
+ keymap_page(),
+ editor_page(),
+ languages_and_tools_page(cx),
+ search_and_files_page(),
+ window_and_layout_page(),
+ panels_page(),
+ debugger_page(),
+ terminal_page(),
+ version_control_page(),
+ collaboration_page(),
+ ai_page(),
+ network_page(),
+ ]
+}
+
+fn general_page() -> SettingsPage {
+ fn general_settings_section() -> [SettingsPageItem; 8] {
+ [
+ SettingsPageItem::SectionHeader("General Settings"),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: PROJECT,
+ title: "Project Name",
+ description: "The displayed name of this project. If left empty, the root directory name will be displayed.",
+ field: Box::new(SettingField {
+ json_path: Some("project_name"),
+ pick: |settings_content| {
+ settings_content
+ .project
+ .worktree
+ .project_name
+ .as_ref()
+ .or(DEFAULT_EMPTY_STRING)
+ },
+ write: |settings_content, value| {
+ settings_content.project.worktree.project_name =
+ value.filter(|name| !name.is_empty());
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "When Closing With No Tabs",
- description: "What to do when using the 'close active item' action with no tabs.",
- field: Box::new(SettingField {
- json_path: Some("when_closing_with_no_tabs"),
- pick: |settings_content| {
- settings_content
- .workspace
- .when_closing_with_no_tabs
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.when_closing_with_no_tabs = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: Some(Box::new(SettingsFieldMetadata {
+ placeholder: Some("Project Name"),
+ ..Default::default()
+ })),
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "When Closing With No Tabs",
+ description: "What to do when using the 'close active item' action with no tabs.",
+ field: Box::new(SettingField {
+ json_path: Some("when_closing_with_no_tabs"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .when_closing_with_no_tabs
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.when_closing_with_no_tabs = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "On Last Window Closed",
- description: "What to do when the last window is closed.",
- field: Box::new(SettingField {
- json_path: Some("on_last_window_closed"),
- pick: |settings_content| {
- settings_content.workspace.on_last_window_closed.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.on_last_window_closed = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Last Window Closed",
+ description: "What to do when the last window is closed.",
+ field: Box::new(SettingField {
+ json_path: Some("on_last_window_closed"),
+ pick: |settings_content| {
+ settings_content.workspace.on_last_window_closed.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.on_last_window_closed = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Use System Path Prompts",
- description: "Use native OS dialogs for 'Open' and 'Save As'.",
- field: Box::new(SettingField {
- json_path: Some("use_system_path_prompts"),
- pick: |settings_content| {
- settings_content.workspace.use_system_path_prompts.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.use_system_path_prompts = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use System Path Prompts",
+ description: "Use native OS dialogs for 'Open' and 'Save As'.",
+ field: Box::new(SettingField {
+ json_path: Some("use_system_path_prompts"),
+ pick: |settings_content| {
+ settings_content.workspace.use_system_path_prompts.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.use_system_path_prompts = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Use System Prompts",
- description: "Use native OS dialogs for confirmations.",
- field: Box::new(SettingField {
- json_path: Some("use_system_prompts"),
- pick: |settings_content| {
- settings_content.workspace.use_system_prompts.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.use_system_prompts = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use System Prompts",
+ description: "Use native OS dialogs for confirmations.",
+ field: Box::new(SettingField {
+ json_path: Some("use_system_prompts"),
+ pick: |settings_content| settings_content.workspace.use_system_prompts.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.use_system_prompts = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Redact Private Values",
- description: "Hide the values of variables in private files.",
- field: Box::new(SettingField {
- json_path: Some("redact_private_values"),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Redact Private Values",
+ description: "Hide the values of variables in private files.",
+ field: Box::new(SettingField {
+ json_path: Some("redact_private_values"),
+ pick: |settings_content| settings_content.editor.redact_private_values.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.redact_private_values = value;
+ },
+ }),
+ 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 {
+ json_path: Some("worktree.private_files"),
pick: |settings_content| {
- settings_content.editor.redact_private_values.as_ref()
+ settings_content.project.worktree.private_files.as_ref()
},
write: |settings_content, value| {
- settings_content.editor.redact_private_values = value;
+ settings_content.project.worktree.private_files = value;
},
- }),
- metadata: None,
- files: USER,
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+ fn security_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Security"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Trust All Projects By Default",
+ description: "When opening Zed, avoid Restricted Mode by auto-trusting all projects, enabling use of all features without having to give permission to each new project.",
+ field: Box::new(SettingField {
+ json_path: Some("session.trust_all_projects"),
+ pick: |settings_content| {
+ settings_content
+ .session
+ .as_ref()
+ .and_then(|session| session.trust_all_worktrees.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .session
+ .get_or_insert_default()
+ .trust_all_worktrees = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Private Files",
- description: "Globs to match against file paths to determine if a file is private.",
- field: Box::new(
- SettingField {
- json_path: Some("worktree.private_files"),
- pick: |settings_content| {
- settings_content.project.worktree.private_files.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.worktree.private_files = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn workspace_restoration_section() -> [SettingsPageItem; 3] {
+ [
+ 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 {
+ json_path: Some("session.restore_unsaved_buffers"),
+ pick: |settings_content| {
+ settings_content
+ .session
+ .as_ref()
+ .and_then(|session| session.restore_unsaved_buffers.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .session
+ .get_or_insert_default()
+ .restore_unsaved_buffers = value;
+ },
}),
- SettingsPageItem::SectionHeader("Security"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Trust All Projects By Default",
- description: "When opening Zed, avoid Restricted Mode by auto-trusting all projects, enabling use of all features without having to give permission to each new project.",
- field: Box::new(SettingField {
- json_path: Some("session.trust_all_projects"),
- pick: |settings_content| {
- settings_content
- .session
- .as_ref()
- .and_then(|session| session.trust_all_worktrees.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .session
- .get_or_insert_default()
- .trust_all_worktrees = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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 {
+ json_path: Some("restore_on_startup"),
+ pick: |settings_content| settings_content.workspace.restore_on_startup.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.restore_on_startup = value;
+ },
}),
- 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 {
- json_path: Some("session.restore_unsaved_buffers"),
- pick: |settings_content| {
- settings_content
- .session
- .as_ref()
- .and_then(|session| session.restore_unsaved_buffers.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .session
- .get_or_insert_default()
- .restore_unsaved_buffers = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn scoped_settings_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Scoped Settings"),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Preview Channel",
+ description: "Which settings should be activated only in Preview build of Zed.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("preview_channel_settings"),
+ pick: |settings_content| Some(settings_content),
+ write: |_settings_content, _value| {},
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Settings Profiles",
+ description: "Any number of settings profiles that are temporarily applied on top of your existing user settings.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("settings_profiles"),
+ pick: |settings_content| Some(settings_content),
+ write: |_settings_content, _value| {},
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ ]
+ }
+
+ fn privacy_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Privacy"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Telemetry Diagnostics",
+ description: "Send debug information like crash reports.",
+ field: Box::new(SettingField {
+ json_path: Some("telemetry.diagnostics"),
+ pick: |settings_content| {
+ settings_content
+ .telemetry
+ .as_ref()
+ .and_then(|telemetry| telemetry.diagnostics.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .telemetry
+ .get_or_insert_default()
+ .diagnostics = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Restore On Startup",
- description: "What to restore from the previous session when opening Zed.",
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Telemetry Metrics",
+ description: "Send anonymized usage data like what languages you're using Zed with.",
+ field: Box::new(SettingField {
+ json_path: Some("telemetry.metrics"),
+ pick: |settings_content| {
+ settings_content
+ .telemetry
+ .as_ref()
+ .and_then(|telemetry| telemetry.metrics.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content.telemetry.get_or_insert_default().metrics = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn auto_update_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Auto Update"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Update",
+ description: "Whether or not to automatically check for updates.",
+ field: Box::new(SettingField {
+ json_path: Some("auto_update"),
+ pick: |settings_content| settings_content.auto_update.as_ref(),
+ write: |settings_content, value| {
+ settings_content.auto_update = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ SettingsPage {
+ title: "General",
+ items: concat_sections!(
+ general_settings_section(),
+ security_section(),
+ workspace_restoration_section(),
+ scoped_settings_section(),
+ privacy_section(),
+ auto_update_section(),
+ ),
+ }
+}
+
+fn appearance_page() -> SettingsPage {
+ fn theme_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Theme"),
+ SettingsPageItem::DynamicItem(DynamicItem {
+ discriminant: SettingItem {
+ files: USER,
+ title: "Theme Mode",
+ description: "Choose a static, fixed theme or dynamically select themes based on appearance and light/dark modes.",
field: Box::new(SettingField {
- json_path: Some("restore_on_startup"),
+ json_path: Some("theme$"),
pick: |settings_content| {
- settings_content.workspace.restore_on_startup.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.restore_on_startup = value;
+ Some(&dynamic_variants::<settings::ThemeSelection>()[
+ settings_content
+ .theme
+ .theme
+ .as_ref()?
+ .discriminant() as usize])
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ settings_content.theme.theme = None;
+ return;
+ };
+ let settings_value = settings_content.theme.theme.get_or_insert_default();
+ *settings_value = match value {
+ settings::ThemeSelectionDiscriminants::Static => {
+ let name = match settings_value {
+ settings::ThemeSelection::Static(_) => return,
+ settings::ThemeSelection::Dynamic { mode, light, dark } => {
+ match mode {
+ theme::ThemeAppearanceMode::Light => light.clone(),
+ theme::ThemeAppearanceMode::Dark => dark.clone(),
+ theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
+ }
+ },
+ };
+ settings::ThemeSelection::Static(name)
+ },
+ settings::ThemeSelectionDiscriminants::Dynamic => {
+ let static_name = match settings_value {
+ settings::ThemeSelection::Static(theme_name) => theme_name.clone(),
+ settings::ThemeSelection::Dynamic {..} => return,
+ };
+
+ settings::ThemeSelection::Dynamic {
+ mode: settings::ThemeAppearanceMode::System,
+ light: static_name.clone(),
+ dark: static_name,
+ }
+ },
+ };
},
}),
metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Scoped Settings"),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Preview Channel",
- description: "Which settings should be activated only in Preview build of Zed.",
- field: Box::new(
- SettingField {
- json_path: Some("preview_channel_settings"),
- pick: |settings_content| {
- Some(settings_content)
+ },
+ pick_discriminant: |settings_content| {
+ Some(settings_content.theme.theme.as_ref()?.discriminant() as usize)
+ },
+ fields: dynamic_variants::<settings::ThemeSelection>().into_iter().map(|variant| {
+ match variant {
+ settings::ThemeSelectionDiscriminants::Static => vec![
+ SettingItem {
+ files: USER,
+ title: "Theme Name",
+ description: "The name of your selected theme.",
+ field: Box::new(SettingField {
+ json_path: Some("theme"),
+ pick: |settings_content| {
+ match settings_content.theme.theme.as_ref() {
+ Some(settings::ThemeSelection::Static(name)) => Some(name),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .theme.get_or_insert_default() {
+ settings::ThemeSelection::Static(theme_name) => *theme_name = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
+ }
+ ],
+ settings::ThemeSelectionDiscriminants::Dynamic => vec![
+ SettingItem {
+ files: USER,
+ title: "Mode",
+ description: "Choose whether to use the selected light or dark theme or to follow your OS appearance configuration.",
+ field: Box::new(SettingField {
+ json_path: Some("theme.mode"),
+ pick: |settings_content| {
+ match settings_content.theme.theme.as_ref() {
+ Some(settings::ThemeSelection::Dynamic { mode, ..}) => Some(mode),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .theme.get_or_insert_default() {
+ settings::ThemeSelection::Dynamic{ mode, ..} => *mode = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
},
- write: |_settings_content, _value| {
-
+ SettingItem {
+ files: USER,
+ title: "Light Theme",
+ description: "The theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
+ field: Box::new(SettingField {
+ json_path: Some("theme.light"),
+ pick: |settings_content| {
+ match settings_content.theme.theme.as_ref() {
+ Some(settings::ThemeSelection::Dynamic { light, ..}) => Some(light),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .theme.get_or_insert_default() {
+ settings::ThemeSelection::Dynamic{ light, ..} => *light = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
},
- }
- .unimplemented(),
- ),
- metadata: None,
- }),
- SettingsPageItem::SettingItem(SettingItem {
+ SettingItem {
+ files: USER,
+ title: "Dark Theme",
+ description: "The theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
+ field: Box::new(SettingField {
+ json_path: Some("theme.dark"),
+ pick: |settings_content| {
+ match settings_content.theme.theme.as_ref() {
+ Some(settings::ThemeSelection::Dynamic { dark, ..}) => Some(dark),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .theme.get_or_insert_default() {
+ settings::ThemeSelection::Dynamic{ dark, ..} => *dark = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
+ }
+ ],
+ }
+ }).collect(),
+ }),
+ SettingsPageItem::DynamicItem(DynamicItem {
+ discriminant: SettingItem {
files: USER,
- title: "Settings Profiles",
- description: "Any number of settings profiles that are temporarily applied on top of your existing user settings.",
- field: Box::new(
- SettingField {
- json_path: Some("settings_profiles"),
- pick: |settings_content| {
- Some(settings_content)
+ title: "Icon Theme",
+ description: "The custom set of icons Zed will associate with files and directories.",
+ field: Box::new(SettingField {
+ json_path: Some("icon_theme$"),
+ pick: |settings_content| {
+ Some(&dynamic_variants::<settings::IconThemeSelection>()[
+ settings_content
+ .theme
+ .icon_theme
+ .as_ref()?
+ .discriminant() as usize])
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ settings_content.theme.icon_theme = None;
+ return;
+ };
+ let settings_value = settings_content.theme.icon_theme.get_or_insert_with(|| {
+ settings::IconThemeSelection::Static(settings::IconThemeName(theme::default_icon_theme().name.clone().into()))
+ });
+ *settings_value = match value {
+ settings::IconThemeSelectionDiscriminants::Static => {
+ let name = match settings_value {
+ settings::IconThemeSelection::Static(_) => return,
+ settings::IconThemeSelection::Dynamic { mode, light, dark } => {
+ match mode {
+ theme::ThemeAppearanceMode::Light => light.clone(),
+ theme::ThemeAppearanceMode::Dark => dark.clone(),
+ theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
+ }
+ },
+ };
+ settings::IconThemeSelection::Static(name)
+ },
+ settings::IconThemeSelectionDiscriminants::Dynamic => {
+ let static_name = match settings_value {
+ settings::IconThemeSelection::Static(theme_name) => theme_name.clone(),
+ settings::IconThemeSelection::Dynamic {..} => return,
+ };
+
+ settings::IconThemeSelection::Dynamic {
+ mode: settings::ThemeAppearanceMode::System,
+ light: static_name.clone(),
+ dark: static_name,
+ }
+ },
+ };
+ },
+ }),
+ metadata: None,
+ },
+ pick_discriminant: |settings_content| {
+ Some(settings_content.theme.icon_theme.as_ref()?.discriminant() as usize)
+ },
+ fields: dynamic_variants::<settings::IconThemeSelection>().into_iter().map(|variant| {
+ match variant {
+ settings::IconThemeSelectionDiscriminants::Static => vec![
+ SettingItem {
+ files: USER,
+ title: "Icon Theme Name",
+ description: "The name of your selected icon theme.",
+ field: Box::new(SettingField {
+ json_path: Some("icon_theme$string"),
+ pick: |settings_content| {
+ match settings_content.theme.icon_theme.as_ref() {
+ Some(settings::IconThemeSelection::Static(name)) => Some(name),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .icon_theme.as_mut() {
+ Some(settings::IconThemeSelection::Static(theme_name)) => *theme_name = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
+ }
+ ],
+ settings::IconThemeSelectionDiscriminants::Dynamic => vec![
+ SettingItem {
+ files: USER,
+ title: "Mode",
+ description: "Choose whether to use the selected light or dark icon theme or to follow your OS appearance configuration.",
+ field: Box::new(SettingField {
+ json_path: Some("icon_theme"),
+ pick: |settings_content| {
+ match settings_content.theme.icon_theme.as_ref() {
+ Some(settings::IconThemeSelection::Dynamic { mode, ..}) => Some(mode),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .icon_theme.as_mut() {
+ Some(settings::IconThemeSelection::Dynamic{ mode, ..}) => *mode = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
},
- write: |_settings_content, _value| {
+ SettingItem {
+ files: USER,
+ title: "Light Icon Theme",
+ description: "The icon theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
+ field: Box::new(SettingField {
+ json_path: Some("icon_theme.light"),
+ pick: |settings_content| {
+ match settings_content.theme.icon_theme.as_ref() {
+ Some(settings::IconThemeSelection::Dynamic { light, ..}) => Some(light),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .icon_theme.as_mut() {
+ Some(settings::IconThemeSelection::Dynamic{ light, ..}) => *light = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
},
- }
- .unimplemented(),
- ),
- metadata: None,
+ SettingItem {
+ files: USER,
+ title: "Dark Icon Theme",
+ description: "The icon theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
+ field: Box::new(SettingField {
+ json_path: Some("icon_theme.dark"),
+ pick: |settings_content| {
+ match settings_content.theme.icon_theme.as_ref() {
+ Some(settings::IconThemeSelection::Dynamic { dark, ..}) => Some(dark),
+ _ => None
+ }
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content
+ .theme
+ .icon_theme.as_mut() {
+ Some(settings::IconThemeSelection::Dynamic{ dark, ..}) => *dark = value,
+ _ => return
+ }
+ },
+ }),
+ metadata: None,
+ }
+ ],
+ }
+ }).collect(),
+ }),
+ ]
+ }
+
+ fn buffer_font_section() -> [SettingsPageItem; 7] {
+ [
+ SettingsPageItem::SectionHeader("Buffer Font"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Family",
+ description: "Font family for editor text.",
+ field: Box::new(SettingField {
+ json_path: Some("buffer_font_family"),
+ pick: |settings_content| settings_content.theme.buffer_font_family.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.buffer_font_family = value;
+ },
}),
- SettingsPageItem::SectionHeader("Privacy"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Telemetry Diagnostics",
- description: "Send debug information like crash reports.",
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Size",
+ description: "Font size for editor text.",
+ field: Box::new(SettingField {
+ json_path: Some("buffer_font_size"),
+ pick: |settings_content| settings_content.theme.buffer_font_size.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.buffer_font_size = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Weight",
+ description: "Font weight for editor text (100-900).",
+ field: Box::new(SettingField {
+ json_path: Some("buffer_font_weight"),
+ pick: |settings_content| settings_content.theme.buffer_font_weight.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.buffer_font_weight = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::DynamicItem(DynamicItem {
+ discriminant: SettingItem {
+ files: USER,
+ title: "Line Height",
+ description: "Line height for editor text.",
field: Box::new(SettingField {
- json_path: Some("telemetry.diagnostics"),
+ json_path: Some("buffer_line_height$"),
pick: |settings_content| {
- settings_content
- .telemetry
- .as_ref()
- .and_then(|telemetry| telemetry.diagnostics.as_ref())
+ Some(
+ &dynamic_variants::<settings::BufferLineHeight>()[settings_content
+ .theme
+ .buffer_line_height
+ .as_ref()?
+ .discriminant()
+ as usize],
+ )
},
write: |settings_content, value| {
- settings_content
- .telemetry
- .get_or_insert_default()
- .diagnostics = value;
+ let Some(value) = value else {
+ settings_content.theme.buffer_line_height = None;
+ return;
+ };
+ let settings_value = settings_content
+ .theme
+ .buffer_line_height
+ .get_or_insert_with(|| settings::BufferLineHeight::default());
+ *settings_value = match value {
+ settings::BufferLineHeightDiscriminants::Comfortable => {
+ settings::BufferLineHeight::Comfortable
+ }
+ settings::BufferLineHeightDiscriminants::Standard => {
+ settings::BufferLineHeight::Standard
+ }
+ settings::BufferLineHeightDiscriminants::Custom => {
+ let custom_value =
+ theme::BufferLineHeight::from(*settings_value).value();
+ settings::BufferLineHeight::Custom(custom_value)
+ }
+ };
},
}),
metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Telemetry Metrics",
- description: "Send anonymized usage data like what languages you're using Zed with.",
- field: Box::new(SettingField {
- json_path: Some("telemetry.metrics"),
+ },
+ pick_discriminant: |settings_content| {
+ Some(
+ settings_content
+ .theme
+ .buffer_line_height
+ .as_ref()?
+ .discriminant() as usize,
+ )
+ },
+ fields: dynamic_variants::<settings::BufferLineHeight>()
+ .into_iter()
+ .map(|variant| match variant {
+ settings::BufferLineHeightDiscriminants::Comfortable => vec![],
+ settings::BufferLineHeightDiscriminants::Standard => vec![],
+ settings::BufferLineHeightDiscriminants::Custom => vec![SettingItem {
+ files: USER,
+ title: "Custom Line Height",
+ description: "Custom line height value (must be at least 1.0).",
+ field: Box::new(SettingField {
+ json_path: Some("buffer_line_height"),
+ pick: |settings_content| match settings_content
+ .theme
+ .buffer_line_height
+ .as_ref()
+ {
+ Some(settings::BufferLineHeight::Custom(value)) => Some(value),
+ _ => None,
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ return;
+ };
+ match settings_content.theme.buffer_line_height.as_mut() {
+ Some(settings::BufferLineHeight::Custom(line_height)) => {
+ *line_height = f32::max(value, 1.0)
+ }
+ _ => return,
+ }
+ },
+ }),
+ metadata: None,
+ }],
+ })
+ .collect(),
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Font Features",
+ description: "The OpenType features to enable for rendering in text buffers.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("buffer_font_features"),
pick: |settings_content| {
- settings_content
- .telemetry
- .as_ref()
- .and_then(|telemetry| telemetry.metrics.as_ref())
+ settings_content.theme.buffer_font_features.as_ref()
},
write: |settings_content, value| {
- settings_content.telemetry.get_or_insert_default().metrics = value;
+ settings_content.theme.buffer_font_features = value;
+ },
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Font Fallbacks",
+ description: "The font fallbacks to use for rendering in text buffers.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("buffer_font_fallbacks"),
+ pick: |settings_content| {
+ settings_content.theme.buffer_font_fallbacks.as_ref()
},
- }),
- 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 {
- json_path: Some("auto_update"),
- pick: |settings_content| settings_content.auto_update.as_ref(),
write: |settings_content, value| {
- settings_content.auto_update = value;
+ settings_content.theme.buffer_font_fallbacks = value;
},
- }),
- metadata: None,
- files: USER,
- }),
- ],
- },
- SettingsPage {
- title: "Appearance",
- items: vec![
- SettingsPageItem::SectionHeader("Theme"),
- SettingsPageItem::DynamicItem(DynamicItem {
- discriminant: SettingItem {
- files: USER,
- title: "Theme Mode",
- description: "Choose a static, fixed theme or dynamically select themes based on appearance and light/dark modes.",
- field: Box::new(SettingField {
- json_path: Some("theme$"),
- pick: |settings_content| {
- Some(&dynamic_variants::<settings::ThemeSelection>()[
- settings_content
- .theme
- .theme
- .as_ref()?
- .discriminant() as usize])
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- settings_content.theme.theme = None;
- return;
- };
- let settings_value = settings_content.theme.theme.get_or_insert_default();
- *settings_value = match value {
- settings::ThemeSelectionDiscriminants::Static => {
- let name = match settings_value {
- settings::ThemeSelection::Static(_) => return,
- settings::ThemeSelection::Dynamic { mode, light, dark } => {
- match mode {
- theme::ThemeAppearanceMode::Light => light.clone(),
- theme::ThemeAppearanceMode::Dark => dark.clone(),
- theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
- }
- },
- };
- settings::ThemeSelection::Static(name)
- },
- settings::ThemeSelectionDiscriminants::Dynamic => {
- let static_name = match settings_value {
- settings::ThemeSelection::Static(theme_name) => theme_name.clone(),
- settings::ThemeSelection::Dynamic {..} => return,
- };
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ ]
+ }
- settings::ThemeSelection::Dynamic {
- mode: settings::ThemeAppearanceMode::System,
- light: static_name.clone(),
- dark: static_name,
- }
- },
- };
- },
- }),
- metadata: None,
+ fn ui_font_section() -> [SettingsPageItem; 6] {
+ [
+ SettingsPageItem::SectionHeader("UI Font"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Family",
+ description: "Font family for UI elements.",
+ field: Box::new(SettingField {
+ json_path: Some("ui_font_family"),
+ pick: |settings_content| settings_content.theme.ui_font_family.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.ui_font_family = value;
},
- pick_discriminant: |settings_content| {
- Some(settings_content.theme.theme.as_ref()?.discriminant() as usize)
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Size",
+ description: "Font size for UI elements.",
+ field: Box::new(SettingField {
+ json_path: Some("ui_font_size"),
+ pick: |settings_content| settings_content.theme.ui_font_size.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.ui_font_size = value;
},
- fields: dynamic_variants::<settings::ThemeSelection>().into_iter().map(|variant| {
- match variant {
- settings::ThemeSelectionDiscriminants::Static => vec![
- SettingItem {
- files: USER,
- title: "Theme Name",
- description: "The name of your selected theme.",
- field: Box::new(SettingField {
- json_path: Some("theme"),
- pick: |settings_content| {
- match settings_content.theme.theme.as_ref() {
- Some(settings::ThemeSelection::Static(name)) => Some(name),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .theme.get_or_insert_default() {
- settings::ThemeSelection::Static(theme_name) => *theme_name = value,
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- settings::ThemeSelectionDiscriminants::Dynamic => vec![
- SettingItem {
- files: USER,
- title: "Mode",
- description: "Choose whether to use the selected light or dark theme or to follow your OS appearance configuration.",
- field: Box::new(SettingField {
- json_path: Some("theme.mode"),
- pick: |settings_content| {
- match settings_content.theme.theme.as_ref() {
- Some(settings::ThemeSelection::Dynamic { mode, ..}) => Some(mode),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .theme.get_or_insert_default() {
- settings::ThemeSelection::Dynamic{ mode, ..} => *mode = value,
- _ => return
- }
- },
- }),
- metadata: None,
- },
- SettingItem {
- files: USER,
- title: "Light Theme",
- description: "The theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
- field: Box::new(SettingField {
- json_path: Some("theme.light"),
- pick: |settings_content| {
- match settings_content.theme.theme.as_ref() {
- Some(settings::ThemeSelection::Dynamic { light, ..}) => Some(light),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .theme.get_or_insert_default() {
- settings::ThemeSelection::Dynamic{ light, ..} => *light = value,
- _ => return
- }
- },
- }),
- metadata: None,
- },
- SettingItem {
- files: USER,
- title: "Dark Theme",
- description: "The theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
- field: Box::new(SettingField {
- json_path: Some("theme.dark"),
- pick: |settings_content| {
- match settings_content.theme.theme.as_ref() {
- Some(settings::ThemeSelection::Dynamic { dark, ..}) => Some(dark),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .theme.get_or_insert_default() {
- settings::ThemeSelection::Dynamic{ dark, ..} => *dark = value,
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- }
- }).collect(),
}),
- SettingsPageItem::DynamicItem(DynamicItem {
- discriminant: SettingItem {
- files: USER,
- title: "Icon Theme",
- description: "The custom set of icons Zed will associate with files and directories.",
- field: Box::new(SettingField {
- json_path: Some("icon_theme$"),
- pick: |settings_content| {
- Some(&dynamic_variants::<settings::IconThemeSelection>()[
- settings_content
- .theme
- .icon_theme
- .as_ref()?
- .discriminant() as usize])
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- settings_content.theme.icon_theme = None;
- return;
- };
- let settings_value = settings_content.theme.icon_theme.get_or_insert_with(|| {
- settings::IconThemeSelection::Static(settings::IconThemeName(theme::default_icon_theme().name.clone().into()))
- });
- *settings_value = match value {
- settings::IconThemeSelectionDiscriminants::Static => {
- let name = match settings_value {
- settings::IconThemeSelection::Static(_) => return,
- settings::IconThemeSelection::Dynamic { mode, light, dark } => {
- match mode {
- theme::ThemeAppearanceMode::Light => light.clone(),
- theme::ThemeAppearanceMode::Dark => dark.clone(),
- theme::ThemeAppearanceMode::System => dark.clone(), // no cx, can't determine correct choice
- }
- },
- };
- settings::IconThemeSelection::Static(name)
- },
- settings::IconThemeSelectionDiscriminants::Dynamic => {
- let static_name = match settings_value {
- settings::IconThemeSelection::Static(theme_name) => theme_name.clone(),
- settings::IconThemeSelection::Dynamic {..} => return,
- };
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Font Weight",
+ description: "Font weight for UI elements (100-900).",
+ field: Box::new(SettingField {
+ json_path: Some("ui_font_weight"),
+ pick: |settings_content| settings_content.theme.ui_font_weight.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.ui_font_weight = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Font Features",
+ description: "The OpenType features to enable for rendering in UI elements.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("ui_font_features"),
+ pick: |settings_content| settings_content.theme.ui_font_features.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.ui_font_features = value;
+ },
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Font Fallbacks",
+ description: "The font fallbacks to use for rendering in the UI.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("ui_font_fallbacks"),
+ pick: |settings_content| settings_content.theme.ui_font_fallbacks.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.ui_font_fallbacks = value;
+ },
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ ]
+ }
- settings::IconThemeSelection::Dynamic {
- mode: settings::ThemeAppearanceMode::System,
- light: static_name.clone(),
- dark: static_name,
- }
- },
- };
- },
- }),
- metadata: None,
+ fn agent_panel_font_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Agent Panel Font"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "UI Font Size",
+ description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.",
+ field: Box::new(SettingField {
+ json_path: Some("agent_ui_font_size"),
+ pick: |settings_content| {
+ settings_content
+ .theme
+ .agent_ui_font_size
+ .as_ref()
+ .or(settings_content.theme.ui_font_size.as_ref())
},
- pick_discriminant: |settings_content| {
- Some(settings_content.theme.icon_theme.as_ref()?.discriminant() as usize)
+ write: |settings_content, value| {
+ settings_content.theme.agent_ui_font_size = value;
},
- fields: dynamic_variants::<settings::IconThemeSelection>().into_iter().map(|variant| {
- match variant {
- settings::IconThemeSelectionDiscriminants::Static => vec![
- SettingItem {
- files: USER,
- title: "Icon Theme Name",
- description: "The name of your selected icon theme.",
- field: Box::new(SettingField {
- json_path: Some("icon_theme$string"),
- pick: |settings_content| {
- match settings_content.theme.icon_theme.as_ref() {
- Some(settings::IconThemeSelection::Static(name)) => Some(name),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .icon_theme.as_mut() {
- Some(settings::IconThemeSelection::Static(theme_name)) => *theme_name = value,
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- settings::IconThemeSelectionDiscriminants::Dynamic => vec![
- SettingItem {
- files: USER,
- title: "Mode",
- description: "Choose whether to use the selected light or dark icon theme or to follow your OS appearance configuration.",
- field: Box::new(SettingField {
- json_path: Some("icon_theme"),
- pick: |settings_content| {
- match settings_content.theme.icon_theme.as_ref() {
- Some(settings::IconThemeSelection::Dynamic { mode, ..}) => Some(mode),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .icon_theme.as_mut() {
- Some(settings::IconThemeSelection::Dynamic{ mode, ..}) => *mode = value,
- _ => return
- }
- },
- }),
- metadata: None,
- },
- SettingItem {
- files: USER,
- title: "Light Icon Theme",
- description: "The icon theme to use when mode is set to light, or when mode is set to system and it is in light mode.",
- field: Box::new(SettingField {
- json_path: Some("icon_theme.light"),
- pick: |settings_content| {
- match settings_content.theme.icon_theme.as_ref() {
- Some(settings::IconThemeSelection::Dynamic { light, ..}) => Some(light),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .icon_theme.as_mut() {
- Some(settings::IconThemeSelection::Dynamic{ light, ..}) => *light = value,
- _ => return
- }
- },
- }),
- metadata: None,
- },
- SettingItem {
- files: USER,
- title: "Dark Icon Theme",
- description: "The icon theme to use when mode is set to dark, or when mode is set to system and it is in dark mode.",
- field: Box::new(SettingField {
- json_path: Some("icon_theme.dark"),
- pick: |settings_content| {
- match settings_content.theme.icon_theme.as_ref() {
- Some(settings::IconThemeSelection::Dynamic { dark, ..}) => Some(dark),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .icon_theme.as_mut() {
- Some(settings::IconThemeSelection::Dynamic{ dark, ..}) => *dark = value,
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- }
- }).collect(),
}),
- SettingsPageItem::SectionHeader("Buffer Font"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Family",
- description: "Font family for editor text.",
- field: Box::new(SettingField {
- json_path: Some("buffer_font_family"),
- pick: |settings_content| settings_content.theme.buffer_font_family.as_ref(),
- write: |settings_content, value|{ settings_content.theme.buffer_font_family = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Buffer Font Size",
+ description: "Font size for user messages text in the agent panel.",
+ field: Box::new(SettingField {
+ json_path: Some("agent_buffer_font_size"),
+ pick: |settings_content| {
+ settings_content
+ .theme
+ .agent_buffer_font_size
+ .as_ref()
+ .or(settings_content.theme.buffer_font_size.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content.theme.agent_buffer_font_size = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Size",
- description: "Font size for editor text.",
- field: Box::new(SettingField {
- json_path: Some("buffer_font_size"),
- pick: |settings_content| settings_content.theme.buffer_font_size.as_ref(),
- write: |settings_content, value|{ settings_content.theme.buffer_font_size = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn text_rendering_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Text Rendering"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Text Rendering Mode",
+ description: "The text rendering mode to use.",
+ field: Box::new(SettingField {
+ json_path: Some("text_rendering_mode"),
+ pick: |settings_content| {
+ settings_content.workspace.text_rendering_mode.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.text_rendering_mode = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Weight",
- description: "Font weight for editor text (100-900).",
- field: Box::new(SettingField {
- json_path: Some("buffer_font_weight"),
- pick: |settings_content| settings_content.theme.buffer_font_weight.as_ref(),
- write: |settings_content, value|{ settings_content.theme.buffer_font_weight = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn cursor_section() -> [SettingsPageItem; 5] {
+ [
+ SettingsPageItem::SectionHeader("Cursor"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Multi Cursor Modifier",
+ description: "Modifier key for adding multiple cursors.",
+ field: Box::new(SettingField {
+ json_path: Some("multi_cursor_modifier"),
+ pick: |settings_content| settings_content.editor.multi_cursor_modifier.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.multi_cursor_modifier = value;
+ },
}),
- SettingsPageItem::DynamicItem(DynamicItem {
- discriminant: SettingItem {
- files: USER,
- title: "Line Height",
- description: "Line height for editor text.",
- field: Box::new(SettingField {
- json_path: Some("buffer_line_height$"),
- pick: |settings_content| {
- Some(&dynamic_variants::<settings::BufferLineHeight>()[
- settings_content
- .theme
- .buffer_line_height
- .as_ref()?
- .discriminant() as usize])
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- settings_content.theme.buffer_line_height = None;
- return;
- };
- let settings_value = settings_content.theme.buffer_line_height.get_or_insert_with(|| {
- settings::BufferLineHeight::default()
- });
- *settings_value = match value {
- settings::BufferLineHeightDiscriminants::Comfortable => {
- settings::BufferLineHeight::Comfortable
- },
- settings::BufferLineHeightDiscriminants::Standard => {
- settings::BufferLineHeight::Standard
- },
- settings::BufferLineHeightDiscriminants::Custom => {
- let custom_value = theme::BufferLineHeight::from(*settings_value).value();
- settings::BufferLineHeight::Custom(custom_value)
- },
- };
- },
- }),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Blink",
+ description: "Whether the cursor blinks in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("cursor_blink"),
+ pick: |settings_content| settings_content.editor.cursor_blink.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.cursor_blink = value;
},
- pick_discriminant: |settings_content| {
- Some(settings_content.theme.buffer_line_height.as_ref()?.discriminant() as usize)
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Shape",
+ description: "Cursor shape for the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("cursor_shape"),
+ pick: |settings_content| settings_content.editor.cursor_shape.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.cursor_shape = value;
},
- fields: dynamic_variants::<settings::BufferLineHeight>().into_iter().map(|variant| {
- match variant {
- settings::BufferLineHeightDiscriminants::Comfortable => vec![],
- settings::BufferLineHeightDiscriminants::Standard => vec![],
- settings::BufferLineHeightDiscriminants::Custom => vec![
- SettingItem {
- files: USER,
- title: "Custom Line Height",
- description: "Custom line height value (must be at least 1.0).",
- field: Box::new(SettingField {
- json_path: Some("buffer_line_height"),
- pick: |settings_content| {
- match settings_content.theme.buffer_line_height.as_ref() {
- Some(settings::BufferLineHeight::Custom(value)) => Some(value),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- return;
- };
- match settings_content
- .theme
- .buffer_line_height.as_mut() {
- Some(settings::BufferLineHeight::Custom(line_height)) => *line_height = f32::max(value, 1.0),
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- }
- }).collect(),
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Font Features",
- description: "The OpenType features to enable for rendering in text buffers.",
- field: Box::new(
- SettingField {
- json_path: Some("buffer_font_features"),
- pick: |settings_content| {
- settings_content.theme.buffer_font_features.as_ref()
- },
- write: |settings_content, value| {
- settings_content.theme.buffer_font_features = value;
-
- },
- }
- .unimplemented(),
- ),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Hide Mouse",
+ description: "When to hide the mouse cursor.",
+ field: Box::new(SettingField {
+ json_path: Some("hide_mouse"),
+ pick: |settings_content| settings_content.editor.hide_mouse.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.hide_mouse = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Font Fallbacks",
- description: "The font fallbacks to use for rendering in text buffers.",
- field: Box::new(
- SettingField {
- json_path: Some("buffer_font_fallbacks"),
- pick: |settings_content| {
- settings_content.theme.buffer_font_fallbacks.as_ref()
- },
- write: |settings_content, value| {
- settings_content.theme.buffer_font_fallbacks = value;
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- },
- }
- .unimplemented(),
- ),
- metadata: None,
+ fn highlighting_section() -> [SettingsPageItem; 6] {
+ [
+ SettingsPageItem::SectionHeader("Highlighting"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Unnecessary Code Fade",
+ description: "How much to fade out unused code (0.0 - 0.9).",
+ field: Box::new(SettingField {
+ json_path: Some("unnecessary_code_fade"),
+ pick: |settings_content| settings_content.theme.unnecessary_code_fade.as_ref(),
+ write: |settings_content, value| {
+ settings_content.theme.unnecessary_code_fade = value;
+ },
}),
- SettingsPageItem::SectionHeader("UI Font"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Family",
- description: "Font family for UI elements.",
- field: Box::new(SettingField {
- json_path: Some("ui_font_family"),
- pick: |settings_content| settings_content.theme.ui_font_family.as_ref(),
- write: |settings_content, value|{ settings_content.theme.ui_font_family = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Current Line Highlight",
+ description: "How to highlight the current line.",
+ field: Box::new(SettingField {
+ json_path: Some("current_line_highlight"),
+ pick: |settings_content| {
+ settings_content.editor.current_line_highlight.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.current_line_highlight = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Size",
- description: "Font size for UI elements.",
- field: Box::new(SettingField {
- json_path: Some("ui_font_size"),
- pick: |settings_content| settings_content.theme.ui_font_size.as_ref(),
- write: |settings_content, value|{ settings_content.theme.ui_font_size = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Selection Highlight",
+ description: "Highlight all occurrences of selected text.",
+ field: Box::new(SettingField {
+ json_path: Some("selection_highlight"),
+ pick: |settings_content| settings_content.editor.selection_highlight.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.selection_highlight = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Font Weight",
- description: "Font weight for UI elements (100-900).",
- field: Box::new(SettingField {
- json_path: Some("ui_font_weight"),
- pick: |settings_content| settings_content.theme.ui_font_weight.as_ref(),
- write: |settings_content, value|{ settings_content.theme.ui_font_weight = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Rounded Selection",
+ description: "Whether the text selection should have rounded corners.",
+ field: Box::new(SettingField {
+ json_path: Some("rounded_selection"),
+ pick: |settings_content| settings_content.editor.rounded_selection.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.rounded_selection = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Font Features",
- description: "The OpenType features to enable for rendering in UI elements.",
- field: Box::new(
- SettingField {
- json_path: Some("ui_font_features"),
- pick: |settings_content| {
- settings_content.theme.ui_font_features.as_ref()
- },
- write: |settings_content, value| {
- settings_content.theme.ui_font_features = value;
-
- },
- }
- .unimplemented(),
- ),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Minimum Contrast For Highlights",
+ description: "The minimum APCA perceptual contrast to maintain when rendering text over highlight backgrounds.",
+ field: Box::new(SettingField {
+ json_path: Some("minimum_contrast_for_highlights"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .minimum_contrast_for_highlights
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.minimum_contrast_for_highlights = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Font Fallbacks",
- description: "The font fallbacks to use for rendering in the UI.",
- field: Box::new(
- SettingField {
- json_path: Some("ui_font_fallbacks"),
- pick: |settings_content| {
- settings_content.theme.ui_font_fallbacks.as_ref()
- },
- write: |settings_content, value| {
- settings_content.theme.ui_font_fallbacks = value;
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- }),
- SettingsPageItem::SectionHeader("Agent Panel Font"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "UI Font Size",
- description: "Font size for agent response text in the agent panel. Falls back to the regular UI font size.",
- field: Box::new(SettingField {
- json_path: Some("agent_ui_font_size"),
- pick: |settings_content| {
- settings_content
- .theme
- .agent_ui_font_size
- .as_ref()
- .or(settings_content.theme.ui_font_size.as_ref())
- },
- write: |settings_content, value|{ settings_content.theme.agent_ui_font_size = value;},
- }),
- metadata: None,
- files: USER,
+ fn guides_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Guides"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Wrap Guides",
+ description: "Show wrap guides (vertical rulers).",
+ field: Box::new(SettingField {
+ json_path: Some("show_wrap_guides"),
+ pick: |settings_content| {
+ settings_content
+ .project
+ .all_languages
+ .defaults
+ .show_wrap_guides
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project
+ .all_languages
+ .defaults
+ .show_wrap_guides = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Buffer Font Size",
- description: "Font size for user messages text in the agent panel.",
- field: Box::new(SettingField {
- json_path: Some("agent_buffer_font_size"),
+ metadata: None,
+ files: USER | PROJECT,
+ }),
+ // todo(settings_ui): This needs a custom component
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Wrap Guides",
+ description: "Character counts at which to show wrap guides.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("wrap_guides"),
pick: |settings_content| {
settings_content
- .theme
- .agent_buffer_font_size
+ .project
+ .all_languages
+ .defaults
+ .wrap_guides
.as_ref()
- .or(settings_content.theme.buffer_font_size.as_ref())
- },
- write: |settings_content, value| {
- settings_content.theme.agent_buffer_font_size = value;
-
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Text Rendering"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Text Rendering Mode",
- description: "The text rendering mode to use.",
- field: Box::new(SettingField {
- json_path: Some("text_rendering_mode"),
- pick: |settings_content| {
- settings_content.workspace.text_rendering_mode.as_ref()
},
write: |settings_content, value| {
- settings_content.workspace.text_rendering_mode = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Cursor"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Multi Cursor Modifier",
- description: "Modifier key for adding multiple cursors.",
- field: Box::new(SettingField {
- json_path: Some("multi_cursor_modifier"),
- pick: |settings_content| {
- settings_content.editor.multi_cursor_modifier.as_ref()
+ settings_content.project.all_languages.defaults.wrap_guides = value;
},
- write: |settings_content, value| {
- settings_content.editor.multi_cursor_modifier = value;
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER | PROJECT,
+ }),
+ ]
+ }
- },
- }),
- metadata: None,
- files: USER,
+ let items: Box<[SettingsPageItem]> = concat_sections!(
+ theme_section(),
+ buffer_font_section(),
+ ui_font_section(),
+ agent_panel_font_section(),
+ text_rendering_section(),
+ cursor_section(),
+ highlighting_section(),
+ guides_section(),
+ );
+
+ SettingsPage {
+ title: "Appearance",
+ items,
+ }
+}
+
+fn keymap_page() -> SettingsPage {
+ fn keybindings_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Keybindings"),
+ SettingsPageItem::ActionLink(ActionLink {
+ title: "Edit Keybindings".into(),
+ description: Some("Customize keybindings in the keymap editor.".into()),
+ button_text: "Open Keymap".into(),
+ on_click: Arc::new(|settings_window, window, cx| {
+ let Some(original_window) = settings_window.original_window else {
+ return;
+ };
+ original_window
+ .update(cx, |_workspace, original_window, cx| {
+ original_window
+ .dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx);
+ original_window.activate_window();
+ })
+ .ok();
+ window.remove_window();
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Cursor Blink",
- description: "Whether the cursor blinks in the editor.",
- field: Box::new(SettingField {
- json_path: Some("cursor_blink"),
- pick: |settings_content| settings_content.editor.cursor_blink.as_ref(),
- write: |settings_content, value|{ settings_content.editor.cursor_blink = value;},
- }),
- metadata: None,
- files: USER,
+ }),
+ ]
+ }
+
+ fn base_keymap_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Base Keymap"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Base Keymap",
+ description: "The name of a base set of key bindings to use.",
+ field: Box::new(SettingField {
+ json_path: Some("base_keymap"),
+ pick: |settings_content| settings_content.base_keymap.as_ref(),
+ write: |settings_content, value| {
+ settings_content.base_keymap = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Cursor Shape",
- description: "Cursor shape for the editor.",
- field: Box::new(SettingField {
- json_path: Some("cursor_shape"),
- pick: |settings_content| settings_content.editor.cursor_shape.as_ref(),
- write: |settings_content, value|{ settings_content.editor.cursor_shape = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: Some(Box::new(SettingsFieldMetadata {
+ should_do_titlecase: Some(false),
+ ..Default::default()
+ })),
+ files: USER,
+ }),
+ ]
+ }
+
+ fn modal_editing_section() -> [SettingsPageItem; 3] {
+ [
+ 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: "Vim Mode",
+ description: "Enable Vim mode and key bindings.",
+ field: Box::new(SettingField {
+ json_path: Some("vim_mode"),
+ pick: |settings_content| settings_content.vim_mode.as_ref(),
+ write: |settings_content, value| {
+ settings_content.vim_mode = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Hide Mouse",
- description: "When to hide the mouse cursor.",
- field: Box::new(SettingField {
- json_path: Some("hide_mouse"),
- pick: |settings_content| settings_content.editor.hide_mouse.as_ref(),
- write: |settings_content, value|{ settings_content.editor.hide_mouse = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Helix Mode",
+ description: "Enable Helix mode and key bindings.",
+ field: Box::new(SettingField {
+ json_path: Some("helix_mode"),
+ pick: |settings_content| settings_content.helix_mode.as_ref(),
+ write: |settings_content, value| {
+ settings_content.helix_mode = value;
+ },
}),
- SettingsPageItem::SectionHeader("Highlighting"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Unnecessary Code Fade",
- description: "How much to fade out unused code (0.0 - 0.9).",
- field: Box::new(SettingField {
- json_path: Some("unnecessary_code_fade"),
- pick: |settings_content| {
- settings_content.theme.unnecessary_code_fade.as_ref()
- },
- write: |settings_content, value| {
- settings_content.theme.unnecessary_code_fade = value;
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Current Line Highlight",
- description: "How to highlight the current line.",
- field: Box::new(SettingField {
- json_path: Some("current_line_highlight"),
- pick: |settings_content| {
- settings_content.editor.current_line_highlight.as_ref()
+ let items: Box<[SettingsPageItem]> = concat_sections!(
+ keybindings_section(),
+ base_keymap_section(),
+ modal_editing_section(),
+ );
+
+ SettingsPage {
+ title: "Keymap",
+ items,
+ }
+}
+
+fn editor_page() -> SettingsPage {
+ fn auto_save_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Auto Save"),
+ SettingsPageItem::DynamicItem(DynamicItem {
+ discriminant: SettingItem {
+ files: USER,
+ title: "Auto Save Mode",
+ description: "When to auto save buffer changes.",
+ field: Box::new(SettingField {
+ json_path: Some("autosave$"),
+ pick: |settings_content| {
+ Some(
+ &dynamic_variants::<settings::AutosaveSetting>()[settings_content
+ .workspace
+ .autosave
+ .as_ref()?
+ .discriminant()
+ as usize],
+ )
},
write: |settings_content, value| {
- settings_content.editor.current_line_highlight = value;
-
+ let Some(value) = value else {
+ settings_content.workspace.autosave = None;
+ return;
+ };
+ let settings_value = settings_content
+ .workspace
+ .autosave
+ .get_or_insert_with(|| settings::AutosaveSetting::Off);
+ *settings_value = match value {
+ settings::AutosaveSettingDiscriminants::Off => {
+ settings::AutosaveSetting::Off
+ }
+ settings::AutosaveSettingDiscriminants::AfterDelay => {
+ let milliseconds = match settings_value {
+ settings::AutosaveSetting::AfterDelay { milliseconds } => {
+ *milliseconds
+ }
+ _ => settings::DelayMs(1000),
+ };
+ settings::AutosaveSetting::AfterDelay { milliseconds }
+ }
+ settings::AutosaveSettingDiscriminants::OnFocusChange => {
+ settings::AutosaveSetting::OnFocusChange
+ }
+ settings::AutosaveSettingDiscriminants::OnWindowChange => {
+ settings::AutosaveSetting::OnWindowChange
+ }
+ };
},
}),
metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Selection Highlight",
- description: "Highlight all occurrences of selected text.",
- field: Box::new(SettingField {
- json_path: Some("selection_highlight"),
- pick: |settings_content| {
- settings_content.editor.selection_highlight.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.selection_highlight = value;
+ },
+ pick_discriminant: |settings_content| {
+ Some(settings_content.workspace.autosave.as_ref()?.discriminant() as usize)
+ },
+ fields: dynamic_variants::<settings::AutosaveSetting>()
+ .into_iter()
+ .map(|variant| match variant {
+ settings::AutosaveSettingDiscriminants::Off => vec![],
+ settings::AutosaveSettingDiscriminants::AfterDelay => vec![SettingItem {
+ files: USER,
+ title: "Delay (milliseconds)",
+ description: "Save after inactivity period (in milliseconds).",
+ field: Box::new(SettingField {
+ json_path: Some("autosave.after_delay.milliseconds"),
+ pick: |settings_content| match settings_content
+ .workspace
+ .autosave
+ .as_ref()
+ {
+ Some(settings::AutosaveSetting::AfterDelay {
+ milliseconds,
+ }) => Some(milliseconds),
+ _ => None,
+ },
+ write: |settings_content, value| {
+ let Some(value) = value else {
+ settings_content.workspace.autosave = None;
+ return;
+ };
+ match settings_content.workspace.autosave.as_mut() {
+ Some(settings::AutosaveSetting::AfterDelay {
+ milliseconds,
+ }) => *milliseconds = value,
+ _ => return,
+ }
+ },
+ }),
+ metadata: None,
+ }],
+ settings::AutosaveSettingDiscriminants::OnFocusChange => vec![],
+ settings::AutosaveSettingDiscriminants::OnWindowChange => vec![],
+ })
+ .collect(),
+ }),
+ ]
+ }
- },
- }),
- metadata: None,
- files: USER,
+ fn which_key_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Which-key Menu"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Which-key Menu",
+ description: "Display the which-key menu with matching bindings while a multi-stroke binding is pending.",
+ field: Box::new(SettingField {
+ json_path: Some("which_key.enabled"),
+ pick: |settings_content| {
+ settings_content
+ .which_key
+ .as_ref()
+ .and_then(|settings| settings.enabled.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content.which_key.get_or_insert_default().enabled = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Rounded Selection",
- description: "Whether the text selection should have rounded corners.",
- field: Box::new(SettingField {
- json_path: Some("rounded_selection"),
- pick: |settings_content| settings_content.editor.rounded_selection.as_ref(),
- write: |settings_content, value|{ settings_content.editor.rounded_selection = value;},
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Menu Delay",
+ description: "Delay in milliseconds before the which-key menu appears.",
+ field: Box::new(SettingField {
+ json_path: Some("which_key.delay_ms"),
+ pick: |settings_content| {
+ settings_content
+ .which_key
+ .as_ref()
+ .and_then(|settings| settings.delay_ms.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content.which_key.get_or_insert_default().delay_ms = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Minimum Contrast For Highlights",
- description: "The minimum APCA perceptual contrast to maintain when rendering text over highlight backgrounds.",
- field: Box::new(SettingField {
- json_path: Some("minimum_contrast_for_highlights"),
- pick: |settings_content| {
- settings_content
- .editor
- .minimum_contrast_for_highlights
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.minimum_contrast_for_highlights = value;
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- },
- }),
- metadata: None,
- files: USER,
+ fn multibuffer_section() -> [SettingsPageItem; 5] {
+ [
+ SettingsPageItem::SectionHeader("Multibuffer"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Double Click In Multibuffer",
+ description: "What to do when multibuffer is double-clicked in some of its excerpts.",
+ field: Box::new(SettingField {
+ json_path: Some("double_click_in_multibuffer"),
+ pick: |settings_content| {
+ settings_content.editor.double_click_in_multibuffer.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.double_click_in_multibuffer = value;
+ },
}),
- SettingsPageItem::SectionHeader("Guides"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Wrap Guides",
- description: "Show wrap guides (vertical rulers).",
- field: Box::new(SettingField {
- json_path: Some("show_wrap_guides"),
- pick: |settings_content| {
- settings_content
- .project
- .all_languages
- .defaults
- .show_wrap_guides
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
-
- .project
- .all_languages
- .defaults
- .show_wrap_guides = value;
- },
- }),
- metadata: None,
- files: USER | PROJECT,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Expand Excerpt Lines",
+ description: "How many lines to expand the multibuffer excerpts by default.",
+ field: Box::new(SettingField {
+ json_path: Some("expand_excerpt_lines"),
+ pick: |settings_content| settings_content.editor.expand_excerpt_lines.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.expand_excerpt_lines = value;
+ },
}),
- // todo(settings_ui): This needs a custom component
- SettingsPageItem::SettingItem(SettingItem {
- title: "Wrap Guides",
- description: "Character counts at which to show wrap guides.",
- field: Box::new(
- SettingField {
- json_path: Some("wrap_guides"),
- pick: |settings_content| {
- settings_content
- .project
- .all_languages
- .defaults
- .wrap_guides
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.all_languages.defaults.wrap_guides = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER | PROJECT,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Excerpt Context Lines",
+ description: "How many lines of context to provide in multibuffer excerpts by default.",
+ field: Box::new(SettingField {
+ json_path: Some("excerpt_context_lines"),
+ pick: |settings_content| settings_content.editor.excerpt_context_lines.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.excerpt_context_lines = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Keymap",
- items: vec![
- SettingsPageItem::SectionHeader("Keybindings"),
- SettingsPageItem::ActionLink(ActionLink {
- title: "Edit Keybindings".into(),
- description: Some("Customize keybindings in the keymap editor.".into()),
- button_text: "Open Keymap".into(),
- on_click: Arc::new(|settings_window, window, cx| {
- let Some(original_window) = settings_window.original_window else {
- return;
- };
- original_window
- .update(cx, |_workspace, original_window, cx| {
- original_window
- .dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx);
- original_window.activate_window();
+ 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 {
+ json_path: Some("outline_panel.expand_outlines_with_depth"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()
+ .and_then(|outline_panel| {
+ outline_panel.expand_outlines_with_depth.as_ref()
})
- .ok();
- window.remove_window();
- }),
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .expand_outlines_with_depth = value;
+ },
}),
- SettingsPageItem::SectionHeader("Base Keymap"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Base Keymap",
- description: "The name of a base set of key bindings to use.",
- field: Box::new(SettingField {
- json_path: Some("base_keymap"),
- pick: |settings_content| settings_content.base_keymap.as_ref(),
- write: |settings_content, value| {
- settings_content.base_keymap = value;
- },
- }),
- metadata: Some(Box::new(SettingsFieldMetadata {
- should_do_titlecase: Some(false),
- ..Default::default()
- })),
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn scrolling_section() -> [SettingsPageItem; 8] {
+ [
+ SettingsPageItem::SectionHeader("Scrolling"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Scroll Beyond Last Line",
+ description: "Whether the editor will scroll beyond the last line.",
+ field: Box::new(SettingField {
+ json_path: Some("scroll_beyond_last_line"),
+ pick: |settings_content| {
+ settings_content.editor.scroll_beyond_last_line.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.scroll_beyond_last_line = value;
+ },
}),
- 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: "Vim Mode",
- description: "Enable Vim mode and key bindings.",
- field: Box::new(SettingField {
- json_path: Some("vim_mode"),
- pick: |settings_content| settings_content.vim_mode.as_ref(),
- write: |settings_content, value| {
- settings_content.vim_mode = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Vertical Scroll Margin",
+ description: "The number of lines to keep above/below the cursor when auto-scrolling.",
+ field: Box::new(SettingField {
+ json_path: Some("vertical_scroll_margin"),
+ pick: |settings_content| {
+ settings_content.editor.vertical_scroll_margin.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.vertical_scroll_margin = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Helix Mode",
- description: "Enable Helix mode and key bindings.",
- field: Box::new(SettingField {
- json_path: Some("helix_mode"),
- pick: |settings_content| settings_content.helix_mode.as_ref(),
- write: |settings_content, value| {
- settings_content.helix_mode = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Horizontal Scroll Margin",
+ description: "The number of characters to keep on either side when scrolling with the mouse.",
+ field: Box::new(SettingField {
+ json_path: Some("horizontal_scroll_margin"),
+ pick: |settings_content| {
+ settings_content.editor.horizontal_scroll_margin.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.horizontal_scroll_margin = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Editor",
- items: {
- let mut items = vec![
- SettingsPageItem::SectionHeader("Auto Save"),
- SettingsPageItem::DynamicItem(DynamicItem {
- discriminant: SettingItem {
- files: USER,
- title: "Auto Save Mode",
- description: "When to auto save buffer changes.",
- field: Box::new(SettingField {
- json_path: Some("autosave$"),
- pick: |settings_content| {
- Some(&dynamic_variants::<settings::AutosaveSetting>()[
- settings_content
- .workspace
- .autosave
- .as_ref()?
- .discriminant() as usize])
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- settings_content.workspace.autosave = None;
- return;
- };
- let settings_value = settings_content.workspace.autosave.get_or_insert_with(|| {
- settings::AutosaveSetting::Off
- });
- *settings_value = match value {
- settings::AutosaveSettingDiscriminants::Off => {
- settings::AutosaveSetting::Off
- },
- settings::AutosaveSettingDiscriminants::AfterDelay => {
- let milliseconds = match settings_value {
- settings::AutosaveSetting::AfterDelay { milliseconds } => *milliseconds,
- _ => settings::DelayMs(1000),
- };
- settings::AutosaveSetting::AfterDelay { milliseconds }
- },
- settings::AutosaveSettingDiscriminants::OnFocusChange => {
- settings::AutosaveSetting::OnFocusChange
- },
- settings::AutosaveSettingDiscriminants::OnWindowChange => {
- settings::AutosaveSetting::OnWindowChange
- },
- };
- },
- }),
- metadata: None,
- },
- pick_discriminant: |settings_content| {
- Some(settings_content.workspace.autosave.as_ref()?.discriminant() as usize)
- },
- fields: dynamic_variants::<settings::AutosaveSetting>().into_iter().map(|variant| {
- match variant {
- settings::AutosaveSettingDiscriminants::Off => vec![],
- settings::AutosaveSettingDiscriminants::AfterDelay => vec![
- SettingItem {
- files: USER,
- title: "Delay (milliseconds)",
- description: "Save after inactivity period (in milliseconds).",
- field: Box::new(SettingField {
- json_path: Some("autosave.after_delay.milliseconds"),
- pick: |settings_content| {
- match settings_content.workspace.autosave.as_ref() {
- Some(settings::AutosaveSetting::AfterDelay { milliseconds }) => Some(milliseconds),
- _ => None
- }
- },
- write: |settings_content, value| {
- let Some(value) = value else {
- settings_content.workspace.autosave = None;
- return;
- };
- match settings_content
- .workspace
- .autosave.as_mut() {
- Some(settings::AutosaveSetting::AfterDelay { milliseconds }) => *milliseconds = value,
- _ => return
- }
- },
- }),
- metadata: None,
- }
- ],
- settings::AutosaveSettingDiscriminants::OnFocusChange => vec![],
- settings::AutosaveSettingDiscriminants::OnWindowChange => vec![],
- }
- }).collect(),
- }),
- SettingsPageItem::SectionHeader("Which-key Menu"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Which-key Menu",
- description: "Display the which-key menu with matching bindings while a multi-stroke binding is pending.",
- field: Box::new(SettingField {
- json_path: Some("which_key.enabled"),
- pick: |settings_content| {
- settings_content
- .which_key
- .as_ref()
- .and_then(|settings| settings.enabled.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .which_key
- .get_or_insert_default()
- .enabled = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Menu Delay",
- description: "Delay in milliseconds before the which-key menu appears.",
- field: Box::new(SettingField {
- json_path: Some("which_key.delay_ms"),
- pick: |settings_content| {
- settings_content
- .which_key
- .as_ref()
- .and_then(|settings| settings.delay_ms.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .which_key
- .get_or_insert_default()
- .delay_ms = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Multibuffer"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Double Click In Multibuffer",
- description: "What to do when multibuffer is double-clicked in some of its excerpts.",
- field: Box::new(SettingField {
- json_path: Some("double_click_in_multibuffer"),
- pick: |settings_content| {
- settings_content.editor.double_click_in_multibuffer.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.double_click_in_multibuffer = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Expand Excerpt Lines",
- description: "How many lines to expand the multibuffer excerpts by default.",
- field: Box::new(SettingField {
- json_path: Some("expand_excerpt_lines"),
- pick: |settings_content| {
- settings_content.editor.expand_excerpt_lines.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.expand_excerpt_lines = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Excerpt Context Lines",
- description: "How many lines of context to provide in multibuffer excerpts by default.",
- field: Box::new(SettingField {
- json_path: Some("excerpt_context_lines"),
- pick: |settings_content| {
- settings_content.editor.excerpt_context_lines.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.excerpt_context_lines = value;
- },
- }),
- 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 {
- json_path: Some("outline_panel.expand_outlines_with_depth"),
- pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()
- .and_then(|outline_panel| {
- outline_panel.expand_outlines_with_depth.as_ref()
- })
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .expand_outlines_with_depth = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Scrolling"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Scroll Beyond Last Line",
- description: "Whether the editor will scroll beyond the last line.",
- field: Box::new(SettingField {
- json_path: Some("scroll_beyond_last_line"),
- pick: |settings_content| {
- settings_content.editor.scroll_beyond_last_line.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.scroll_beyond_last_line = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Vertical Scroll Margin",
- description: "The number of lines to keep above/below the cursor when auto-scrolling.",
- field: Box::new(SettingField {
- json_path: Some("vertical_scroll_margin"),
- pick: |settings_content| {
- settings_content.editor.vertical_scroll_margin.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.vertical_scroll_margin = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Horizontal Scroll Margin",
- description: "The number of characters to keep on either side when scrolling with the mouse.",
- field: Box::new(SettingField {
- json_path: Some("horizontal_scroll_margin"),
- pick: |settings_content| {
- settings_content.editor.horizontal_scroll_margin.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.horizontal_scroll_margin = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Scroll Sensitivity",
- description: "Scroll sensitivity multiplier for both horizontal and vertical scrolling.",
- field: Box::new(SettingField {
- json_path: Some("scroll_sensitivity"),
- pick: |settings_content| {
- settings_content.editor.scroll_sensitivity.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.scroll_sensitivity = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Fast Scroll Sensitivity",
- description: "Fast scroll sensitivity multiplier for both horizontal and vertical scrolling.",
- field: Box::new(SettingField {
- json_path: Some("fast_scroll_sensitivity"),
- pick: |settings_content| {
- settings_content.editor.fast_scroll_sensitivity.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.fast_scroll_sensitivity = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Autoscroll On Clicks",
- description: "Whether to scroll when clicking near the edge of the visible text area.",
- field: Box::new(SettingField {
- json_path: Some("autoscroll_on_clicks"),
- pick: |settings_content| {
- settings_content.editor.autoscroll_on_clicks.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.autoscroll_on_clicks = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Sticky Scroll",
- description: "Whether to stick scopes to the top of the editor",
- field: Box::new(SettingField {
- json_path: Some("sticky_scroll.enabled"),
- pick: |settings_content| {
- settings_content.editor.sticky_scroll.as_ref().and_then(|sticky_scroll| sticky_scroll.enabled.as_ref())
- },
- write: |settings_content, value| {
- settings_content.editor.sticky_scroll.get_or_insert_default().enabled = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Signature Help"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Auto Signature Help",
- description: "Automatically show a signature help pop-up.",
- field: Box::new(SettingField {
- json_path: Some("auto_signature_help"),
- pick: |settings_content| {
- settings_content.editor.auto_signature_help.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.auto_signature_help = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Signature Help After Edits",
- description: "Show the signature help pop-up after completions or bracket pairs are inserted.",
- field: Box::new(SettingField {
- json_path: Some("show_signature_help_after_edits"),
- pick: |settings_content| {
- settings_content
- .editor
- .show_signature_help_after_edits
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.show_signature_help_after_edits = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Snippet Sort Order",
- description: "Determines how snippets are sorted relative to other completion items.",
- field: Box::new(SettingField {
- json_path: Some("snippet_sort_order"),
- pick: |settings_content| {
- settings_content.editor.snippet_sort_order.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.snippet_sort_order = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Hover Popover"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enabled",
- description: "Show the informational hover box when moving the mouse over symbols in the editor.",
- field: Box::new(SettingField {
- json_path: Some("hover_popover_enabled"),
- pick: |settings_content| {
- settings_content.editor.hover_popover_enabled.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.hover_popover_enabled = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- // todo(settings ui): add units to this number input
- SettingsPageItem::SettingItem(SettingItem {
- title: "Delay",
- description: "Time to wait in milliseconds before showing the informational hover box.",
- field: Box::new(SettingField {
- json_path: Some("hover_popover_enabled"),
- pick: |settings_content| {
- settings_content.editor.hover_popover_delay.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.hover_popover_delay = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Drag And Drop Selection"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enabled",
- description: "Enable drag and drop selection.",
- field: Box::new(SettingField {
- json_path: Some("drag_and_drop_selection.enabled"),
- pick: |settings_content| {
- settings_content
- .editor
- .drag_and_drop_selection
- .as_ref()
- .and_then(|drag_and_drop| drag_and_drop.enabled.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .drag_and_drop_selection
- .get_or_insert_default()
- .enabled = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Delay",
- description: "Delay in milliseconds before drag and drop selection starts.",
- field: Box::new(SettingField {
- json_path: Some("drag_and_drop_selection.delay"),
- pick: |settings_content| {
- settings_content
- .editor
- .drag_and_drop_selection
- .as_ref()
- .and_then(|drag_and_drop| drag_and_drop.delay.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .drag_and_drop_selection
- .get_or_insert_default()
- .delay = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Gutter"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Line Numbers",
- description: "Show line numbers in the gutter.",
- field: Box::new(SettingField {
- json_path: Some("gutter.line_numbers"),
- pick: |settings_content| {
- settings_content
- .editor
- .gutter
- .as_ref()
- .and_then(|gutter| gutter.line_numbers.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .gutter
- .get_or_insert_default()
- .line_numbers = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Relative Line Numbers",
- description: "Controls line number display in the editor's gutter. \"disabled\" shows absolute line numbers, \"enabled\" shows relative line numbers for each absolute line, and \"wrapped\" shows relative line numbers for every line, absolute or wrapped.",
- field: Box::new(SettingField {
- json_path: Some("relative_line_numbers"),
- pick: |settings_content| {
- settings_content.editor.relative_line_numbers.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.relative_line_numbers = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Runnables",
- description: "Show runnable buttons in the gutter.",
- field: Box::new(SettingField {
- json_path: Some("gutter.runnables"),
- pick: |settings_content| {
- settings_content
- .editor
- .gutter
- .as_ref()
- .and_then(|gutter| gutter.runnables.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .gutter
- .get_or_insert_default()
- .runnables = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Breakpoints",
- description: "Show breakpoints in the gutter.",
- field: Box::new(SettingField {
- json_path: Some("gutter.breakpoints"),
- pick: |settings_content| {
- settings_content
- .editor
- .gutter
- .as_ref()
- .and_then(|gutter| gutter.breakpoints.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .gutter
- .get_or_insert_default()
- .breakpoints = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Folds",
- description: "Show code folding controls in the gutter.",
- field: Box::new(SettingField {
- json_path: Some("gutter.folds"),
- pick: |settings_content| {
- settings_content
- .editor
- .gutter
- .as_ref()
- .and_then(|gutter| gutter.folds.as_ref())
- },
- write: |settings_content, value| {
- settings_content.editor.gutter.get_or_insert_default().folds =
- value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Min Line Number Digits",
- description: "Minimum number of characters to reserve space for in the gutter.",
- field: Box::new(SettingField {
- json_path: Some("gutter.min_line_number_digits"),
- pick: |settings_content| {
- settings_content
- .editor
- .gutter
- .as_ref()
- .and_then(|gutter| gutter.min_line_number_digits.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .gutter
- .get_or_insert_default()
- .min_line_number_digits = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Inline Code Actions",
- description: "Show code action button at start of buffer line.",
- field: Box::new(SettingField {
- json_path: Some("inline_code_actions"),
- pick: |settings_content| {
- settings_content.editor.inline_code_actions.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.inline_code_actions = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Scrollbar"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show",
- description: "When to show the scrollbar in the editor.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar"),
- pick: |settings_content| {
- settings_content.editor.scrollbar.as_ref()?.show.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .show = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Cursors",
- description: "Show cursor positions in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.cursors"),
- pick: |settings_content| {
- settings_content.editor.scrollbar.as_ref()?.cursors.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .cursors = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Diff",
- description: "Show Git diff indicators in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.git_diff"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .git_diff
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .git_diff = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Search Results",
- description: "Show buffer search result indicators in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.search_results"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .search_results
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .search_results = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Selected Text",
- description: "Show selected text occurrences in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.selected_text"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .selected_text
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .selected_text = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Selected Symbol",
- description: "Show selected symbol occurrences in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.selected_symbol"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .selected_symbol
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .selected_symbol = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Diagnostics",
- description: "Which diagnostic indicators to show in the scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.diagnostics"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .diagnostics
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .diagnostics = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Horizontal Scrollbar",
- description: "When false, forcefully disables the horizontal scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.axes.horizontal"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .axes
- .as_ref()?
- .horizontal
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .axes
- .get_or_insert_default()
- .horizontal = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Vertical Scrollbar",
- description: "When false, forcefully disables the vertical scrollbar.",
- field: Box::new(SettingField {
- json_path: Some("scrollbar.axes.vertical"),
- pick: |settings_content| {
- settings_content
- .editor
- .scrollbar
- .as_ref()?
- .axes
- .as_ref()?
- .vertical
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .scrollbar
- .get_or_insert_default()
- .axes
- .get_or_insert_default()
- .vertical = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Minimap"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show",
- description: "When to show the minimap in the editor.",
- field: Box::new(SettingField {
- json_path: Some("minimap.show"),
- pick: |settings_content| {
- settings_content.editor.minimap.as_ref()?.show.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.minimap.get_or_insert_default().show =
- value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Display In",
- description: "Where to show the minimap in the editor.",
- field: Box::new(SettingField {
- json_path: Some("minimap.display_in"),
- pick: |settings_content| {
- settings_content
- .editor
- .minimap
- .as_ref()?
- .display_in
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .minimap
- .get_or_insert_default()
- .display_in = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Thumb",
- description: "When to show the minimap thumb.",
- field: Box::new(SettingField {
- json_path: Some("minimap.thumb"),
- pick: |settings_content| {
- settings_content.editor.minimap.as_ref()?.thumb.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .minimap
- .get_or_insert_default()
- .thumb = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Thumb Border",
- description: "Border style for the minimap's scrollbar thumb.",
- field: Box::new(SettingField {
- json_path: Some("minimap.thumb_border"),
- pick: |settings_content| {
- settings_content
- .editor
- .minimap
- .as_ref()?
- .thumb_border
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .minimap
- .get_or_insert_default()
- .thumb_border = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Current Line Highlight",
- description: "How to highlight the current line in the minimap.",
- field: Box::new(SettingField {
- json_path: Some("minimap.current_line_highlight"),
- pick: |settings_content| {
- settings_content
- .editor
- .minimap
- .as_ref()
- .and_then(|minimap| minimap.current_line_highlight.as_ref())
- .or(settings_content.editor.current_line_highlight.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .minimap
- .get_or_insert_default()
- .current_line_highlight = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Max Width Columns",
- description: "Maximum number of columns to display in the minimap.",
- field: Box::new(SettingField {
- json_path: Some("minimap.max_width_columns"),
- pick: |settings_content| {
- settings_content
- .editor
- .minimap
- .as_ref()?
- .max_width_columns
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .minimap
- .get_or_insert_default()
- .max_width_columns = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SectionHeader("Toolbar"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Breadcrumbs",
- description: "Show breadcrumbs.",
- field: Box::new(SettingField {
- json_path: Some("toolbar.breadcrumbs"),
- pick: |settings_content| {
- settings_content
- .editor
- .toolbar
- .as_ref()?
- .breadcrumbs
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .toolbar
- .get_or_insert_default()
- .breadcrumbs = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Quick Actions",
- description: "Show quick action buttons (e.g., search, selection, editor controls, etc.).",
- field: Box::new(SettingField {
- json_path: Some("toolbar.quick_actions"),
- pick: |settings_content| {
- settings_content
- .editor
- .toolbar
- .as_ref()?
- .quick_actions
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .toolbar
- .get_or_insert_default()
- .quick_actions = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Selections Menu",
- description: "Show the selections menu in the editor toolbar.",
- field: Box::new(SettingField {
- json_path: Some("toolbar.selections_menu"),
- pick: |settings_content| {
- settings_content
- .editor
- .toolbar
- .as_ref()?
- .selections_menu
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .toolbar
- .get_or_insert_default()
- .selections_menu = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Agent Review",
- description: "Show agent review buttons in the editor toolbar.",
- field: Box::new(SettingField {
- json_path: Some("toolbar.agent_review"),
- pick: |settings_content| {
- settings_content
- .editor
- .toolbar
- .as_ref()?
- .agent_review
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .toolbar
- .get_or_insert_default()
- .agent_review = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Code Actions",
- description: "Show code action buttons in the editor toolbar.",
- field: Box::new(SettingField {
- json_path: Some("toolbar.code_actions"),
- pick: |settings_content| {
- settings_content
- .editor
- .toolbar
- .as_ref()?
- .code_actions
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .toolbar
- .get_or_insert_default()
- .code_actions = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- ];
- items.extend(language_settings_data());
- items
- },
- },
- SettingsPage {
- title: "Languages & Tools",
- 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 {
- json_path: Some("file_type_associations"),
- pick: |settings_content| {
- settings_content.project.all_languages.file_types.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.all_languages.file_types = value;
-
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER | PROJECT,
- }),
- ]);
-
- 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 {
- json_path: Some("diagnostics_max_severity"),
- pick: |settings_content| settings_content.editor.diagnostics_max_severity.as_ref(),
- write: |settings_content, value| {
- settings_content.editor.diagnostics_max_severity = value;
-
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Include Warnings",
- description: "Whether to show warnings or not by default.",
- field: Box::new(SettingField {
- json_path: Some("diagnostics.include_warnings"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.include_warnings.as_ref()
- },
- write: |settings_content, value| {
- settings_content
-
- .diagnostics
- .get_or_insert_default()
- .include_warnings
- = value;
- },
- }),
- 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 {
- json_path: Some("diagnostics.inline.enabled"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.inline.as_ref()?.enabled.as_ref()
- },
- write: |settings_content, value| {
- settings_content
-
- .diagnostics
- .get_or_insert_default()
- .inline
- .get_or_insert_default()
- .enabled
- = value;
- },
- }),
- 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 {
- json_path: Some("diagnostics.inline.update_debounce_ms"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.inline.as_ref()?.update_debounce_ms.as_ref()
- },
- write: |settings_content, value| {
- settings_content
-
- .diagnostics
- .get_or_insert_default()
- .inline
- .get_or_insert_default()
- .update_debounce_ms
- = value;
- },
- }),
- 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 {
- json_path: Some("diagnostics.inline.padding"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.inline.as_ref()?.padding.as_ref()
- },
- write: |settings_content, value| {
- settings_content
-
- .diagnostics
- .get_or_insert_default()
- .inline
- .get_or_insert_default()
- .padding
- = value;
- },
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Minimum Column",
- description: "The minimum column at which to display inline diagnostics.",
- field: Box::new(SettingField {
- json_path: Some("diagnostics.inline.min_column"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.inline.as_ref()?.min_column.as_ref()
- },
- write: |settings_content, value| {
- settings_content
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Scroll Sensitivity",
+ description: "Scroll sensitivity multiplier for both horizontal and vertical scrolling.",
+ field: Box::new(SettingField {
+ json_path: Some("scroll_sensitivity"),
+ pick: |settings_content| settings_content.editor.scroll_sensitivity.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.scroll_sensitivity = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Fast Scroll Sensitivity",
+ description: "Fast scroll sensitivity multiplier for both horizontal and vertical scrolling.",
+ field: Box::new(SettingField {
+ json_path: Some("fast_scroll_sensitivity"),
+ pick: |settings_content| {
+ settings_content.editor.fast_scroll_sensitivity.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.fast_scroll_sensitivity = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Autoscroll On Clicks",
+ description: "Whether to scroll when clicking near the edge of the visible text area.",
+ field: Box::new(SettingField {
+ json_path: Some("autoscroll_on_clicks"),
+ pick: |settings_content| settings_content.editor.autoscroll_on_clicks.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.autoscroll_on_clicks = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Sticky Scroll",
+ description: "Whether to stick scopes to the top of the editor",
+ field: Box::new(SettingField {
+ json_path: Some("sticky_scroll.enabled"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .sticky_scroll
+ .as_ref()
+ .and_then(|sticky_scroll| sticky_scroll.enabled.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .sticky_scroll
+ .get_or_insert_default()
+ .enabled = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- .diagnostics
- .get_or_insert_default()
- .inline
- .get_or_insert_default()
- .min_column
- = value;
- },
- }),
- 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 {
- json_path: Some("diagnostics.lsp_pull_diagnostics.enabled"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.lsp_pull_diagnostics.as_ref()?.enabled.as_ref()
- },
- write: |settings_content, value| {
- settings_content
+ fn signature_help_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Signature Help"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Signature Help",
+ description: "Automatically show a signature help pop-up.",
+ field: Box::new(SettingField {
+ json_path: Some("auto_signature_help"),
+ pick: |settings_content| settings_content.editor.auto_signature_help.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.auto_signature_help = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Signature Help After Edits",
+ description: "Show the signature help pop-up after completions or bracket pairs are inserted.",
+ field: Box::new(SettingField {
+ json_path: Some("show_signature_help_after_edits"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .show_signature_help_after_edits
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.show_signature_help_after_edits = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Snippet Sort Order",
+ description: "Determines how snippets are sorted relative to other completion items.",
+ field: Box::new(SettingField {
+ json_path: Some("snippet_sort_order"),
+ pick: |settings_content| settings_content.editor.snippet_sort_order.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.snippet_sort_order = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- .diagnostics
- .get_or_insert_default()
- .lsp_pull_diagnostics
- .get_or_insert_default()
- .enabled
- = value;
- },
- }),
- 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 {
- json_path: Some("diagnostics.lsp_pull_diagnostics.debounce_ms"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.lsp_pull_diagnostics.as_ref()?.debounce_ms.as_ref()
- },
- write: |settings_content, value| {
- settings_content
+ fn hover_popover_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Hover Popover"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enabled",
+ description: "Show the informational hover box when moving the mouse over symbols in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("hover_popover_enabled"),
+ pick: |settings_content| settings_content.editor.hover_popover_enabled.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.hover_popover_enabled = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ // todo(settings ui): add units to this number input
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Delay",
+ description: "Time to wait in milliseconds before showing the informational hover box.",
+ field: Box::new(SettingField {
+ json_path: Some("hover_popover_enabled"),
+ pick: |settings_content| settings_content.editor.hover_popover_delay.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.hover_popover_delay = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
- .diagnostics
- .get_or_insert_default()
- .lsp_pull_diagnostics
- .get_or_insert_default()
- .debounce_ms
- = value;
- },
- }),
- 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 {
- json_path: Some("lsp_highlight_debounce"),
- pick: |settings_content| settings_content.editor.lsp_highlight_debounce.as_ref(),
- write: |settings_content, value| {
- settings_content.editor.lsp_highlight_debounce = value;
- },
- }),
- 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));
- items.extend(all_language_names(cx).into_iter().map(|language_name| {
- let link = format!("languages.{language_name}");
- SettingsPageItem::SubPageLink(SubPageLink {
- title: language_name,
- description: None,
- json_path: Some(link.leak()),
- in_json: true,
- files: USER | PROJECT,
- render: Arc::new(|this, window, cx| {
- this.render_sub_page_items(
- language_settings_data()
- .iter()
- .chain(non_editor_language_settings_data().iter())
- .chain(edit_prediction_language_settings_section().iter())
- .enumerate(),
- None,
- window,
- cx,
- )
- .into_any_element()
- }),
- })
- }));
- items
- },
- },
- SettingsPage {
- title: "Search & Files",
- items: vec![
- SettingsPageItem::SectionHeader("Search"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Whole Word",
- description: "Search for whole words by default.",
- field: Box::new(SettingField {
- json_path: Some("search.whole_word"),
- pick: |settings_content| {
- settings_content.editor.search.as_ref()?.whole_word.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .search
- .get_or_insert_default()
- .whole_word = value;
- },
- }),
- metadata: None,
- files: USER,
+ fn drag_and_drop_selection_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Drag And Drop Selection"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enabled",
+ description: "Enable drag and drop selection.",
+ field: Box::new(SettingField {
+ json_path: Some("drag_and_drop_selection.enabled"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .drag_and_drop_selection
+ .as_ref()
+ .and_then(|drag_and_drop| drag_and_drop.enabled.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .drag_and_drop_selection
+ .get_or_insert_default()
+ .enabled = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Case Sensitive",
- description: "Search case-sensitively by default.",
- field: Box::new(SettingField {
- json_path: Some("search.case_sensitive"),
- pick: |settings_content| {
- settings_content
- .editor
- .search
- .as_ref()?
- .case_sensitive
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .search
- .get_or_insert_default()
- .case_sensitive = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Delay",
+ description: "Delay in milliseconds before drag and drop selection starts.",
+ field: Box::new(SettingField {
+ json_path: Some("drag_and_drop_selection.delay"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .drag_and_drop_selection
+ .as_ref()
+ .and_then(|drag_and_drop| drag_and_drop.delay.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .drag_and_drop_selection
+ .get_or_insert_default()
+ .delay = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Use Smartcase Search",
- description: "Whether to automatically enable case-sensitive search based on the search query.",
- field: Box::new(SettingField {
- json_path: Some("use_smartcase_search"),
- pick: |settings_content| {
- settings_content.editor.use_smartcase_search.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.use_smartcase_search = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn gutter_section() -> [SettingsPageItem; 8] {
+ [
+ SettingsPageItem::SectionHeader("Gutter"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Line Numbers",
+ description: "Show line numbers in the gutter.",
+ field: Box::new(SettingField {
+ json_path: Some("gutter.line_numbers"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .gutter
+ .as_ref()
+ .and_then(|gutter| gutter.line_numbers.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .gutter
+ .get_or_insert_default()
+ .line_numbers = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Include Ignored",
- description: "Include ignored files in search results by default.",
- field: Box::new(SettingField {
- json_path: Some("search.include_ignored"),
- pick: |settings_content| {
- settings_content
- .editor
- .search
- .as_ref()?
- .include_ignored
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .search
- .get_or_insert_default()
- .include_ignored = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Relative Line Numbers",
+ description: "Controls line number display in the editor's gutter. \"disabled\" shows absolute line numbers, \"enabled\" shows relative line numbers for each absolute line, and \"wrapped\" shows relative line numbers for every line, absolute or wrapped.",
+ field: Box::new(SettingField {
+ json_path: Some("relative_line_numbers"),
+ pick: |settings_content| settings_content.editor.relative_line_numbers.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.relative_line_numbers = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Regex",
- description: "Use regex search by default.",
- field: Box::new(SettingField {
- json_path: Some("search.regex"),
- pick: |settings_content| {
- settings_content.editor.search.as_ref()?.regex.as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.search.get_or_insert_default().regex = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Runnables",
+ description: "Show runnable buttons in the gutter.",
+ field: Box::new(SettingField {
+ json_path: Some("gutter.runnables"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .gutter
+ .as_ref()
+ .and_then(|gutter| gutter.runnables.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .gutter
+ .get_or_insert_default()
+ .runnables = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Search Wrap",
- description: "Whether the editor search results will loop.",
- field: Box::new(SettingField {
- json_path: Some("search_wrap"),
- pick: |settings_content| settings_content.editor.search_wrap.as_ref(),
- write: |settings_content, value| {
- settings_content.editor.search_wrap = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Breakpoints",
+ description: "Show breakpoints in the gutter.",
+ field: Box::new(SettingField {
+ json_path: Some("gutter.breakpoints"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .gutter
+ .as_ref()
+ .and_then(|gutter| gutter.breakpoints.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .gutter
+ .get_or_insert_default()
+ .breakpoints = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Folds",
+ description: "Show code folding controls in the gutter.",
+ field: Box::new(SettingField {
+ json_path: Some("gutter.folds"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .gutter
+ .as_ref()
+ .and_then(|gutter| gutter.folds.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content.editor.gutter.get_or_insert_default().folds = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Center on Match",
- description: "Whether to center the current match in the editor",
- field: Box::new(SettingField {
- json_path: Some("editor.search.center_on_match"),
- pick: |settings_content| {
- settings_content
- .editor
- .search
- .as_ref()
- .and_then(|search| search.center_on_match.as_ref())
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .search
- .get_or_insert_default()
- .center_on_match = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Min Line Number Digits",
+ description: "Minimum number of characters to reserve space for in the gutter.",
+ field: Box::new(SettingField {
+ json_path: Some("gutter.min_line_number_digits"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .gutter
+ .as_ref()
+ .and_then(|gutter| gutter.min_line_number_digits.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .gutter
+ .get_or_insert_default()
+ .min_line_number_digits = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Seed Search Query From Cursor",
- description: "When to populate a new search's query based on the text under the cursor.",
- field: Box::new(SettingField {
- json_path: Some("seed_search_query_from_cursor"),
- pick: |settings_content| {
- settings_content
- .editor
- .seed_search_query_from_cursor
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.editor.seed_search_query_from_cursor = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Inline Code Actions",
+ description: "Show code action button at start of buffer line.",
+ field: Box::new(SettingField {
+ json_path: Some("inline_code_actions"),
+ pick: |settings_content| settings_content.editor.inline_code_actions.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.inline_code_actions = value;
+ },
}),
- SettingsPageItem::SectionHeader("File Finder"),
- // todo: null by default
- SettingsPageItem::SettingItem(SettingItem {
- title: "Include Ignored in Search",
- description: "Use gitignored files when searching.",
- field: Box::new(
- SettingField {
- json_path: Some("file_finder.include_ignored"),
- pick: |settings_content| {
- settings_content
- .file_finder
- .as_ref()?
- .include_ignored
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .file_finder
- .get_or_insert_default()
- .include_ignored = value;
- },
- }
- ),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn scrollbar_section() -> [SettingsPageItem; 10] {
+ [
+ SettingsPageItem::SectionHeader("Scrollbar"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show",
+ description: "When to show the scrollbar in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar"),
+ pick: |settings_content| {
+ settings_content.editor.scrollbar.as_ref()?.show.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .show = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "File Icons",
- description: "Show file icons in the file finder.",
- field: Box::new(SettingField {
- json_path: Some("file_finder.file_icons"),
- pick: |settings_content| {
- settings_content.file_finder.as_ref()?.file_icons.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .file_finder
- .get_or_insert_default()
- .file_icons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursors",
+ description: "Show cursor positions in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.cursors"),
+ pick: |settings_content| {
+ settings_content.editor.scrollbar.as_ref()?.cursors.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .cursors = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Modal Max Width",
- description: "Determines how much space the file finder can take up in relation to the available window width.",
- field: Box::new(SettingField {
- json_path: Some("file_finder.modal_max_width"),
- pick: |settings_content| {
- settings_content
- .file_finder
- .as_ref()?
- .modal_max_width
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .file_finder
- .get_or_insert_default()
- .modal_max_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Diff",
+ description: "Show Git diff indicators in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.git_diff"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .git_diff
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .git_diff = value;
+ },
}),
- 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.",
- field: Box::new(SettingField {
- json_path: Some("file_finder.skip_focus_for_active_in_search"),
- pick: |settings_content| {
- settings_content
- .file_finder
- .as_ref()?
- .skip_focus_for_active_in_search
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .file_finder
- .get_or_insert_default()
- .skip_focus_for_active_in_search = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Search Results",
+ description: "Show buffer search result indicators in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.search_results"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .search_results
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .search_results = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Status",
- description: "Show the Git status in the file finder.",
- field: Box::new(SettingField {
- json_path: Some("file_finder.git_status"),
- pick: |settings_content| {
- settings_content.file_finder.as_ref()?.git_status.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .file_finder
- .get_or_insert_default()
- .git_status = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Selected Text",
+ description: "Show selected text occurrences in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.selected_text"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .selected_text
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .selected_text = value;
+ },
}),
- 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 {
- json_path: Some("file_scan_exclusions"),
- pick: |settings_content| {
- settings_content
- .project
- .worktree
- .file_scan_exclusions
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.worktree.file_scan_exclusions = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Selected Symbol",
+ description: "Show selected symbol occurrences in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.selected_symbol"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .selected_symbol
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .selected_symbol = value;
+ },
}),
- 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 {
- json_path: Some("file_scan_inclusions"),
- pick: |settings_content| {
- settings_content
- .project
- .worktree
- .file_scan_inclusions
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.worktree.file_scan_inclusions = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Diagnostics",
+ description: "Which diagnostic indicators to show in the scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.diagnostics"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .diagnostics
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .diagnostics = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Restore File State",
- description: "Restore previous file state when reopening.",
- field: Box::new(SettingField {
- json_path: Some("restore_on_file_reopen"),
- pick: |settings_content| {
- settings_content.workspace.restore_on_file_reopen.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.restore_on_file_reopen = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Horizontal Scrollbar",
+ description: "When false, forcefully disables the horizontal scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.axes.horizontal"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .axes
+ .as_ref()?
+ .horizontal
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .axes
+ .get_or_insert_default()
+ .horizontal = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Vertical Scrollbar",
+ description: "When false, forcefully disables the vertical scrollbar.",
+ field: Box::new(SettingField {
+ json_path: Some("scrollbar.axes.vertical"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .scrollbar
+ .as_ref()?
+ .axes
+ .as_ref()?
+ .vertical
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .scrollbar
+ .get_or_insert_default()
+ .axes
+ .get_or_insert_default()
+ .vertical = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Close on File Delete",
- description: "Automatically close files that have been deleted.",
- field: Box::new(SettingField {
- json_path: Some("close_on_file_delete"),
- pick: |settings_content| {
- settings_content.workspace.close_on_file_delete.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.close_on_file_delete = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn minimap_section() -> [SettingsPageItem; 7] {
+ [
+ SettingsPageItem::SectionHeader("Minimap"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show",
+ description: "When to show the minimap in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.show"),
+ pick: |settings_content| {
+ settings_content.editor.minimap.as_ref()?.show.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.minimap.get_or_insert_default().show = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Window & Layout",
- items: vec![
- SettingsPageItem::SectionHeader("Status Bar"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Project Panel Button",
- description: "Show the project panel button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.button"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Display In",
+ description: "Where to show the minimap in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.display_in"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .minimap
+ .as_ref()?
+ .display_in
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .minimap
+ .get_or_insert_default()
+ .display_in = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Active Language Button",
- description: "Show the active language button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("status_bar.active_language_button"),
- pick: |settings_content| {
- settings_content
- .status_bar
- .as_ref()?
- .active_language_button
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .status_bar
- .get_or_insert_default()
- .active_language_button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Thumb",
+ description: "When to show the minimap thumb.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.thumb"),
+ pick: |settings_content| {
+ settings_content.editor.minimap.as_ref()?.thumb.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .minimap
+ .get_or_insert_default()
+ .thumb = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Active Encoding Button",
- description: "Control when to show the active encoding in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("status_bar.active_encoding_button"),
- pick: |settings_content| {
- settings_content
- .status_bar
- .as_ref()?
- .active_encoding_button
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .status_bar
- .get_or_insert_default()
- .active_encoding_button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Thumb Border",
+ description: "Border style for the minimap's scrollbar thumb.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.thumb_border"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .minimap
+ .as_ref()?
+ .thumb_border
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .minimap
+ .get_or_insert_default()
+ .thumb_border = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Cursor Position Button",
- description: "Show the cursor position button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("status_bar.cursor_position_button"),
- pick: |settings_content| {
- settings_content
- .status_bar
- .as_ref()?
- .cursor_position_button
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .status_bar
- .get_or_insert_default()
- .cursor_position_button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Current Line Highlight",
+ description: "How to highlight the current line in the minimap.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.current_line_highlight"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .minimap
+ .as_ref()
+ .and_then(|minimap| minimap.current_line_highlight.as_ref())
+ .or(settings_content.editor.current_line_highlight.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .minimap
+ .get_or_insert_default()
+ .current_line_highlight = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Terminal Button",
- description: "Show the terminal button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("terminal.button"),
- pick: |settings_content| {
- settings_content.terminal.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content.terminal.get_or_insert_default().button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Max Width Columns",
+ description: "Maximum number of columns to display in the minimap.",
+ field: Box::new(SettingField {
+ json_path: Some("minimap.max_width_columns"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .minimap
+ .as_ref()?
+ .max_width_columns
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .minimap
+ .get_or_insert_default()
+ .max_width_columns = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Diagnostics Button",
- description: "Show the project diagnostics button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("diagnostics.button"),
- pick: |settings_content| {
- settings_content.diagnostics.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content.diagnostics.get_or_insert_default().button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn toolbar_section() -> [SettingsPageItem; 6] {
+ [
+ SettingsPageItem::SectionHeader("Toolbar"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Breadcrumbs",
+ description: "Show breadcrumbs.",
+ field: Box::new(SettingField {
+ json_path: Some("toolbar.breadcrumbs"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .toolbar
+ .as_ref()?
+ .breadcrumbs
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .toolbar
+ .get_or_insert_default()
+ .breadcrumbs = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Project Search Button",
- description: "Show the project search button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("search.button"),
- pick: |settings_content| {
- settings_content.editor.search.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .editor
- .search
- .get_or_insert_default()
- .button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Quick Actions",
+ description: "Show quick action buttons (e.g., search, selection, editor controls, etc.).",
+ field: Box::new(SettingField {
+ json_path: Some("toolbar.quick_actions"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .toolbar
+ .as_ref()?
+ .quick_actions
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .toolbar
+ .get_or_insert_default()
+ .quick_actions = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Debugger Button",
- description: "Show the debugger button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("debugger.button"),
- pick: |settings_content| {
- settings_content.debugger.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content.debugger.get_or_insert_default().button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Selections Menu",
+ description: "Show the selections menu in the editor toolbar.",
+ field: Box::new(SettingField {
+ json_path: Some("toolbar.selections_menu"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .toolbar
+ .as_ref()?
+ .selections_menu
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .toolbar
+ .get_or_insert_default()
+ .selections_menu = value;
+ },
}),
- SettingsPageItem::SectionHeader("Title Bar"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Branch Icon",
- description: "Show the branch icon beside branch switcher in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_branch_icon"),
- pick: |settings_content| {
- settings_content
- .title_bar
- .as_ref()?
- .show_branch_icon
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_branch_icon = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Agent Review",
+ description: "Show agent review buttons in the editor toolbar.",
+ field: Box::new(SettingField {
+ json_path: Some("toolbar.agent_review"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .toolbar
+ .as_ref()?
+ .agent_review
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .toolbar
+ .get_or_insert_default()
+ .agent_review = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Branch Name",
- description: "Show the branch name button in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_branch_name"),
- pick: |settings_content| {
- settings_content
- .title_bar
- .as_ref()?
- .show_branch_name
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_branch_name = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Code Actions",
+ description: "Show code action buttons in the editor toolbar.",
+ field: Box::new(SettingField {
+ json_path: Some("toolbar.code_actions"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .toolbar
+ .as_ref()?
+ .code_actions
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .toolbar
+ .get_or_insert_default()
+ .code_actions = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Project Items",
- description: "Show the project host and name in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_project_items"),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ let items = concat_sections!(
+ auto_save_section(),
+ which_key_section(),
+ multibuffer_section(),
+ scrolling_section(),
+ signature_help_section(),
+ hover_popover_section(),
+ drag_and_drop_selection_section(),
+ gutter_section(),
+ scrollbar_section(),
+ minimap_section(),
+ toolbar_section(),
+ language_settings_data(),
+ );
+
+ SettingsPage {
+ title: "Editor",
+ items: items,
+ }
+}
+
+fn languages_and_tools_page(cx: &App) -> SettingsPage {
+ fn file_types_section() -> [SettingsPageItem; 2] {
+ [
+ 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 {
+ json_path: Some("file_type_associations"),
pick: |settings_content| {
- settings_content
- .title_bar
- .as_ref()?
- .show_project_items
- .as_ref()
+ settings_content.project.all_languages.file_types.as_ref()
},
write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_project_items = value;
+ settings_content.project.all_languages.file_types = value;
},
- }),
- metadata: None,
- files: USER,
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER | PROJECT,
+ }),
+ ]
+ }
+
+ fn diagnostics_section() -> [SettingsPageItem; 3] {
+ [
+ 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 {
+ json_path: Some("diagnostics_max_severity"),
+ pick: |settings_content| {
+ settings_content.editor.diagnostics_max_severity.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.diagnostics_max_severity = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Onboarding Banner",
- description: "Show banners announcing new features in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_onboarding_banner"),
- pick: |settings_content| {
- settings_content
- .title_bar
- .as_ref()?
- .show_onboarding_banner
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_onboarding_banner = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Include Warnings",
+ description: "Whether to show warnings or not by default.",
+ field: Box::new(SettingField {
+ json_path: Some("diagnostics.include_warnings"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .include_warnings
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .include_warnings = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Sign In",
- description: "Show the sign in button in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_sign_in"),
- pick: |settings_content| {
- settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_sign_in = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn inline_diagnostics_section() -> [SettingsPageItem; 5] {
+ [
+ SettingsPageItem::SectionHeader("Inline Diagnostics"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enabled",
+ description: "Whether to show diagnostics inline or not.",
+ field: Box::new(SettingField {
+ json_path: Some("diagnostics.inline.enabled"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .inline
+ .as_ref()?
+ .enabled
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .inline
+ .get_or_insert_default()
+ .enabled = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show User Menu",
- description: "Show the user menu button in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_user_menu"),
- pick: |settings_content| {
- settings_content.title_bar.as_ref()?.show_user_menu.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_user_menu = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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 {
+ json_path: Some("diagnostics.inline.update_debounce_ms"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .inline
+ .as_ref()?
+ .update_debounce_ms
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .inline
+ .get_or_insert_default()
+ .update_debounce_ms = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show User Picture",
- description: "Show user picture in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_user_picture"),
- pick: |settings_content| {
- settings_content
- .title_bar
- .as_ref()?
- .show_user_picture
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_user_picture = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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 {
+ json_path: Some("diagnostics.inline.padding"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .inline
+ .as_ref()?
+ .padding
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .inline
+ .get_or_insert_default()
+ .padding = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Menus",
- description: "Show the menus in the titlebar.",
- field: Box::new(SettingField {
- json_path: Some("title_bar.show_menus"),
- pick: |settings_content| {
- settings_content.title_bar.as_ref()?.show_menus.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .title_bar
- .get_or_insert_default()
- .show_menus = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Minimum Column",
+ description: "The minimum column at which to display inline diagnostics.",
+ field: Box::new(SettingField {
+ json_path: Some("diagnostics.inline.min_column"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .inline
+ .as_ref()?
+ .min_column
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .inline
+ .get_or_insert_default()
+ .min_column = value;
+ },
}),
- SettingsPageItem::SectionHeader("Tab Bar"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Tab Bar",
- description: "Show the tab bar in the editor.",
- field: Box::new(SettingField {
- json_path: Some("tab_bar.show"),
- pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
- write: |settings_content, value| {
- settings_content.tab_bar.get_or_insert_default().show = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn lsp_pull_diagnostics_section() -> [SettingsPageItem; 3] {
+ [
+ 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 {
+ json_path: Some("diagnostics.lsp_pull_diagnostics.enabled"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .lsp_pull_diagnostics
+ .as_ref()?
+ .enabled
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .lsp_pull_diagnostics
+ .get_or_insert_default()
+ .enabled = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Git Status In Tabs",
- description: "Show the Git file status on a tab item.",
- field: Box::new(SettingField {
- json_path: Some("tabs.git_status"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.git_status.as_ref()
- },
- write: |settings_content, value| {
- settings_content.tabs.get_or_insert_default().git_status = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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 {
+ json_path: Some("diagnostics.lsp_pull_diagnostics.debounce_ms"),
+ pick: |settings_content| {
+ settings_content
+ .diagnostics
+ .as_ref()?
+ .lsp_pull_diagnostics
+ .as_ref()?
+ .debounce_ms
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .diagnostics
+ .get_or_insert_default()
+ .lsp_pull_diagnostics
+ .get_or_insert_default()
+ .debounce_ms = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show File Icons In Tabs",
- description: "Show the file icon for a tab.",
- field: Box::new(SettingField {
- json_path: Some("tabs.file_icons"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.file_icons.as_ref()
- },
- write: |settings_content, value| {
- settings_content.tabs.get_or_insert_default().file_icons = value;
- },
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn lsp_highlights_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("LSP Highlights"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Debounce",
+ description: "The debounce delay before querying highlights from the language.",
+ field: Box::new(SettingField {
+ json_path: Some("lsp_highlight_debounce"),
+ pick: |settings_content| {
+ settings_content.editor.lsp_highlight_debounce.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.lsp_highlight_debounce = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn languages_list_section(cx: &App) -> Box<[SettingsPageItem]> {
+ // 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
+ std::iter::once(SettingsPageItem::SectionHeader(LANGUAGES_SECTION_HEADER))
+ .chain(all_language_names(cx).into_iter().map(|language_name| {
+ let link = format!("languages.{language_name}");
+ SettingsPageItem::SubPageLink(SubPageLink {
+ title: language_name,
+ description: None,
+ json_path: Some(link.leak()),
+ in_json: true,
+ files: USER | PROJECT,
+ render: Arc::new(|this, window, cx| {
+ let items: Box<[SettingsPageItem]> = concat_sections!(
+ language_settings_data(),
+ non_editor_language_settings_data(),
+ edit_prediction_language_settings_section()
+ );
+ this.render_sub_page_items(items.iter().enumerate(), None, window, cx)
+ .into_any_element()
}),
- metadata: None,
- files: USER,
+ })
+ }))
+ .collect()
+ }
+
+ SettingsPage {
+ title: "Languages & Tools",
+ items: {
+ concat_sections!(
+ non_editor_language_settings_data(),
+ file_types_section(),
+ diagnostics_section(),
+ inline_diagnostics_section(),
+ lsp_pull_diagnostics_section(),
+ lsp_highlights_section(),
+ languages_list_section(cx),
+ )
+ },
+ }
+}
+
+fn search_and_files_page() -> SettingsPage {
+ fn search_section() -> [SettingsPageItem; 9] {
+ [
+ SettingsPageItem::SectionHeader("Search"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Whole Word",
+ description: "Search for whole words by default.",
+ field: Box::new(SettingField {
+ json_path: Some("search.whole_word"),
+ pick: |settings_content| {
+ settings_content.editor.search.as_ref()?.whole_word.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .whole_word = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Case Sensitive",
+ description: "Search case-sensitively by default.",
+ field: Box::new(SettingField {
+ json_path: Some("search.case_sensitive"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .search
+ .as_ref()?
+ .case_sensitive
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .case_sensitive = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Tab Close Position",
- description: "Position of the close button in a tab.",
- field: Box::new(SettingField {
- json_path: Some("tabs.close_position"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.close_position.as_ref()
- },
- write: |settings_content, value| {
- settings_content.tabs.get_or_insert_default().close_position = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use Smartcase Search",
+ description: "Whether to automatically enable case-sensitive search based on the search query.",
+ field: Box::new(SettingField {
+ json_path: Some("use_smartcase_search"),
+ pick: |settings_content| settings_content.editor.use_smartcase_search.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.use_smartcase_search = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Maximum Tabs",
- description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
- // todo(settings_ui): The default for this value is null and it's use in code
- // is complex, so I'm going to come back to this later
- field: Box::new(
- SettingField {
- json_path: Some("max_tabs"),
- pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
- write: |settings_content, value| {
- settings_content.workspace.max_tabs = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Include Ignored",
+ description: "Include ignored files in search results by default.",
+ field: Box::new(SettingField {
+ json_path: Some("search.include_ignored"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .search
+ .as_ref()?
+ .include_ignored
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .include_ignored = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Navigation History Buttons",
- description: "Show the navigation history buttons in the tab bar.",
- field: Box::new(SettingField {
- json_path: Some("tab_bar.show_nav_history_buttons"),
- pick: |settings_content| {
- settings_content
- .tab_bar
- .as_ref()?
- .show_nav_history_buttons
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .tab_bar
- .get_or_insert_default()
- .show_nav_history_buttons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Regex",
+ description: "Use regex search by default.",
+ field: Box::new(SettingField {
+ json_path: Some("search.regex"),
+ pick: |settings_content| {
+ settings_content.editor.search.as_ref()?.regex.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.search.get_or_insert_default().regex = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Tab Bar Buttons",
- description: "Show the tab bar buttons (New, Split Pane, Zoom).",
- field: Box::new(SettingField {
- json_path: Some("tab_bar.show_tab_bar_buttons"),
- pick: |settings_content| {
- settings_content
- .tab_bar
- .as_ref()?
- .show_tab_bar_buttons
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .tab_bar
- .get_or_insert_default()
- .show_tab_bar_buttons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Search Wrap",
+ description: "Whether the editor search results will loop.",
+ field: Box::new(SettingField {
+ json_path: Some("search_wrap"),
+ pick: |settings_content| settings_content.editor.search_wrap.as_ref(),
+ write: |settings_content, value| {
+ settings_content.editor.search_wrap = value;
+ },
}),
- SettingsPageItem::SectionHeader("Tab Settings"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Activate On Close",
- description: "What to do after closing the current tab.",
- field: Box::new(SettingField {
- json_path: Some("tabs.activate_on_close"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.activate_on_close.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .tabs
- .get_or_insert_default()
- .activate_on_close = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Center on Match",
+ description: "Whether to center the current match in the editor",
+ field: Box::new(SettingField {
+ json_path: Some("editor.search.center_on_match"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .search
+ .as_ref()
+ .and_then(|search| search.center_on_match.as_ref())
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .center_on_match = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Tab Show Diagnostics",
- description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
- field: Box::new(SettingField {
- json_path: Some("tabs.show_diagnostics"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .tabs
- .get_or_insert_default()
- .show_diagnostics = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Seed Search Query From Cursor",
+ description: "When to populate a new search's query based on the text under the cursor.",
+ field: Box::new(SettingField {
+ json_path: Some("seed_search_query_from_cursor"),
+ pick: |settings_content| {
+ settings_content
+ .editor
+ .seed_search_query_from_cursor
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.editor.seed_search_query_from_cursor = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Close Button",
- description: "Controls the appearance behavior of the tab's close button.",
- field: Box::new(SettingField {
- json_path: Some("tabs.show_close_button"),
- pick: |settings_content| {
- settings_content.tabs.as_ref()?.show_close_button.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .tabs
- .get_or_insert_default()
- .show_close_button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn file_finder_section() -> [SettingsPageItem; 6] {
+ [
+ SettingsPageItem::SectionHeader("File Finder"),
+ // todo: null by default
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Include Ignored in Search",
+ description: "Use gitignored files when searching.",
+ field: Box::new(SettingField {
+ json_path: Some("file_finder.include_ignored"),
+ pick: |settings_content| {
+ settings_content
+ .file_finder
+ .as_ref()?
+ .include_ignored
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .file_finder
+ .get_or_insert_default()
+ .include_ignored = value;
+ },
}),
- SettingsPageItem::SectionHeader("Preview Tabs"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Preview Tabs Enabled",
- description: "Show opened editors as preview tabs.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enabled"),
- pick: |settings_content| {
- settings_content.preview_tabs.as_ref()?.enabled.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enabled = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "File Icons",
+ description: "Show file icons in the file finder.",
+ field: Box::new(SettingField {
+ json_path: Some("file_finder.file_icons"),
+ pick: |settings_content| {
+ settings_content.file_finder.as_ref()?.file_icons.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .file_finder
+ .get_or_insert_default()
+ .file_icons = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Preview From Project Panel",
- description: "Whether to open tabs in preview mode when opened from the project panel with a single click.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_preview_from_project_panel"),
- pick: |settings_content| {
- settings_content
- .preview_tabs
- .as_ref()?
- .enable_preview_from_project_panel
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_preview_from_project_panel = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Modal Max Width",
+ description: "Determines how much space the file finder can take up in relation to the available window width.",
+ field: Box::new(SettingField {
+ json_path: Some("file_finder.modal_max_width"),
+ pick: |settings_content| {
+ settings_content
+ .file_finder
+ .as_ref()?
+ .modal_max_width
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .file_finder
+ .get_or_insert_default()
+ .modal_max_width = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Preview From File Finder",
- description: "Whether to open tabs in preview mode when selected from the file finder.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_preview_from_file_finder"),
- pick: |settings_content| {
- settings_content
- .preview_tabs
- .as_ref()?
- .enable_preview_from_file_finder
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_preview_from_file_finder = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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.",
+ field: Box::new(SettingField {
+ json_path: Some("file_finder.skip_focus_for_active_in_search"),
+ pick: |settings_content| {
+ settings_content
+ .file_finder
+ .as_ref()?
+ .skip_focus_for_active_in_search
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .file_finder
+ .get_or_insert_default()
+ .skip_focus_for_active_in_search = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Preview From Multibuffer",
- description: "Whether to open tabs in preview mode when opened from a multibuffer.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_preview_from_multibuffer"),
- pick: |settings_content| {
- settings_content
- .preview_tabs
- .as_ref()?
- .enable_preview_from_multibuffer
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_preview_from_multibuffer = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Status",
+ description: "Show the Git status in the file finder.",
+ field: Box::new(SettingField {
+ json_path: Some("file_finder.git_status"),
+ pick: |settings_content| {
+ settings_content.file_finder.as_ref()?.git_status.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .file_finder
+ .get_or_insert_default()
+ .git_status = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Preview Multibuffer From Code Navigation",
- description: "Whether to open tabs in preview mode when code navigation is used to open a multibuffer.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_preview_multibuffer_from_code_navigation"),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn file_scan_section() -> [SettingsPageItem; 5] {
+ [
+ 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 {
+ json_path: Some("file_scan_exclusions"),
pick: |settings_content| {
settings_content
- .preview_tabs
- .as_ref()?
- .enable_preview_multibuffer_from_code_navigation
+ .project
+ .worktree
+ .file_scan_exclusions
.as_ref()
},
write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_preview_multibuffer_from_code_navigation = value;
+ settings_content.project.worktree.file_scan_exclusions = value;
},
- }),
- metadata: None,
- files: USER,
- }),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Preview File From Code Navigation",
- description: "Whether to open tabs in preview mode when code navigation is used to open a single file.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_preview_file_from_code_navigation"),
+ }
+ .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 {
+ json_path: Some("file_scan_inclusions"),
pick: |settings_content| {
settings_content
- .preview_tabs
- .as_ref()?
- .enable_preview_file_from_code_navigation
+ .project
+ .worktree
+ .file_scan_inclusions
.as_ref()
},
write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_preview_file_from_code_navigation = value;
+ settings_content.project.worktree.file_scan_inclusions = value;
},
- }),
- metadata: None,
- files: USER,
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Restore File State",
+ description: "Restore previous file state when reopening.",
+ field: Box::new(SettingField {
+ json_path: Some("restore_on_file_reopen"),
+ pick: |settings_content| {
+ settings_content.workspace.restore_on_file_reopen.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.restore_on_file_reopen = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Enable Keep Preview On Code Navigation",
- description: "Whether to keep tabs in preview mode when code navigation is used to navigate away from them. If `enable_preview_file_from_code_navigation` or `enable_preview_multibuffer_from_code_navigation` is also true, the new tab may replace the existing one.",
- field: Box::new(SettingField {
- json_path: Some("preview_tabs.enable_keep_preview_on_code_navigation"),
- pick: |settings_content| {
- settings_content
- .preview_tabs
- .as_ref()?
- .enable_keep_preview_on_code_navigation
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .preview_tabs
- .get_or_insert_default()
- .enable_keep_preview_on_code_navigation = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Close on File Delete",
+ description: "Automatically close files that have been deleted.",
+ field: Box::new(SettingField {
+ json_path: Some("close_on_file_delete"),
+ pick: |settings_content| {
+ settings_content.workspace.close_on_file_delete.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.close_on_file_delete = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ SettingsPage {
+ title: "Search & Files",
+ items: concat_sections![search_section(), file_finder_section(), file_scan_section()],
+ }
+}
+
+fn window_and_layout_page() -> SettingsPage {
+ fn status_bar_section() -> [SettingsPageItem; 9] {
+ [
+ SettingsPageItem::SectionHeader("Status Bar"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Project Panel Button",
+ description: "Show the project panel button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.button"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.button.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Active Language Button",
+ description: "Show the active language button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("status_bar.active_language_button"),
+ pick: |settings_content| {
+ settings_content
+ .status_bar
+ .as_ref()?
+ .active_language_button
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .status_bar
+ .get_or_insert_default()
+ .active_language_button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Active Encoding Button",
+ description: "Control when to show the active encoding in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("status_bar.active_encoding_button"),
+ pick: |settings_content| {
+ settings_content
+ .status_bar
+ .as_ref()?
+ .active_encoding_button
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .status_bar
+ .get_or_insert_default()
+ .active_encoding_button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Position Button",
+ description: "Show the cursor position button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("status_bar.cursor_position_button"),
+ pick: |settings_content| {
+ settings_content
+ .status_bar
+ .as_ref()?
+ .cursor_position_button
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .status_bar
+ .get_or_insert_default()
+ .cursor_position_button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Terminal Button",
+ description: "Show the terminal button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("terminal.button"),
+ pick: |settings_content| settings_content.terminal.as_ref()?.button.as_ref(),
+ write: |settings_content, value| {
+ settings_content.terminal.get_or_insert_default().button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Diagnostics Button",
+ description: "Show the project diagnostics button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("diagnostics.button"),
+ pick: |settings_content| settings_content.diagnostics.as_ref()?.button.as_ref(),
+ write: |settings_content, value| {
+ settings_content.diagnostics.get_or_insert_default().button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Project Search Button",
+ description: "Show the project search button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("search.button"),
+ pick: |settings_content| {
+ settings_content.editor.search.as_ref()?.button.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .editor
+ .search
+ .get_or_insert_default()
+ .button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Debugger Button",
+ description: "Show the debugger button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.button"),
+ pick: |settings_content| settings_content.debugger.as_ref()?.button.as_ref(),
+ write: |settings_content, value| {
+ settings_content.debugger.get_or_insert_default().button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn title_bar_section() -> [SettingsPageItem; 9] {
+ [
+ SettingsPageItem::SectionHeader("Title Bar"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Branch Icon",
+ description: "Show the branch icon beside branch switcher in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_branch_icon"),
+ pick: |settings_content| {
+ settings_content
+ .title_bar
+ .as_ref()?
+ .show_branch_icon
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_branch_icon = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Branch Name",
+ description: "Show the branch name button in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_branch_name"),
+ pick: |settings_content| {
+ settings_content
+ .title_bar
+ .as_ref()?
+ .show_branch_name
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_branch_name = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Project Items",
+ description: "Show the project host and name in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_project_items"),
+ pick: |settings_content| {
+ settings_content
+ .title_bar
+ .as_ref()?
+ .show_project_items
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_project_items = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Onboarding Banner",
+ description: "Show banners announcing new features in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_onboarding_banner"),
+ pick: |settings_content| {
+ settings_content
+ .title_bar
+ .as_ref()?
+ .show_onboarding_banner
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_onboarding_banner = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Sign In",
+ description: "Show the sign in button in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_sign_in"),
+ pick: |settings_content| {
+ settings_content.title_bar.as_ref()?.show_sign_in.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_sign_in = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show User Menu",
+ description: "Show the user menu button in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_user_menu"),
+ pick: |settings_content| {
+ settings_content.title_bar.as_ref()?.show_user_menu.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_user_menu = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show User Picture",
+ description: "Show user picture in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_user_picture"),
+ pick: |settings_content| {
+ settings_content
+ .title_bar
+ .as_ref()?
+ .show_user_picture
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_user_picture = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Menus",
+ description: "Show the menus in the titlebar.",
+ field: Box::new(SettingField {
+ json_path: Some("title_bar.show_menus"),
+ pick: |settings_content| {
+ settings_content.title_bar.as_ref()?.show_menus.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .title_bar
+ .get_or_insert_default()
+ .show_menus = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn tab_bar_section() -> [SettingsPageItem; 8] {
+ [
+ SettingsPageItem::SectionHeader("Tab Bar"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Tab Bar",
+ description: "Show the tab bar in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("tab_bar.show"),
+ pick: |settings_content| settings_content.tab_bar.as_ref()?.show.as_ref(),
+ write: |settings_content, value| {
+ settings_content.tab_bar.get_or_insert_default().show = value;
+ },
}),
- SettingsPageItem::SectionHeader("Layout"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Bottom Dock Layout",
- description: "Layout mode for the bottom dock.",
- field: Box::new(SettingField {
- json_path: Some("bottom_dock_layout"),
- pick: |settings_content| {
- settings_content.workspace.bottom_dock_layout.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.bottom_dock_layout = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Git Status In Tabs",
+ description: "Show the Git file status on a tab item.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.git_status"),
+ pick: |settings_content| settings_content.tabs.as_ref()?.git_status.as_ref(),
+ write: |settings_content, value| {
+ settings_content.tabs.get_or_insert_default().git_status = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Centered Layout Left Padding",
- description: "Left padding for centered layout.",
- field: Box::new(SettingField {
- json_path: Some("centered_layout.left_padding"),
- pick: |settings_content| {
- settings_content
- .workspace
- .centered_layout
- .as_ref()?
- .left_padding
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .workspace
- .centered_layout
- .get_or_insert_default()
- .left_padding = value;
- },
- }),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show File Icons In Tabs",
+ description: "Show the file icon for a tab.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.file_icons"),
+ pick: |settings_content| settings_content.tabs.as_ref()?.file_icons.as_ref(),
+ write: |settings_content, value| {
+ settings_content.tabs.get_or_insert_default().file_icons = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Centered Layout Right Padding",
- description: "Right padding for centered layout.",
- field: Box::new(SettingField {
- json_path: Some("centered_layout.right_padding"),
- pick: |settings_content| {
- settings_content
- .workspace
- .centered_layout
- .as_ref()?
- .right_padding
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .workspace
- .centered_layout
- .get_or_insert_default()
- .right_padding = value;
- },
- }),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Tab Close Position",
+ description: "Position of the close button in a tab.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.close_position"),
+ pick: |settings_content| {
+ settings_content.tabs.as_ref()?.close_position.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.tabs.get_or_insert_default().close_position = value;
+ },
}),
- SettingsPageItem::SectionHeader("Window"),
- // todo(settings_ui): Should we filter by platform.as_ref()?
- SettingsPageItem::SettingItem(SettingItem {
- title: "Use System Window Tabs",
- description: "(macOS only) whether to allow Windows to tab together.",
- field: Box::new(SettingField {
- json_path: Some("use_system_window_tabs"),
- pick: |settings_content| {
- settings_content.workspace.use_system_window_tabs.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.use_system_window_tabs = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Maximum Tabs",
+ description: "Maximum open tabs in a pane. Will not close an unsaved tab.",
+ // todo(settings_ui): The default for this value is null and it's use in code
+ // is complex, so I'm going to come back to this later
+ field: Box::new(
+ SettingField {
+ json_path: Some("max_tabs"),
+ pick: |settings_content| settings_content.workspace.max_tabs.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.max_tabs = value;
+ },
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Navigation History Buttons",
+ description: "Show the navigation history buttons in the tab bar.",
+ field: Box::new(SettingField {
+ json_path: Some("tab_bar.show_nav_history_buttons"),
+ pick: |settings_content| {
+ settings_content
+ .tab_bar
+ .as_ref()?
+ .show_nav_history_buttons
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .tab_bar
+ .get_or_insert_default()
+ .show_nav_history_buttons = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Window Decorations",
- description: "(Linux only) whether Zed or your compositor should draw window decorations.",
- field: Box::new(SettingField {
- json_path: Some("window_decorations"),
- pick: |settings_content| {
- settings_content.workspace.window_decorations.as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.window_decorations = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Tab Bar Buttons",
+ description: "Show the tab bar buttons (New, Split Pane, Zoom).",
+ field: Box::new(SettingField {
+ json_path: Some("tab_bar.show_tab_bar_buttons"),
+ pick: |settings_content| {
+ settings_content
+ .tab_bar
+ .as_ref()?
+ .show_tab_bar_buttons
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .tab_bar
+ .get_or_insert_default()
+ .show_tab_bar_buttons = value;
+ },
}),
- SettingsPageItem::SectionHeader("Pane Modifiers"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Inactive Opacity",
- description: "Opacity of inactive panels (0.0 - 1.0).",
- field: Box::new(SettingField {
- json_path: Some("active_pane_modifiers.inactive_opacity"),
- pick: |settings_content| {
- settings_content
- .workspace
- .active_pane_modifiers
- .as_ref()?
- .inactive_opacity
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .workspace
- .active_pane_modifiers
- .get_or_insert_default()
- .inactive_opacity = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn tab_settings_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Tab Settings"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Activate On Close",
+ description: "What to do after closing the current tab.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.activate_on_close"),
+ pick: |settings_content| {
+ settings_content.tabs.as_ref()?.activate_on_close.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .tabs
+ .get_or_insert_default()
+ .activate_on_close = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Border Size",
- description: "Size of the border surrounding the active pane.",
- field: Box::new(SettingField {
- json_path: Some("active_pane_modifiers.border_size"),
- pick: |settings_content| {
- settings_content
- .workspace
- .active_pane_modifiers
- .as_ref()?
- .border_size
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .workspace
- .active_pane_modifiers
- .get_or_insert_default()
- .border_size = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Tab Show Diagnostics",
+ description: "Which files containing diagnostic errors/warnings to mark in the tabs.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.show_diagnostics"),
+ pick: |settings_content| {
+ settings_content.tabs.as_ref()?.show_diagnostics.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .tabs
+ .get_or_insert_default()
+ .show_diagnostics = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Zoomed Padding",
- description: "Show padding for zoomed panes.",
- field: Box::new(SettingField {
- json_path: Some("zoomed_padding"),
- pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
- write: |settings_content, value| {
- settings_content.workspace.zoomed_padding = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Close Button",
+ description: "Controls the appearance behavior of the tab's close button.",
+ field: Box::new(SettingField {
+ json_path: Some("tabs.show_close_button"),
+ pick: |settings_content| {
+ settings_content.tabs.as_ref()?.show_close_button.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .tabs
+ .get_or_insert_default()
+ .show_close_button = value;
+ },
}),
- SettingsPageItem::SectionHeader("Pane Split Direction"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Vertical Split Direction",
- description: "Direction to split vertically.",
- field: Box::new(SettingField {
- json_path: Some("pane_split_direction_vertical"),
- pick: |settings_content| {
- settings_content
- .workspace
- .pane_split_direction_vertical
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.pane_split_direction_vertical = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn preview_tabs_section() -> [SettingsPageItem; 8] {
+ [
+ SettingsPageItem::SectionHeader("Preview Tabs"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Preview Tabs Enabled",
+ description: "Show opened editors as preview tabs.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enabled"),
+ pick: |settings_content| {
+ settings_content.preview_tabs.as_ref()?.enabled.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enabled = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Horizontal Split Direction",
- description: "Direction to split horizontally.",
- field: Box::new(SettingField {
- json_path: Some("pane_split_direction_horizontal"),
- pick: |settings_content| {
- settings_content
- .workspace
- .pane_split_direction_horizontal
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content.workspace.pane_split_direction_horizontal = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Preview From Project Panel",
+ description: "Whether to open tabs in preview mode when opened from the project panel with a single click.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_preview_from_project_panel"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_preview_from_project_panel
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_preview_from_project_panel = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Panels",
- items: vec![
- SettingsPageItem::SectionHeader("Project Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Project Panel Dock",
- description: "Where to dock the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.dock"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.dock.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project_panel.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Preview From File Finder",
+ description: "Whether to open tabs in preview mode when selected from the file finder.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_preview_from_file_finder"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_preview_from_file_finder
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_preview_from_file_finder = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Project Panel Default Width",
- description: "Default width of the project panel in pixels.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.default_width"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .default_width
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Preview From Multibuffer",
+ description: "Whether to open tabs in preview mode when opened from a multibuffer.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_preview_from_multibuffer"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_preview_from_multibuffer
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_preview_from_multibuffer = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Hide .gitignore",
- description: "Whether to hide the gitignore entries in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.hide_gitignore"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .hide_gitignore
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .hide_gitignore = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Preview Multibuffer From Code Navigation",
+ description: "Whether to open tabs in preview mode when code navigation is used to open a multibuffer.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_preview_multibuffer_from_code_navigation"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_preview_multibuffer_from_code_navigation
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_preview_multibuffer_from_code_navigation = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Entry Spacing",
- description: "Spacing between worktree entries in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.entry_spacing"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .entry_spacing
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .entry_spacing = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Preview File From Code Navigation",
+ description: "Whether to open tabs in preview mode when code navigation is used to open a single file.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_preview_file_from_code_navigation"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_preview_file_from_code_navigation
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_preview_file_from_code_navigation = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "File Icons",
- description: "Show file icons in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.file_icons"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.file_icons.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .file_icons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Enable Keep Preview On Code Navigation",
+ description: "Whether to keep tabs in preview mode when code navigation is used to navigate away from them. If `enable_preview_file_from_code_navigation` or `enable_preview_multibuffer_from_code_navigation` is also true, the new tab may replace the existing one.",
+ field: Box::new(SettingField {
+ json_path: Some("preview_tabs.enable_keep_preview_on_code_navigation"),
+ pick: |settings_content| {
+ settings_content
+ .preview_tabs
+ .as_ref()?
+ .enable_keep_preview_on_code_navigation
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .preview_tabs
+ .get_or_insert_default()
+ .enable_keep_preview_on_code_navigation = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Folder Icons",
- description: "Whether to show folder icons or chevrons for directories in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.folder_icons"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .folder_icons
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .folder_icons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn layout_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Layout"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Bottom Dock Layout",
+ description: "Layout mode for the bottom dock.",
+ field: Box::new(SettingField {
+ json_path: Some("bottom_dock_layout"),
+ pick: |settings_content| settings_content.workspace.bottom_dock_layout.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.bottom_dock_layout = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Status",
- description: "Show the Git status in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.git_status"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.git_status.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .git_status = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Centered Layout Left Padding",
+ description: "Left padding for centered layout.",
+ field: Box::new(SettingField {
+ json_path: Some("centered_layout.left_padding"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .centered_layout
+ .as_ref()?
+ .left_padding
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .workspace
+ .centered_layout
+ .get_or_insert_default()
+ .left_padding = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Indent Size",
- description: "Amount of indentation for nested items.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.indent_size"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .indent_size
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .indent_size = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Centered Layout Right Padding",
+ description: "Right padding for centered layout.",
+ field: Box::new(SettingField {
+ json_path: Some("centered_layout.right_padding"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .centered_layout
+ .as_ref()?
+ .right_padding
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .workspace
+ .centered_layout
+ .get_or_insert_default()
+ .right_padding = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Auto Reveal Entries",
- description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.auto_reveal_entries"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .auto_reveal_entries
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .auto_reveal_entries = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ }),
+ ]
+ }
+
+ fn window_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Window"),
+ // todo(settings_ui): Should we filter by platform.as_ref()?
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use System Window Tabs",
+ description: "(macOS only) whether to allow Windows to tab together.",
+ field: Box::new(SettingField {
+ json_path: Some("use_system_window_tabs"),
+ pick: |settings_content| {
+ settings_content.workspace.use_system_window_tabs.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.use_system_window_tabs = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Starts Open",
- description: "Whether the project panel should open on startup.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.starts_open"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .starts_open
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .starts_open = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Window Decorations",
+ description: "(Linux only) whether Zed or your compositor should draw window decorations.",
+ field: Box::new(SettingField {
+ json_path: Some("window_decorations"),
+ pick: |settings_content| settings_content.workspace.window_decorations.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.window_decorations = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Auto Fold Directories",
- description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.auto_fold_dirs"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .auto_fold_dirs
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .auto_fold_dirs = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn pane_modifiers_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Pane Modifiers"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Inactive Opacity",
+ description: "Opacity of inactive panels (0.0 - 1.0).",
+ field: Box::new(SettingField {
+ json_path: Some("active_pane_modifiers.inactive_opacity"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .active_pane_modifiers
+ .as_ref()?
+ .inactive_opacity
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .workspace
+ .active_pane_modifiers
+ .get_or_insert_default()
+ .inactive_opacity = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Scrollbar",
- description: "Show the scrollbar in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.scrollbar.show"),
- pick: |settings_content| {
- show_scrollbar_or_editor(settings_content, |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .scrollbar
- .as_ref()?
- .show
- .as_ref()
- })
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .scrollbar
- .get_or_insert_default()
- .show = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Border Size",
+ description: "Size of the border surrounding the active pane.",
+ field: Box::new(SettingField {
+ json_path: Some("active_pane_modifiers.border_size"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .active_pane_modifiers
+ .as_ref()?
+ .border_size
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .workspace
+ .active_pane_modifiers
+ .get_or_insert_default()
+ .border_size = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Show Diagnostics",
- description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.show_diagnostics"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .show_diagnostics
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .show_diagnostics = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Zoomed Padding",
+ description: "Show padding for zoomed panes.",
+ field: Box::new(SettingField {
+ json_path: Some("zoomed_padding"),
+ pick: |settings_content| settings_content.workspace.zoomed_padding.as_ref(),
+ write: |settings_content, value| {
+ settings_content.workspace.zoomed_padding = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Sticky Scroll",
- description: "Whether to stick parent directories at top of the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.sticky_scroll"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .sticky_scroll
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .sticky_scroll = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn pane_split_direction_section() -> [SettingsPageItem; 3] {
+ [
+ SettingsPageItem::SectionHeader("Pane Split Direction"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Vertical Split Direction",
+ description: "Direction to split vertically.",
+ field: Box::new(SettingField {
+ json_path: Some("pane_split_direction_vertical"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .pane_split_direction_vertical
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.pane_split_direction_vertical = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Show Indent Guides",
- description: "Show indent guides in the project panel.",
- field: Box::new(
- SettingField {
- json_path: Some("project_panel.indent_guides.show"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .indent_guides
- .as_ref()?
- .show
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .indent_guides
- .get_or_insert_default()
- .show = value;
- },
- }
- ),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Horizontal Split Direction",
+ description: "Direction to split horizontally.",
+ field: Box::new(SettingField {
+ json_path: Some("pane_split_direction_horizontal"),
+ pick: |settings_content| {
+ settings_content
+ .workspace
+ .pane_split_direction_horizontal
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.workspace.pane_split_direction_horizontal = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Drag and Drop",
- description: "Whether to enable drag-and-drop operations in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.drag_and_drop"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .drag_and_drop
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .drag_and_drop = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ SettingsPage {
+ title: "Window & Layout",
+ items: concat_sections![
+ status_bar_section(),
+ title_bar_section(),
+ tab_bar_section(),
+ tab_settings_section(),
+ preview_tabs_section(),
+ layout_section(),
+ window_section(),
+ pane_modifiers_section(),
+ pane_split_direction_section(),
+ ],
+ }
+}
+
+fn panels_page() -> SettingsPage {
+ fn project_panel_section() -> [SettingsPageItem; 20] {
+ [
+ SettingsPageItem::SectionHeader("Project Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Project Panel Dock",
+ description: "Where to dock the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.dock"),
+ pick: |settings_content| settings_content.project_panel.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.project_panel.get_or_insert_default().dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Hide Root",
- description: "Whether to hide the root entry when only one folder is open in the window.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.drag_and_drop"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.hide_root.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .hide_root = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Project Panel Default Width",
+ description: "Default width of the project panel in pixels.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.default_width"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .default_width
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .default_width = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Hide Hidden",
- description: "Whether to hide the hidden entries in the project panel.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.hide_hidden"),
- pick: |settings_content| {
- settings_content
- .project_panel
- .as_ref()?
- .hide_hidden
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .hide_hidden = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Hide .gitignore",
+ description: "Whether to hide the gitignore entries in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.hide_gitignore"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .hide_gitignore
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .hide_gitignore = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Hidden Files",
- description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
- field: Box::new(
- SettingField {
- json_path: Some("worktree.hidden_files"),
- pick: |settings_content| {
- settings_content.project.worktree.hidden_files.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project.worktree.hidden_files = value;
- },
- }
- .unimplemented(),
- ),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Entry Spacing",
+ description: "Spacing between worktree entries in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.entry_spacing"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .entry_spacing
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .entry_spacing = value;
+ },
}),
- SettingsPageItem::SectionHeader("Auto Open Files"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "On Create",
- description: "Whether to automatically open newly created files in the editor.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.auto_open.on_create"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_create.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_create = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "File Icons",
+ description: "Show file icons in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.file_icons"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.file_icons.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .file_icons = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "On Paste",
- description: "Whether to automatically open files after pasting or duplicating them.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.auto_open.on_paste"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_paste.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_paste = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Folder Icons",
+ description: "Whether to show folder icons or chevrons for directories in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.folder_icons"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .folder_icons
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .folder_icons = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "On Drop",
- description: "Whether to automatically open files dropped from external sources.",
- field: Box::new(SettingField {
- json_path: Some("project_panel.auto_open.on_drop"),
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.auto_open.as_ref()?.on_drop.as_ref()
- },
- write: |settings_content, value| {
- settings_content.project_panel.get_or_insert_default().auto_open.get_or_insert_default().on_drop = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Status",
+ description: "Show the Git status in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.git_status"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.git_status.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .git_status = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Sort Mode",
- description: "Sort order for entries in the project panel.",
- field: Box::new(SettingField {
- pick: |settings_content| {
- settings_content.project_panel.as_ref()?.sort_mode.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .project_panel
- .get_or_insert_default()
- .sort_mode = value;
- },
- json_path: Some("project_panel.sort_mode"),
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Indent Size",
+ description: "Amount of indentation for nested items.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.indent_size"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .indent_size
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .indent_size = value;
+ },
}),
- SettingsPageItem::SectionHeader("Terminal Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Terminal Dock",
- description: "Where to dock the terminal panel.",
- field: Box::new(SettingField {
- json_path: Some("terminal.dock"),
- pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
- write: |settings_content, value| {
- settings_content.terminal.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Reveal Entries",
+ description: "Whether to reveal entries in the project panel automatically when a corresponding project entry becomes active.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_reveal_entries"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .auto_reveal_entries
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .auto_reveal_entries = value;
+ },
}),
- SettingsPageItem::SectionHeader("Outline Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Outline Panel Button",
- description: "Show the outline panel button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.button"),
- pick: |settings_content| {
- settings_content.outline_panel.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Starts Open",
+ description: "Whether the project panel should open on startup.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.starts_open"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .starts_open
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .starts_open = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Outline Panel Dock",
- description: "Where to dock the outline panel.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.dock"),
- pick: |settings_content| {
- settings_content.outline_panel.as_ref()?.dock.as_ref()
- },
- write: |settings_content, value| {
- settings_content.outline_panel.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Fold Directories",
+ description: "Whether to fold directories automatically and show compact folders when a directory has only one subdirectory inside.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_fold_dirs"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .auto_fold_dirs
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .auto_fold_dirs = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Outline Panel Default Width",
- description: "Default width of the outline panel in pixels.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.default_width"),
- pick: |settings_content| {
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Scrollbar",
+ description: "Show the scrollbar in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.scrollbar.show"),
+ pick: |settings_content| {
+ show_scrollbar_or_editor(settings_content, |settings_content| {
settings_content
- .outline_panel
+ .project_panel
+ .as_ref()?
+ .scrollbar
.as_ref()?
- .default_width
+ .show
.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ })
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .scrollbar
+ .get_or_insert_default()
+ .show = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "File Icons",
- description: "Show file icons in the outline panel.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.file_icons"),
- pick: |settings_content| {
- settings_content.outline_panel.as_ref()?.file_icons.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .file_icons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Show Diagnostics",
+ description: "Which files containing diagnostic errors/warnings to mark in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.show_diagnostics"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .show_diagnostics
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .show_diagnostics = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Folder Icons",
- description: "Whether to show folder icons or chevrons for directories in the outline panel.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.folder_icons"),
- pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()?
- .folder_icons
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .folder_icons = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Sticky Scroll",
+ description: "Whether to stick parent directories at top of the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.sticky_scroll"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .sticky_scroll
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .sticky_scroll = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Status",
- description: "Show the Git status in the outline panel.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.git_status"),
- pick: |settings_content| {
- settings_content.outline_panel.as_ref()?.git_status.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .git_status = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Show Indent Guides",
+ description: "Show indent guides in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.indent_guides.show"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .indent_guides
+ .as_ref()?
+ .show
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .indent_guides
+ .get_or_insert_default()
+ .show = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Indent Size",
- description: "Amount of indentation for nested items.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.indent_size"),
- pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()?
- .indent_size
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .indent_size = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Drag and Drop",
+ description: "Whether to enable drag-and-drop operations in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.drag_and_drop"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .drag_and_drop
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .drag_and_drop = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Hide Root",
+ description: "Whether to hide the root entry when only one folder is open in the window.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.drag_and_drop"),
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.hide_root.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .hide_root = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Hide Hidden",
+ description: "Whether to hide the hidden entries in the project panel.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.hide_hidden"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .hide_hidden
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .hide_hidden = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Auto Reveal Entries",
- description: "Whether to reveal when a corresponding outline entry becomes active.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.auto_reveal_entries"),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Hidden Files",
+ description: "Globs to match files that will be considered \"hidden\" and can be hidden from the project panel.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("worktree.hidden_files"),
pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()?
- .auto_reveal_entries
- .as_ref()
+ settings_content.project.worktree.hidden_files.as_ref()
},
write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .auto_reveal_entries = value;
+ settings_content.project.worktree.hidden_files = value;
},
- }),
- metadata: None,
- files: USER,
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn auto_open_files_section() -> [SettingsPageItem; 5] {
+ [
+ SettingsPageItem::SectionHeader("Auto Open Files"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Create",
+ description: "Whether to automatically open newly created files in the editor.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_open.on_create"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .auto_open
+ .as_ref()?
+ .on_create
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .auto_open
+ .get_or_insert_default()
+ .on_create = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Auto Fold Directories",
- description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
- field: Box::new(SettingField {
- json_path: Some("outline_panel.auto_fold_dirs"),
- pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()?
- .auto_fold_dirs
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .auto_fold_dirs = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Paste",
+ description: "Whether to automatically open files after pasting or duplicating them.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_open.on_paste"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .auto_open
+ .as_ref()?
+ .on_paste
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .auto_open
+ .get_or_insert_default()
+ .on_paste = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- files: USER,
- title: "Show Indent Guides",
- description: "When to show indent guides in the outline panel.",
- field: Box::new(
- SettingField {
- json_path: Some("outline_panel.indent_guides.show"),
- pick: |settings_content| {
- settings_content
- .outline_panel
- .as_ref()?
- .indent_guides
- .as_ref()?
- .show
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .outline_panel
- .get_or_insert_default()
- .indent_guides
- .get_or_insert_default()
- .show = value;
- },
- }
- ),
- metadata: None,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "On Drop",
+ description: "Whether to automatically open files dropped from external sources.",
+ field: Box::new(SettingField {
+ json_path: Some("project_panel.auto_open.on_drop"),
+ pick: |settings_content| {
+ settings_content
+ .project_panel
+ .as_ref()?
+ .auto_open
+ .as_ref()?
+ .on_drop
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .auto_open
+ .get_or_insert_default()
+ .on_drop = value;
+ },
}),
- 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 {
- json_path: Some("git_panel.button"),
- pick: |settings_content| {
- settings_content.git_panel.as_ref()?.button.as_ref()
- },
- write: |settings_content, value| {
- settings_content.git_panel.get_or_insert_default().button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Sort Mode",
+ description: "Sort order for entries in the project panel.",
+ field: Box::new(SettingField {
+ pick: |settings_content| {
+ settings_content.project_panel.as_ref()?.sort_mode.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .project_panel
+ .get_or_insert_default()
+ .sort_mode = value;
+ },
+ json_path: Some("project_panel.sort_mode"),
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Panel Dock",
- description: "Where to dock the Git panel.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.dock"),
- pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
- write: |settings_content, value| {
- settings_content.git_panel.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn terminal_panel_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Terminal Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Terminal Dock",
+ description: "Where to dock the terminal panel.",
+ field: Box::new(SettingField {
+ json_path: Some("terminal.dock"),
+ pick: |settings_content| settings_content.terminal.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.terminal.get_or_insert_default().dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Panel Default Width",
- description: "Default width of the Git panel in pixels.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.default_width"),
- pick: |settings_content| {
- settings_content.git_panel.as_ref()?.default_width.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn outline_panel_section() -> [SettingsPageItem; 11] {
+ [
+ SettingsPageItem::SectionHeader("Outline Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Outline Panel Button",
+ description: "Show the outline panel button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.button"),
+ pick: |settings_content| {
+ settings_content.outline_panel.as_ref()?.button.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .button = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Git Panel Status Style",
- description: "How entry statuses are displayed.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.status_style"),
- pick: |settings_content| {
- settings_content.git_panel.as_ref()?.status_style.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .status_style = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Outline Panel Dock",
+ description: "Where to dock the outline panel.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.dock"),
+ pick: |settings_content| settings_content.outline_panel.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.outline_panel.get_or_insert_default().dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Fallback Branch Name",
- description: "Default branch name will be when init.defaultbranch is not set in Git.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.fallback_branch_name"),
- pick: |settings_content| {
- settings_content
- .git_panel
- .as_ref()?
- .fallback_branch_name
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .fallback_branch_name = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Outline Panel Default Width",
+ description: "Default width of the outline panel in pixels.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.default_width"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .default_width
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .default_width = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "File Icons",
+ description: "Show file icons in the outline panel.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.file_icons"),
+ pick: |settings_content| {
+ settings_content.outline_panel.as_ref()?.file_icons.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .file_icons = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Folder Icons",
+ description: "Whether to show folder icons or chevrons for directories in the outline panel.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.folder_icons"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .folder_icons
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .folder_icons = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Status",
+ description: "Show the Git status in the outline panel.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.git_status"),
+ pick: |settings_content| {
+ settings_content.outline_panel.as_ref()?.git_status.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .git_status = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Indent Size",
+ description: "Amount of indentation for nested items.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.indent_size"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .indent_size
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .indent_size = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Sort By Path",
- description: "Enable to sort entries in the panel by path, disable to sort by status.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.sort_by_path"),
- pick: |settings_content| {
- settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .sort_by_path = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Reveal Entries",
+ description: "Whether to reveal when a corresponding outline entry becomes active.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.auto_reveal_entries"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .auto_reveal_entries
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .auto_reveal_entries = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Collapse Untracked Diff",
- description: "Whether to collapse untracked files in the diff panel.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.collapse_untracked_diff"),
- pick: |settings_content| {
- settings_content
- .git_panel
- .as_ref()?
- .collapse_untracked_diff
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .collapse_untracked_diff = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Auto Fold Directories",
+ description: "Whether to fold directories automatically when a directory contains only one subdirectory.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.auto_fold_dirs"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .auto_fold_dirs
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .auto_fold_dirs = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Tree View",
- description: "Enable to show entries in tree view list, disable to show in flat view list.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.tree_view"),
- pick: |settings_content| {
- settings_content.git_panel.as_ref()?.tree_view.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .tree_view = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ files: USER,
+ title: "Show Indent Guides",
+ description: "When to show indent guides in the outline panel.",
+ field: Box::new(SettingField {
+ json_path: Some("outline_panel.indent_guides.show"),
+ pick: |settings_content| {
+ settings_content
+ .outline_panel
+ .as_ref()?
+ .indent_guides
+ .as_ref()?
+ .show
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .outline_panel
+ .get_or_insert_default()
+ .indent_guides
+ .get_or_insert_default()
+ .show = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Scroll Bar",
- description: "How and when the scrollbar should be displayed.",
- field: Box::new(SettingField {
- json_path: Some("git_panel.scrollbar.show"),
- pick: |settings_content| {
- show_scrollbar_or_editor(settings_content, |settings_content| {
- settings_content
- .git_panel
- .as_ref()?
- .scrollbar
- .as_ref()?
- .show
- .as_ref()
- })
- },
- write: |settings_content, value| {
- settings_content
- .git_panel
- .get_or_insert_default()
- .scrollbar
- .get_or_insert_default()
- .show = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ }),
+ ]
+ }
+
+ fn git_panel_section() -> [SettingsPageItem; 10] {
+ [
+ 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 {
+ json_path: Some("git_panel.button"),
+ pick: |settings_content| settings_content.git_panel.as_ref()?.button.as_ref(),
+ write: |settings_content, value| {
+ settings_content.git_panel.get_or_insert_default().button = value;
+ },
}),
- SettingsPageItem::SectionHeader("Debugger Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Debugger Panel Dock",
- description: "The dock position of the debug panel.",
- field: Box::new(SettingField {
- json_path: Some("debugger.dock"),
- pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
- write: |settings_content, value| {
- settings_content.debugger.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Panel Dock",
+ description: "Where to dock the Git panel.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.dock"),
+ pick: |settings_content| settings_content.git_panel.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.git_panel.get_or_insert_default().dock = value;
+ },
}),
- SettingsPageItem::SectionHeader("Notification Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Notification Panel Button",
- description: "Show the notification panel button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("notification_panel.button"),
- pick: |settings_content| {
- settings_content
- .notification_panel
- .as_ref()?
- .button
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .notification_panel
- .get_or_insert_default()
- .button = value;
- },
- }),
- metadata: None,
- files: USER,
+ 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 {
+ json_path: Some("git_panel.default_width"),
+ pick: |settings_content| {
+ settings_content.git_panel.as_ref()?.default_width.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .default_width = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Notification Panel Dock",
- description: "Where to dock the notification panel.",
- field: Box::new(SettingField {
- json_path: Some("notification_panel.dock"),
- pick: |settings_content| {
- settings_content.notification_panel.as_ref()?.dock.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .notification_panel
- .get_or_insert_default()
- .dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Git Panel Status Style",
+ description: "How entry statuses are displayed.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.status_style"),
+ pick: |settings_content| {
+ settings_content.git_panel.as_ref()?.status_style.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .status_style = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Notification Panel Default Width",
- description: "Default width of the notification panel in pixels.",
- field: Box::new(SettingField {
- json_path: Some("notification_panel.default_width"),
- pick: |settings_content| {
- settings_content
- .notification_panel
- .as_ref()?
- .default_width
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .notification_panel
- .get_or_insert_default()
- .default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Fallback Branch Name",
+ description: "Default branch name will be when init.defaultbranch is not set in Git.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.fallback_branch_name"),
+ pick: |settings_content| {
+ settings_content
+ .git_panel
+ .as_ref()?
+ .fallback_branch_name
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .fallback_branch_name = value;
+ },
}),
- SettingsPageItem::SectionHeader("Collaboration Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Collaboration Panel Button",
- description: "Show the collaboration panel button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("collaboration_panel.button"),
- pick: |settings_content| {
- settings_content
- .collaboration_panel
- .as_ref()?
- .button
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .collaboration_panel
- .get_or_insert_default()
- .button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Sort By Path",
+ description: "Enable to sort entries in the panel by path, disable to sort by status.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.sort_by_path"),
+ pick: |settings_content| {
+ settings_content.git_panel.as_ref()?.sort_by_path.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .sort_by_path = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Collaboration Panel Dock",
- description: "Where to dock the collaboration panel.",
- field: Box::new(SettingField {
- json_path: Some("collaboration_panel.dock"),
- pick: |settings_content| {
- settings_content.collaboration_panel.as_ref()?.dock.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .collaboration_panel
- .get_or_insert_default()
- .dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Collapse Untracked Diff",
+ description: "Whether to collapse untracked files in the diff panel.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.collapse_untracked_diff"),
+ pick: |settings_content| {
+ settings_content
+ .git_panel
+ .as_ref()?
+ .collapse_untracked_diff
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .collapse_untracked_diff = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Collaboration Panel Default Width",
- description: "Default width of the collaboration panel in pixels.",
- field: Box::new(SettingField {
- json_path: Some("collaboration_panel.dock"),
- pick: |settings_content| {
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Tree View",
+ description: "Enable to show entries in tree view list, disable to show in flat view list.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.tree_view"),
+ pick: |settings_content| {
+ settings_content.git_panel.as_ref()?.tree_view.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.git_panel.get_or_insert_default().tree_view = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Scroll Bar",
+ description: "How and when the scrollbar should be displayed.",
+ field: Box::new(SettingField {
+ json_path: Some("git_panel.scrollbar.show"),
+ pick: |settings_content| {
+ show_scrollbar_or_editor(settings_content, |settings_content| {
settings_content
- .collaboration_panel
+ .git_panel
.as_ref()?
- .default_width
+ .scrollbar
+ .as_ref()?
+ .show
.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .collaboration_panel
- .get_or_insert_default()
- .default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ })
+ },
+ write: |settings_content, value| {
+ settings_content
+ .git_panel
+ .get_or_insert_default()
+ .scrollbar
+ .get_or_insert_default()
+ .show = value;
+ },
}),
- SettingsPageItem::SectionHeader("Agent Panel"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Agent Panel Button",
- description: "Whether to show the agent panel button in the status bar.",
- field: Box::new(SettingField {
- json_path: Some("agent.button"),
- pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
- write: |settings_content, value| {
- settings_content.agent.get_or_insert_default().button = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn debugger_panel_section() -> [SettingsPageItem; 2] {
+ [
+ SettingsPageItem::SectionHeader("Debugger Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Debugger Panel Dock",
+ description: "The dock position of the debug panel.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.dock"),
+ pick: |settings_content| settings_content.debugger.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.debugger.get_or_insert_default().dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Agent Panel Dock",
- description: "Where to dock the agent panel.",
- field: Box::new(SettingField {
- json_path: Some("agent.dock"),
- pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
- write: |settings_content, value| {
- settings_content.agent.get_or_insert_default().dock = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn notification_panel_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Notification Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Notification Panel Button",
+ description: "Show the notification panel button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("notification_panel.button"),
+ pick: |settings_content| {
+ settings_content
+ .notification_panel
+ .as_ref()?
+ .button
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .notification_panel
+ .get_or_insert_default()
+ .button = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Agent Panel Default Width",
- description: "Default width when the agent panel is docked to the left or right.",
- field: Box::new(SettingField {
- json_path: Some("agent.default_width"),
- pick: |settings_content| {
- settings_content.agent.as_ref()?.default_width.as_ref()
- },
- write: |settings_content, value| {
- settings_content.agent.get_or_insert_default().default_width = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Notification Panel Dock",
+ description: "Where to dock the notification panel.",
+ field: Box::new(SettingField {
+ json_path: Some("notification_panel.dock"),
+ pick: |settings_content| {
+ settings_content.notification_panel.as_ref()?.dock.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .notification_panel
+ .get_or_insert_default()
+ .dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Agent Panel Default Height",
- description: "Default height when the agent panel is docked to the bottom.",
- field: Box::new(SettingField {
- json_path: Some("agent.default_height"),
- pick: |settings_content| {
- settings_content.agent.as_ref()?.default_height.as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .agent
- .get_or_insert_default()
- .default_height = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Notification Panel Default Width",
+ description: "Default width of the notification panel in pixels.",
+ field: Box::new(SettingField {
+ json_path: Some("notification_panel.default_width"),
+ pick: |settings_content| {
+ settings_content
+ .notification_panel
+ .as_ref()?
+ .default_width
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .notification_panel
+ .get_or_insert_default()
+ .default_width = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Debugger",
- items: vec![
- SettingsPageItem::SectionHeader("General"),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Stepping Granularity",
- description: "Determines the stepping granularity for debug operations.",
- field: Box::new(SettingField {
- json_path: Some("debugger.stepping_granularity"),
- pick: |settings_content| {
- settings_content
- .debugger
- .as_ref()?
- .stepping_granularity
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .debugger
- .get_or_insert_default()
- .stepping_granularity = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn collaboration_panel_section() -> [SettingsPageItem; 4] {
+ [
+ SettingsPageItem::SectionHeader("Collaboration Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Collaboration Panel Button",
+ description: "Show the collaboration panel button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("collaboration_panel.button"),
+ pick: |settings_content| {
+ settings_content
+ .collaboration_panel
+ .as_ref()?
+ .button
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .collaboration_panel
+ .get_or_insert_default()
+ .button = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Save Breakpoints",
- description: "Whether breakpoints should be reused across Zed sessions.",
- field: Box::new(SettingField {
- json_path: Some("debugger.save_breakpoints"),
- pick: |settings_content| {
- settings_content
- .debugger
- .as_ref()?
- .save_breakpoints
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .debugger
- .get_or_insert_default()
- .save_breakpoints = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Collaboration Panel Dock",
+ description: "Where to dock the collaboration panel.",
+ field: Box::new(SettingField {
+ json_path: Some("collaboration_panel.dock"),
+ pick: |settings_content| {
+ settings_content.collaboration_panel.as_ref()?.dock.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .collaboration_panel
+ .get_or_insert_default()
+ .dock = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Timeout",
- description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
- field: Box::new(SettingField {
- json_path: Some("debugger.timeout"),
- pick: |settings_content| {
- settings_content.debugger.as_ref()?.timeout.as_ref()
- },
- write: |settings_content, value| {
- settings_content.debugger.get_or_insert_default().timeout = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Collaboration Panel Default Width",
+ description: "Default width of the collaboration panel in pixels.",
+ field: Box::new(SettingField {
+ json_path: Some("collaboration_panel.dock"),
+ pick: |settings_content| {
+ settings_content
+ .collaboration_panel
+ .as_ref()?
+ .default_width
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .collaboration_panel
+ .get_or_insert_default()
+ .default_width = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Log DAP Communications",
- description: "Whether to log messages between active debug adapters and Zed.",
- field: Box::new(SettingField {
- json_path: Some("debugger.log_dap_communications"),
- pick: |settings_content| {
- settings_content
- .debugger
- .as_ref()?
- .log_dap_communications
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .debugger
- .get_or_insert_default()
- .log_dap_communications = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ fn agent_panel_section() -> [SettingsPageItem; 5] {
+ [
+ SettingsPageItem::SectionHeader("Agent Panel"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Agent Panel Button",
+ description: "Whether to show the agent panel button in the status bar.",
+ field: Box::new(SettingField {
+ json_path: Some("agent.button"),
+ pick: |settings_content| settings_content.agent.as_ref()?.button.as_ref(),
+ write: |settings_content, value| {
+ settings_content.agent.get_or_insert_default().button = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Agent Panel Dock",
+ description: "Where to dock the agent panel.",
+ field: Box::new(SettingField {
+ json_path: Some("agent.dock"),
+ pick: |settings_content| settings_content.agent.as_ref()?.dock.as_ref(),
+ write: |settings_content, value| {
+ settings_content.agent.get_or_insert_default().dock = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Agent Panel Default Width",
+ description: "Default width when the agent panel is docked to the left or right.",
+ field: Box::new(SettingField {
+ json_path: Some("agent.default_width"),
+ pick: |settings_content| {
+ settings_content.agent.as_ref()?.default_width.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.agent.get_or_insert_default().default_width = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Agent Panel Default Height",
+ description: "Default height when the agent panel is docked to the bottom.",
+ field: Box::new(SettingField {
+ json_path: Some("agent.default_height"),
+ pick: |settings_content| {
+ settings_content.agent.as_ref()?.default_height.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .agent
+ .get_or_insert_default()
+ .default_height = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ SettingsPage {
+ title: "Panels",
+ items: concat_sections![
+ project_panel_section(),
+ auto_open_files_section(),
+ terminal_panel_section(),
+ outline_panel_section(),
+ git_panel_section(),
+ debugger_panel_section(),
+ notification_panel_section(),
+ collaboration_panel_section(),
+ agent_panel_section(),
+ ],
+ }
+}
+
+fn debugger_page() -> SettingsPage {
+ fn general_section() -> [SettingsPageItem; 6] {
+ [
+ SettingsPageItem::SectionHeader("General"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Stepping Granularity",
+ description: "Determines the stepping granularity for debug operations.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.stepping_granularity"),
+ pick: |settings_content| {
+ settings_content
+ .debugger
+ .as_ref()?
+ .stepping_granularity
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .debugger
+ .get_or_insert_default()
+ .stepping_granularity = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Save Breakpoints",
+ description: "Whether breakpoints should be reused across Zed sessions.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.save_breakpoints"),
+ pick: |settings_content| {
+ settings_content
+ .debugger
+ .as_ref()?
+ .save_breakpoints
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .debugger
+ .get_or_insert_default()
+ .save_breakpoints = value;
+ },
}),
- SettingsPageItem::SettingItem(SettingItem {
- title: "Format DAP Log Messages",
- description: "Whether to format DAP messages when adding them to debug adapter logger.",
- field: Box::new(SettingField {
- json_path: Some("debugger.format_dap_log_messages"),
- pick: |settings_content| {
- settings_content
- .debugger
- .as_ref()?
- .format_dap_log_messages
- .as_ref()
- },
- write: |settings_content, value| {
- settings_content
- .debugger
- .get_or_insert_default()
- .format_dap_log_messages = value;
- },
- }),
- metadata: None,
- files: USER,
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Timeout",
+ description: "Time in milliseconds until timeout error when connecting to a TCP debug adapter.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.timeout"),
+ pick: |settings_content| settings_content.debugger.as_ref()?.timeout.as_ref(),
+ write: |settings_content, value| {
+ settings_content.debugger.get_or_insert_default().timeout = value;
+ },
}),
- ],
- },
- SettingsPage {
- title: "Terminal",
- items: vec![
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Log DAP Communications",
+ description: "Whether to log messages between active debug adapters and Zed.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.log_dap_communications"),
+ pick: |settings_content| {
+ settings_content
+ .debugger
+ .as_ref()?
+ .log_dap_communications
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .debugger
+ .get_or_insert_default()
+ .log_dap_communications = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Format DAP Log Messages",
+ description: "Whether to format DAP messages when adding them to debug adapter logger.",
+ field: Box::new(SettingField {
+ json_path: Some("debugger.format_dap_log_messages"),
+ pick: |settings_content| {
+ settings_content
+ .debugger
+ .as_ref()?
+ .format_dap_log_messages
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .debugger
+ .get_or_insert_default()
+ .format_dap_log_messages = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
+ SettingsPage {
+ title: "Debugger",
+ items: concat_sections![general_section()],
+ }
+}
+
+fn terminal_page() -> SettingsPage {
+ fn environment_section() -> [SettingsPageItem; 5] {
+ [
SettingsPageItem::SectionHeader("Environment"),
SettingsPageItem::DynamicItem(DynamicItem {
discriminant: SettingItem {