Detailed changes
@@ -116,27 +116,30 @@ impl Drop for MacOsUnmounter {
}
}
-struct AutoUpdateSetting(bool);
-
/// Whether or not to automatically check for updates.
-///
-/// Default: true
-#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
+#[derive(Clone, Copy, JsonSchema, Deserialize, Serialize)]
+#[serde(default)]
#[serde(transparent)]
-struct AutoUpdateSettingContent(bool);
+struct AutoUpdateSetting(bool);
+
+impl Default for AutoUpdateSetting {
+ fn default() -> Self {
+ Self(true)
+ }
+}
impl Settings for AutoUpdateSetting {
const KEY: Option<&'static str> = Some("auto_update");
- type FileContent = Option<AutoUpdateSettingContent>;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
let auto_update = [sources.release_channel, sources.user]
.into_iter()
- .find_map(|value| value.copied().flatten())
- .unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
+ .find_map(|value| value.copied())
+ .unwrap_or(*sources.default);
- Ok(Self(auto_update.0))
+ Ok(auto_update)
}
}
@@ -4,30 +4,20 @@ use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Deserialize, Debug)]
-pub struct CallSettings {
- pub mute_on_join: bool,
- pub share_on_join: bool,
-}
-
/// Configuration of voice calls in Zed.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct CallSettingsContent {
+#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)]
+#[serde(default)]
+pub struct CallSettings {
/// Whether the microphone should be muted when joining a channel or a call.
- ///
- /// Default: false
- pub mute_on_join: Option<bool>,
-
+ pub mute_on_join: bool,
/// Whether your current project should be shared when joining an empty channel.
- ///
- /// Default: true
- pub share_on_join: Option<bool>,
+ pub share_on_join: bool,
}
impl Settings for CallSettings {
const KEY: Option<&'static str> = Some("calls");
- type FileContent = CallSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -99,20 +99,26 @@ pub const CONNECTION_TIMEOUT: Duration = Duration::from_secs(20);
actions!(client, [SignIn, SignOut, Reconnect]);
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct ClientSettingsContent {
- server_url: Option<String>,
-}
-
-#[derive(Deserialize)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct ClientSettings {
+ /// The server to connect to. If the environment variable
+ /// ZED_SERVER_URL is set, it will override this setting.
pub server_url: String,
}
+impl Default for ClientSettings {
+ fn default() -> Self {
+ Self {
+ server_url: "https://zed.dev".to_owned(),
+ }
+ }
+}
+
impl Settings for ClientSettings {
const KEY: Option<&'static str> = None;
- type FileContent = ClientSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
let mut result = sources.json_merge::<Self>()?;
@@ -124,19 +130,37 @@ impl Settings for ClientSettings {
}
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema)]
-pub struct ProxySettingsContent {
- proxy: Option<String>,
-}
-
-#[derive(Deserialize, Default)]
+#[serde(default)]
pub struct ProxySettings {
+ /// Set a proxy to use. The proxy protocol is specified by the URI scheme.
+ ///
+ /// Supported URI scheme: `http`, `https`, `socks4`, `socks4a`, `socks5`,
+ /// `socks5h`. `http` will be used when no scheme is specified.
+ ///
+ /// By default no proxy will be used, or Zed will try get proxy settings from
+ /// environment variables.
+ ///
+ /// Examples:
+ /// - "proxy": "socks5://localhost:10808"
+ /// - "proxy": "http://127.0.0.1:10809"
+ #[schemars(example = "Self::example_1")]
+ #[schemars(example = "Self::example_2")]
pub proxy: Option<String>,
}
+impl ProxySettings {
+ fn example_1() -> String {
+ "http://127.0.0.1:10809".to_owned()
+ }
+ fn example_2() -> String {
+ "socks5://localhost:10808".to_owned()
+ }
+}
+
impl Settings for ProxySettings {
const KEY: Option<&'static str> = None;
- type FileContent = ProxySettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
Ok(Self {
@@ -2261,11 +2261,11 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
cx_a.update(editor::init);
cx_b.update(editor::init);
// Turn inline-blame-off by default so no state is transferred without us explicitly doing so
- let inline_blame_off_settings = Some(InlineBlameSettings {
+ let inline_blame_off_settings = InlineBlameSettings {
enabled: false,
- delay_ms: None,
- min_column: None,
- });
+ delay_ms: 0,
+ min_column: 0,
+ };
cx_a.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
store.update_user_settings::<ProjectSettings>(cx, |settings| {
@@ -1649,7 +1649,7 @@ async fn test_following_into_excluded_file(
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |settings| {
- settings.file_scan_exclusions = Some(vec!["**/.git".to_string()]);
+ settings.file_scan_exclusions = vec!["**/.git".to_string()];
});
});
});
@@ -1108,7 +1108,7 @@ impl Panel for ChatPanel {
settings::update_settings_file::<ChatPanelSettings>(
self.fs.clone(),
cx,
- move |settings, _| settings.dock = Some(position),
+ move |settings, _| settings.dock = position,
);
}
@@ -113,9 +113,7 @@ impl MessageEditor {
editor.set_show_indent_guides(false, cx);
editor.set_completion_provider(Box::new(MessageEditorCompletionProvider(this)));
editor.set_auto_replace_emoji_shortcode(
- MessageEditorSettings::get_global(cx)
- .auto_replace_emoji_shortcode
- .unwrap_or_default(),
+ MessageEditorSettings::get_global(cx).auto_replace_emoji_shortcode,
);
});
@@ -130,9 +128,7 @@ impl MessageEditor {
cx.observe_global::<settings::SettingsStore>(|view, cx| {
view.editor.update(cx, |editor, cx| {
editor.set_auto_replace_emoji_shortcode(
- MessageEditorSettings::get_global(cx)
- .auto_replace_emoji_shortcode
- .unwrap_or_default(),
+ MessageEditorSettings::get_global(cx).auto_replace_emoji_shortcode,
)
})
})
@@ -2813,7 +2813,7 @@ impl Panel for CollabPanel {
settings::update_settings_file::<CollaborationPanelSettings>(
self.fs.clone(),
cx,
- move |settings, _| settings.dock = Some(position),
+ move |settings, _| settings.dock = position,
);
}
@@ -672,7 +672,7 @@ impl Panel for NotificationPanel {
settings::update_settings_file::<NotificationPanelSettings>(
self.fs.clone(),
cx,
- move |settings, _| settings.dock = Some(position),
+ move |settings, _| settings.dock = position,
);
}
@@ -2,58 +2,84 @@ use gpui::Pixels;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
+use ui::px;
use workspace::dock::DockPosition;
-#[derive(Deserialize, Debug)]
+#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
+#[serde(default)]
pub struct CollaborationPanelSettings {
+ /// Whether to show the panel button in the status bar.
pub button: bool,
+ /// Where to dock the panel.
pub dock: DockPosition,
+ /// Default width of the panel in pixels.
pub default_width: Pixels,
}
-#[derive(Deserialize, Debug)]
+impl Default for CollaborationPanelSettings {
+ fn default() -> Self {
+ Self {
+ button: true,
+ dock: DockPosition::Left,
+ default_width: px(240.),
+ }
+ }
+}
+
+#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
+#[serde(default)]
pub struct ChatPanelSettings {
+ /// Whether to show the panel button in the status bar.
pub button: bool,
+ /// Where to dock the panel.
pub dock: DockPosition,
+ /// Default width of the panel in pixels.
pub default_width: Pixels,
}
-#[derive(Deserialize, Debug)]
+impl Default for ChatPanelSettings {
+ fn default() -> Self {
+ Self {
+ button: true,
+ dock: DockPosition::Right,
+ default_width: px(240.),
+ }
+ }
+}
+
+#[derive(Clone, Deserialize, Debug, JsonSchema, Serialize)]
+#[serde(default)]
pub struct NotificationPanelSettings {
+ /// Whether to show the panel button in the status bar.
pub button: bool,
+ /// Where to dock the panel.
pub dock: DockPosition,
+ /// Default width of the panel in pixels.
pub default_width: Pixels,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct PanelSettingsContent {
- /// Whether to show the panel button in the status bar.
- ///
- /// Default: true
- pub button: Option<bool>,
- /// Where to dock the panel.
- ///
- /// Default: left
- pub dock: Option<DockPosition>,
- /// Default width of the panel in pixels.
- ///
- /// Default: 240
- pub default_width: Option<f32>,
+impl Default for NotificationPanelSettings {
+ fn default() -> Self {
+ Self {
+ button: true,
+ dock: DockPosition::Right,
+ default_width: px(380.),
+ }
+ }
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
+#[serde(default)]
pub struct MessageEditorSettings {
/// Whether to automatically replace emoji shortcodes with emoji characters.
/// For example: typing `:wave:` gets replaced with `👋`.
- ///
- /// Default: false
- pub auto_replace_emoji_shortcode: Option<bool>,
+ pub auto_replace_emoji_shortcode: bool,
}
impl Settings for CollaborationPanelSettings {
const KEY: Option<&'static str> = Some("collaboration_panel");
- type FileContent = PanelSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -66,7 +92,7 @@ impl Settings for CollaborationPanelSettings {
impl Settings for ChatPanelSettings {
const KEY: Option<&'static str> = Some("chat_panel");
- type FileContent = PanelSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -79,7 +105,7 @@ impl Settings for ChatPanelSettings {
impl Settings for NotificationPanelSettings {
const KEY: Option<&'static str> = Some("notification_panel");
- type FileContent = PanelSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -92,7 +118,7 @@ impl Settings for NotificationPanelSettings {
impl Settings for MessageEditorSettings {
const KEY: Option<&'static str> = Some("message_editor");
- type FileContent = MessageEditorSettings;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -4,23 +4,25 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Deserialize, Debug)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
+#[serde(default)]
+/// Diagnostics configuration.
pub struct ProjectDiagnosticsSettings {
+ /// Whether to show warnings or not by default.
pub include_warnings: bool,
}
-/// Diagnostics configuration.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct ProjectDiagnosticsSettingsContent {
- /// Whether to show warnings or not by default.
- ///
- /// Default: true
- include_warnings: Option<bool>,
+impl Default for ProjectDiagnosticsSettings {
+ fn default() -> Self {
+ Self {
+ include_warnings: true,
+ }
+ }
}
impl Settings for ProjectDiagnosticsSettings {
const KEY: Option<&'static str> = Some("diagnostics");
- type FileContent = ProjectDiagnosticsSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -10639,7 +10639,7 @@ impl Editor {
let fs = workspace.read(cx).app_state().fs.clone();
let current_show = TabBarSettings::get_global(cx).show;
update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
- setting.show = Some(!current_show);
+ setting.show = !current_show;
});
}
@@ -12562,7 +12562,7 @@ impl EditorSnapshot {
let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
matches!(
ProjectSettings::get_global(cx).git.git_gutter,
- Some(GitGutterSetting::TrackedFiles)
+ GitGutterSetting::TrackedFiles
)
});
let gutter_settings = EditorSettings::get_global(cx).gutter;
@@ -3,38 +3,105 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Deserialize, Clone)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct EditorSettings {
+ /// Whether the cursor blinks in the editor.
pub cursor_blink: bool,
+ /// How to highlight the current line in the editor.
pub current_line_highlight: CurrentLineHighlight,
+ /// Whether to show the informational hover box when moving the mouse
+ /// over symbols in the editor.
pub hover_popover_enabled: bool,
+ /// Whether to pop the completions menu while typing in an editor without
+ /// explicitly requesting it.
pub show_completions_on_input: bool,
+ /// Whether to display inline and alongside documentation for items in the
+ /// completions menu.
pub show_completion_documentation: bool,
+ /// The debounce delay before re-querying the language server for completion
+ /// documentation when not included in original completion list.
pub completion_documentation_secondary_query_debounce: u64,
+ /// Whether to use additional LSP queries to format (and amend) the code after
+ /// every "trigger" symbol input, defined by LSP server capabilities.
pub use_on_type_format: bool,
+ /// Toolbar related settings
pub toolbar: Toolbar,
+ /// Scrollbar related settings
pub scrollbar: Scrollbar,
+ /// Gutter related settings
pub gutter: Gutter,
+ /// Whether the editor will scroll beyond the last line.
pub scroll_beyond_last_line: ScrollBeyondLastLine,
+ /// The number of lines to keep above/below the cursor when auto-scrolling.
pub vertical_scroll_margin: f32,
+ /// Scroll sensitivity multiplier. This multiplier is applied
+ /// to both the horizontal and vertical delta values while scrolling.
pub scroll_sensitivity: f32,
+ /// Whether the line numbers on editors gutter are relative or not.
pub relative_line_numbers: bool,
+ /// When to populate a new search's query based on the text under the cursor.
pub seed_search_query_from_cursor: SeedQuerySetting,
pub use_smartcase_search: bool,
+ /// The key to use for adding multiple cursors
pub multi_cursor_modifier: MultiCursorModifier,
+ /// Hide the values of variables in `private` files, as defined by the
+ /// private_files setting. This only changes the visual representation,
+ /// the values are still present in the file and can be selected / copied / pasted
pub redact_private_values: bool,
+
+ /// How many lines to expand the multibuffer excerpts by default
pub expand_excerpt_lines: u32,
pub middle_click_paste: bool,
+ /// What to do when multibuffer is double clicked in some of its excerpts
+ /// (parts of singleton buffers).
#[serde(default)]
pub double_click_in_multibuffer: DoubleClickInMultibuffer,
+ /// Whether the editor search results will loop
pub search_wrap: bool,
#[serde(default)]
pub search: SearchSettings,
+ /// Show method signatures in the editor, when inside parentheses.
pub auto_signature_help: bool,
+ /// Whether to show the signature help after completion or a bracket pair inserted.
+ /// If `auto_signature_help` is enabled, this setting will be treated as enabled also.
pub show_signature_help_after_edits: bool,
+ /// Jupyter REPL settings.
pub jupyter: Jupyter,
}
+impl Default for EditorSettings {
+ fn default() -> Self {
+ Self {
+ cursor_blink: true,
+ current_line_highlight: CurrentLineHighlight::All,
+ hover_popover_enabled: true,
+ show_completions_on_input: true,
+ show_completion_documentation: true,
+ completion_documentation_secondary_query_debounce: 300,
+ use_on_type_format: true,
+ toolbar: Default::default(),
+ scrollbar: Default::default(),
+ gutter: Default::default(),
+ scroll_beyond_last_line: ScrollBeyondLastLine::OnePage,
+ vertical_scroll_margin: 3.,
+ scroll_sensitivity: 1.0,
+ relative_line_numbers: false,
+ seed_search_query_from_cursor: SeedQuerySetting::Always,
+ multi_cursor_modifier: MultiCursorModifier::Alt,
+ redact_private_values: false,
+ expand_excerpt_lines: 3,
+ double_click_in_multibuffer: DoubleClickInMultibuffer::Select,
+ search_wrap: true,
+ auto_signature_help: false,
+ show_signature_help_after_edits: true,
+ jupyter: Default::default(),
+ use_smartcase_search: false,
+ middle_click_paste: true,
+ search: SearchSettings::default(),
+ }
+ }
+}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CurrentLineHighlight {
@@ -72,48 +139,93 @@ pub enum DoubleClickInMultibuffer {
Open,
}
-#[derive(Debug, Clone, Deserialize)]
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct Jupyter {
/// Whether the Jupyter feature is enabled.
- ///
- /// Default: true
pub enabled: bool,
}
-#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub struct JupyterContent {
- /// Whether the Jupyter feature is enabled.
- ///
- /// Default: true
- pub enabled: Option<bool>,
+impl Default for Jupyter {
+ fn default() -> Self {
+ Self { enabled: true }
+ }
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+#[serde(default)]
pub struct Toolbar {
+ /// Whether to display breadcrumbs in the editor toolbar.
pub breadcrumbs: bool,
+ /// Whether to display quick action buttons in the editor toolbar.
pub quick_actions: bool,
+ /// Whether to show the selections menu in the editor toolbar
pub selections_menu: bool,
}
+impl Default for Toolbar {
+ fn default() -> Self {
+ Self {
+ breadcrumbs: true,
+ quick_actions: true,
+ selections_menu: true,
+ }
+ }
+}
+
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct Scrollbar {
+ /// When to show the scrollbar in the editor.
pub show: ShowScrollbar,
+ /// Whether to show git diff indicators in the scrollbar.
pub git_diff: bool,
+ /// Whether to show buffer search result indicators in the scrollbar.
pub selected_symbol: bool,
+ /// Whether to show selected symbol occurrences in the scrollbar.
pub search_results: bool,
+ /// Whether to show diagnostic indicators in the scrollbar.
pub diagnostics: bool,
+ /// Whether to show cursor positions in the scrollbar.
pub cursors: bool,
}
+impl Default for Scrollbar {
+ fn default() -> Self {
+ Self {
+ show: ShowScrollbar::Auto,
+ git_diff: true,
+ selected_symbol: true,
+ search_results: true,
+ diagnostics: true,
+ cursors: true,
+ }
+ }
+}
+
+/// Gutter-related settings.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+#[serde(default)]
pub struct Gutter {
+ /// Whether to show line numbers in the gutter.
pub line_numbers: bool,
+ /// Whether to show code action buttons in the gutter.
pub code_actions: bool,
+ /// Whether to show runnable buttons in the gutter.
pub runnables: bool,
+ /// Whether to show fold buttons in the gutter.
pub folds: bool,
}
+impl Default for Gutter {
+ fn default() -> Self {
+ Self {
+ line_numbers: true,
+ code_actions: true,
+ runnables: true,
+ folds: true,
+ }
+ }
+}
+
/// When to show the scrollbar in the editor.
///
/// Default: auto
@@ -171,188 +283,6 @@ pub struct SearchSettings {
pub regex: bool,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct EditorSettingsContent {
- /// Whether the cursor blinks in the editor.
- ///
- /// Default: true
- pub cursor_blink: Option<bool>,
- /// How to highlight the current line in the editor.
- ///
- /// Default: all
- pub current_line_highlight: Option<CurrentLineHighlight>,
- /// Whether to show the informational hover box when moving the mouse
- /// over symbols in the editor.
- ///
- /// Default: true
- pub hover_popover_enabled: Option<bool>,
-
- /// Whether to pop the completions menu while typing in an editor without
- /// explicitly requesting it.
- ///
- /// Default: true
- pub show_completions_on_input: Option<bool>,
- /// Whether to display inline and alongside documentation for items in the
- /// completions menu.
- ///
- /// Default: true
- pub show_completion_documentation: Option<bool>,
- /// The debounce delay before re-querying the language server for completion
- /// documentation when not included in original completion list.
- ///
- /// Default: 300 ms
- pub completion_documentation_secondary_query_debounce: Option<u64>,
- /// Whether to use additional LSP queries to format (and amend) the code after
- /// every "trigger" symbol input, defined by LSP server capabilities.
- ///
- /// Default: true
- pub use_on_type_format: Option<bool>,
- /// Toolbar related settings
- pub toolbar: Option<ToolbarContent>,
- /// Scrollbar related settings
- pub scrollbar: Option<ScrollbarContent>,
- /// Gutter related settings
- pub gutter: Option<GutterContent>,
- /// Whether the editor will scroll beyond the last line.
- ///
- /// Default: one_page
- pub scroll_beyond_last_line: Option<ScrollBeyondLastLine>,
- /// The number of lines to keep above/below the cursor when auto-scrolling.
- ///
- /// Default: 3.
- pub vertical_scroll_margin: Option<f32>,
- /// Scroll sensitivity multiplier. This multiplier is applied
- /// to both the horizontal and vertical delta values while scrolling.
- ///
- /// Default: 1.0
- pub scroll_sensitivity: Option<f32>,
- /// Whether the line numbers on editors gutter are relative or not.
- ///
- /// Default: false
- pub relative_line_numbers: Option<bool>,
- /// When to populate a new search's query based on the text under the cursor.
- ///
- /// Default: always
- pub seed_search_query_from_cursor: Option<SeedQuerySetting>,
- pub use_smartcase_search: Option<bool>,
- /// The key to use for adding multiple cursors
- ///
- /// Default: alt
- pub multi_cursor_modifier: Option<MultiCursorModifier>,
- /// Hide the values of variables in `private` files, as defined by the
- /// private_files setting. This only changes the visual representation,
- /// the values are still present in the file and can be selected / copied / pasted
- ///
- /// Default: false
- pub redact_private_values: Option<bool>,
-
- /// How many lines to expand the multibuffer excerpts by default
- ///
- /// Default: 3
- pub expand_excerpt_lines: Option<u32>,
-
- /// Whether to enable middle-click paste on Linux
- ///
- /// Default: true
- pub middle_click_paste: Option<bool>,
-
- /// What to do when multibuffer is double clicked in some of its excerpts
- /// (parts of singleton buffers).
- ///
- /// Default: select
- pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
- /// Whether the editor search results will loop
- ///
- /// Default: true
- pub search_wrap: Option<bool>,
-
- /// Defaults to use when opening a new buffer and project search items.
- ///
- /// Default: nothing is enabled
- pub search: Option<SearchSettings>,
-
- /// Whether to automatically show a signature help pop-up or not.
- ///
- /// Default: false
- pub auto_signature_help: Option<bool>,
-
- /// Whether to show the signature help pop-up after completions or bracket pairs inserted.
- ///
- /// Default: true
- pub show_signature_help_after_edits: Option<bool>,
-
- /// Jupyter REPL settings.
- pub jupyter: Option<JupyterContent>,
-}
-
-// Toolbar related settings
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
-pub struct ToolbarContent {
- /// Whether to display breadcrumbs in the editor toolbar.
- ///
- /// Default: true
- pub breadcrumbs: Option<bool>,
- /// Whether to display quick action buttons in the editor toolbar.
- ///
- /// Default: true
- pub quick_actions: Option<bool>,
-
- /// Whether to show the selections menu in the editor toolbar
- ///
- /// Default: true
- pub selections_menu: Option<bool>,
-}
-
-/// Scrollbar related settings
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
-pub struct ScrollbarContent {
- /// When to show the scrollbar in the editor.
- ///
- /// Default: auto
- pub show: Option<ShowScrollbar>,
- /// Whether to show git diff indicators in the scrollbar.
- ///
- /// Default: true
- pub git_diff: Option<bool>,
- /// Whether to show buffer search result indicators in the scrollbar.
- ///
- /// Default: true
- pub search_results: Option<bool>,
- /// Whether to show selected symbol occurrences in the scrollbar.
- ///
- /// Default: true
- pub selected_symbol: Option<bool>,
- /// Whether to show diagnostic indicators in the scrollbar.
- ///
- /// Default: true
- pub diagnostics: Option<bool>,
- /// Whether to show cursor positions in the scrollbar.
- ///
- /// Default: true
- pub cursors: Option<bool>,
-}
-
-/// Gutter related settings
-#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
-pub struct GutterContent {
- /// Whether to show line numbers in the gutter.
- ///
- /// Default: true
- pub line_numbers: Option<bool>,
- /// Whether to show code action buttons in the gutter.
- ///
- /// Default: true
- pub code_actions: Option<bool>,
- /// Whether to show runnable buttons in the gutter.
- ///
- /// Default: true
- pub runnables: Option<bool>,
- /// Whether to show fold buttons in the gutter.
- ///
- /// Default: true
- pub folds: Option<bool>,
-}
-
impl EditorSettings {
pub fn jupyter_enabled(cx: &AppContext) -> bool {
EditorSettings::get_global(cx).jupyter.enabled
@@ -362,7 +292,7 @@ impl EditorSettings {
impl Settings for EditorSettings {
const KEY: Option<&'static str> = None;
- type FileContent = EditorSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -1,7 +1,7 @@
use std::sync::Arc;
use gpui::{AppContext, FontFeatures, FontWeight};
-use project::project_settings::{InlineBlameSettings, ProjectSettings};
+use project::project_settings::ProjectSettings;
use settings::{EditableSettingControl, Settings};
use theme::{FontFamilyCache, ThemeSettings};
use ui::{
@@ -296,14 +296,7 @@ impl EditableSettingControl for InlineGitBlameControl {
value: Self::Value,
_cx: &AppContext,
) {
- if let Some(inline_blame) = settings.git.inline_blame.as_mut() {
- inline_blame.enabled = value;
- } else {
- settings.git.inline_blame = Some(InlineBlameSettings {
- enabled: false,
- ..Default::default()
- });
- }
+ settings.git.inline_blame.enabled = value;
}
}
@@ -349,14 +342,7 @@ impl EditableSettingControl for LineNumbersControl {
value: Self::Value,
_cx: &AppContext,
) {
- if let Some(gutter) = settings.gutter.as_mut() {
- gutter.line_numbers = Some(value);
- } else {
- settings.gutter = Some(crate::editor_settings::GutterContent {
- line_numbers: Some(value),
- ..Default::default()
- });
- }
+ settings.gutter.line_numbers = value;
}
}
@@ -402,7 +388,7 @@ impl EditableSettingControl for RelativeLineNumbersControl {
value: Self::Value,
_cx: &AppContext,
) {
- settings.relative_line_numbers = Some(value);
+ settings.relative_line_numbers = value;
}
}
@@ -6964,7 +6964,7 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true(
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.auto_signature_help = Some(true);
+ settings.auto_signature_help = true;
});
});
});
@@ -7105,8 +7105,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.auto_signature_help = Some(false);
- settings.show_signature_help_after_edits = Some(false);
+ settings.auto_signature_help = false;
+ settings.show_signature_help_after_edits = false;
});
});
});
@@ -7232,8 +7232,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.auto_signature_help = Some(false);
- settings.show_signature_help_after_edits = Some(true);
+ settings.auto_signature_help = false;
+ settings.show_signature_help_after_edits = true;
});
});
});
@@ -7274,8 +7274,8 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.auto_signature_help = Some(true);
- settings.show_signature_help_after_edits = Some(false);
+ settings.auto_signature_help = true;
+ settings.show_signature_help_after_edits = false;
});
});
});
@@ -7318,7 +7318,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.auto_signature_help = Some(true);
+ settings.auto_signature_help = true;
});
});
});
@@ -7759,7 +7759,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|settings, cx| {
settings.update_user_settings::<EditorSettings>(cx, |settings| {
- settings.show_completions_on_input = Some(false);
+ settings.show_completions_on_input = false;
});
})
});
@@ -1283,10 +1283,7 @@ impl EditorElement {
.row,
);
- let git_gutter_setting = ProjectSettings::get_global(cx)
- .git
- .git_gutter
- .unwrap_or_default();
+ let git_gutter_setting = ProjectSettings::get_global(cx).git.git_gutter;
let display_hunks = buffer_snapshot
.git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
.map(|hunk| diff_hunk_to_display(&hunk, snapshot))
@@ -1366,12 +1363,10 @@ impl EditorElement {
};
let padded_line_end = line_end + em_width * INLINE_BLAME_PADDING_EM_WIDTHS;
- let min_column_in_pixels = ProjectSettings::get_global(cx)
- .git
- .inline_blame
- .and_then(|settings| settings.min_column)
- .map(|col| self.column_pixels(col as usize, cx))
- .unwrap_or(px(0.));
+ let min_column_in_pixels = self.column_pixels(
+ ProjectSettings::get_global(cx).git.inline_blame.min_column as usize,
+ cx,
+ );
let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
cmp::max(padded_line_end, min_start)
@@ -3331,7 +3326,7 @@ impl EditorElement {
.unwrap_or_else(|| {
matches!(
ProjectSettings::get_global(cx).git.git_gutter,
- Some(GitGutterSetting::TrackedFiles)
+ GitGutterSetting::TrackedFiles
)
});
if show_git_gutter {
@@ -6,18 +6,25 @@ use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
use std::sync::Arc;
-#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
+#[derive(Deserialize, Serialize, Debug, Clone, JsonSchema)]
+#[serde(default)]
pub struct ExtensionSettings {
/// The extensions that should be automatically installed by Zed.
///
/// This is used to make functionality provided by extensions (e.g., language support)
/// available out-of-the-box.
- #[serde(default)]
pub auto_install_extensions: HashMap<Arc<str>, bool>,
- #[serde(default)]
pub auto_update_extensions: HashMap<Arc<str>, bool>,
}
+impl Default for ExtensionSettings {
+ fn default() -> Self {
+ Self {
+ auto_install_extensions: HashMap::from_iter([("html".into(), true)]),
+ auto_update_extensions: Default::default(),
+ }
+ }
+}
impl ExtensionSettings {
/// Returns whether the given extension should be auto-installed.
pub fn should_auto_install(&self, extension_id: &str) -> bool {
@@ -1000,7 +1000,7 @@ impl ExtensionsPage {
this.update_settings::<VimModeSetting>(
selection,
cx,
- |setting, value| *setting = Some(value),
+ |setting, value| *setting = VimModeSetting(value),
);
}),
)),
@@ -180,18 +180,10 @@ pub(crate) enum LineIndicatorFormat {
Long,
}
-/// Whether or not to automatically check for updates.
-///
-/// Values: short, long
-/// Default: short
-#[derive(Clone, Copy, Default, JsonSchema, Deserialize, Serialize)]
-#[serde(transparent)]
-pub(crate) struct LineIndicatorFormatContent(LineIndicatorFormat);
-
impl Settings for LineIndicatorFormat {
const KEY: Option<&'static str> = Some("line_indicator_format");
- type FileContent = Option<LineIndicatorFormatContent>;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -199,9 +191,9 @@ impl Settings for LineIndicatorFormat {
) -> anyhow::Result<Self> {
let format = [sources.release_channel, sources.user]
.into_iter()
- .find_map(|value| value.copied().flatten())
- .unwrap_or(sources.default.ok_or_else(Self::missing_default)?);
+ .find_map(|value| value.copied())
+ .unwrap_or(*sources.default);
- Ok(format.0)
+ Ok(format)
}
}
@@ -5,6 +5,7 @@
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, DivAssign, Mul, Neg, Sub, SubAssign};
use refineable::Refineable;
+use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use std::{
cmp::{self, PartialOrd},
@@ -2201,6 +2202,7 @@ impl From<Percentage> for Radians {
PartialEq,
Serialize,
Deserialize,
+ JsonSchema,
)]
#[repr(transparent)]
pub struct Pixels(pub f32);
@@ -70,10 +70,10 @@ pub struct LanguageSettings {
/// The column at which to soft-wrap lines, for buffers where soft-wrap
/// is enabled.
pub preferred_line_length: u32,
- // Whether to show wrap guides (vertical rulers) in the editor.
- // Setting this to true will show a guide at the 'preferred_line_length' value
- // if softwrap is set to 'preferred_line_length', and will show any
- // additional guides as specified by the 'wrap_guides' setting.
+ /// Whether to show wrap guides (vertical rulers) in the editor.
+ /// Setting this to true will show a guide at the 'preferred_line_length' value
+ /// if softwrap is set to 'preferred_line_length', and will show any
+ /// additional guides as specified by the 'wrap_guides' setting.
pub show_wrap_guides: bool,
/// Character counts at which to show wrap guides (vertical rulers) in the editor.
pub wrap_guides: Vec<usize>,
@@ -7,10 +7,13 @@ use feature_flags::FeatureFlagAppExt;
use futures::StreamExt;
use gpui::{AppContext, AsyncAppContext};
use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
-use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
+use language::{
+ CodeLabel, Language, LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate,
+};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
use project::ContextProviderWithTasks;
+use rope::Rope;
use serde_json::{json, Value};
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
use smol::{
@@ -202,6 +205,30 @@ impl LspAdapter for JsonLspAdapter {
})))
}
+ async fn label_for_completion(
+ &self,
+ item: &lsp::CompletionItem,
+ language: &Arc<Language>,
+ ) -> Option<CodeLabel> {
+ let text = if let Some(description) = item
+ .label_details
+ .as_ref()
+ .and_then(|label_details| label_details.description.as_ref())
+ {
+ format!("{} {}", item.label, description)
+ } else if let Some(detail) = &item.detail {
+ format!("{} {}", item.label, detail)
+ } else {
+ item.label.clone()
+ };
+ let rope = Rope::from(item.label.as_str());
+ let runs = language.highlight_text(&rope, 0..item.label.len());
+ Some(language::CodeLabel {
+ text,
+ runs,
+ filter_range: 0..item.label.len(),
+ })
+ }
async fn workspace_configuration(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
@@ -24,12 +24,12 @@ use editor::{
use file_icons::FileIcons;
use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
use gpui::{
- actions, anchored, deferred, div, impl_actions, px, uniform_list, Action, AnyElement,
- AppContext, AssetSource, AsyncWindowContext, ClipboardItem, DismissEvent, Div, ElementId,
- EventEmitter, FocusHandle, FocusableView, HighlightStyle, InteractiveElement, IntoElement,
- KeyContext, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render,
- SharedString, Stateful, Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext,
- VisualContext, WeakView, WindowContext,
+ actions, anchored, deferred, div, impl_actions, uniform_list, Action, AnyElement, AppContext,
+ AssetSource, AsyncWindowContext, ClipboardItem, DismissEvent, Div, ElementId, EventEmitter,
+ FocusHandle, FocusableView, HighlightStyle, InteractiveElement, IntoElement, KeyContext, Model,
+ MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render, SharedString, Stateful,
+ Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext, VisualContext,
+ WeakView, WindowContext,
};
use itertools::Itertools;
use language::{BufferId, BufferSnapshot, OffsetRangeExt, OutlineItem};
@@ -1938,7 +1938,7 @@ impl OutlinePanel {
.child(
ListItem::new(item_id)
.indent_level(depth)
- .indent_step_size(px(settings.indent_size))
+ .indent_step_size(settings.indent_size)
.selected(is_active)
.when_some(icon_element, |list_item, icon_element| {
list_item.child(h_flex().child(icon_element))
@@ -3801,7 +3801,7 @@ impl Panel for OutlinePanel {
DockPosition::Left | DockPosition::Bottom => OutlinePanelDockPosition::Left,
DockPosition::Right => OutlinePanelDockPosition::Right,
};
- settings.dock = Some(dock);
+ settings.dock = dock;
},
);
}
@@ -1,4 +1,5 @@
-use gpui::Pixels;
+use anyhow;
+use gpui::{px, Pixels};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
@@ -10,66 +11,51 @@ pub enum OutlinePanelDockPosition {
Right,
}
-#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
+#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, JsonSchema)]
pub struct OutlinePanelSettings {
- pub button: bool,
- pub default_width: Pixels,
- pub dock: OutlinePanelDockPosition,
- pub file_icons: bool,
- pub folder_icons: bool,
- pub git_status: bool,
- pub indent_size: f32,
- pub auto_reveal_entries: bool,
- pub auto_fold_dirs: bool,
-}
-
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct OutlinePanelSettingsContent {
/// Whether to show the outline panel button in the status bar.
- ///
- /// Default: true
- pub button: Option<bool>,
+ pub button: bool,
/// Customize default width (in pixels) taken by outline panel
- ///
- /// Default: 240
- pub default_width: Option<f32>,
+ pub default_width: Pixels,
/// The position of outline panel
- ///
- /// Default: left
- pub dock: Option<OutlinePanelDockPosition>,
+ pub dock: OutlinePanelDockPosition,
/// Whether to show file icons in the outline panel.
- ///
- /// Default: true
- pub file_icons: Option<bool>,
+ pub file_icons: bool,
/// Whether to show folder icons or chevrons for directories in the outline panel.
- ///
- /// Default: true
- pub folder_icons: Option<bool>,
+ pub folder_icons: bool,
/// Whether to show the git status in the outline panel.
- ///
- /// Default: true
- pub git_status: Option<bool>,
+ pub git_status: bool,
/// Amount of indentation (in pixels) for nested items.
- ///
- /// Default: 20
- pub indent_size: Option<f32>,
+ pub indent_size: Pixels,
/// Whether to reveal it in the outline panel automatically,
/// when a corresponding project entry becomes active.
/// Gitignored entries are never auto revealed.
- ///
- /// Default: true
- pub auto_reveal_entries: Option<bool>,
+ pub auto_reveal_entries: bool,
/// Whether to fold directories automatically
/// when directory has only one directory inside.
- ///
- /// Default: true
- pub auto_fold_dirs: Option<bool>,
+ pub auto_fold_dirs: bool,
+}
+
+impl Default for OutlinePanelSettings {
+ fn default() -> Self {
+ Self {
+ button: true,
+ default_width: px(240.),
+ dock: OutlinePanelDockPosition::Left,
+ file_icons: true,
+ folder_icons: true,
+ auto_fold_dirs: true,
+ auto_reveal_entries: true,
+ indent_size: px(20.),
+ git_status: true,
+ }
+ }
}
impl Settings for OutlinePanelSettings {
const KEY: Option<&'static str> = Some("outline_panel");
- type FileContent = OutlinePanelSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -0,0 +1,184 @@
+use std::time::Instant;
+
+use anyhow::Result;
+use gpui::{
+ div, AppContext, InteractiveElement as _, Render, StatefulInteractiveElement as _,
+ Subscription, ViewContext, VisualContext,
+};
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use settings::{Settings, SettingsSources, SettingsStore};
+use workspace::{
+ ui::{Label, LabelCommon, LabelSize, Tooltip},
+ ItemHandle, StatusItemView, Workspace,
+};
+
+const SHOW_STARTUP_TIME_DURATION: std::time::Duration = std::time::Duration::from_secs(5);
+
+pub fn init(cx: &mut AppContext) {
+ PerformanceSettings::register(cx);
+
+ let mut enabled = PerformanceSettings::get_global(cx).show_in_status_bar;
+ let start_time = Instant::now();
+ let mut _observe_workspaces = toggle_status_bar_items(enabled, start_time, cx);
+
+ cx.observe_global::<SettingsStore>(move |cx| {
+ let new_value = PerformanceSettings::get_global(cx).show_in_status_bar;
+ if new_value != enabled {
+ enabled = new_value;
+ _observe_workspaces = toggle_status_bar_items(enabled, start_time, cx);
+ }
+ })
+ .detach();
+}
+
+fn toggle_status_bar_items(
+ enabled: bool,
+ start_time: Instant,
+ cx: &mut AppContext,
+) -> Option<Subscription> {
+ for window in cx.windows() {
+ if let Some(workspace) = window.downcast::<Workspace>() {
+ workspace
+ .update(cx, |workspace, cx| {
+ toggle_status_bar_item(workspace, enabled, start_time, cx);
+ })
+ .ok();
+ }
+ }
+
+ if enabled {
+ log::info!("performance metrics display enabled");
+ Some(cx.observe_new_views::<Workspace>(move |workspace, cx| {
+ toggle_status_bar_item(workspace, true, start_time, cx);
+ }))
+ } else {
+ log::info!("performance metrics display disabled");
+ None
+ }
+}
+
+struct PerformanceStatusBarItem {
+ display_mode: DisplayMode,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum DisplayMode {
+ StartupTime,
+ Fps,
+}
+
+impl PerformanceStatusBarItem {
+ fn new(start_time: Instant, cx: &mut ViewContext<Self>) -> Self {
+ let now = Instant::now();
+ let display_mode = if now < start_time + SHOW_STARTUP_TIME_DURATION {
+ DisplayMode::StartupTime
+ } else {
+ DisplayMode::Fps
+ };
+
+ let this = Self { display_mode };
+
+ if let DisplayMode::StartupTime = display_mode {
+ cx.spawn(|this, mut cx| async move {
+ let now = Instant::now();
+ let remaining_duration =
+ (start_time + SHOW_STARTUP_TIME_DURATION).saturating_duration_since(now);
+ cx.background_executor().timer(remaining_duration).await;
+ this.update(&mut cx, |this, cx| {
+ this.display_mode = DisplayMode::Fps;
+ cx.notify();
+ })
+ .ok();
+ })
+ .detach();
+ }
+
+ this
+ }
+}
+
+impl Render for PerformanceStatusBarItem {
+ fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement {
+ let text = match self.display_mode {
+ DisplayMode::StartupTime => cx
+ .time_to_first_window_draw()
+ .map_or("Pending".to_string(), |duration| {
+ format!("{}ms", duration.as_millis())
+ }),
+ DisplayMode::Fps => cx.fps().map_or("".to_string(), |fps| {
+ format!("{:3} FPS", fps.round() as u32)
+ }),
+ };
+
+ use gpui::ParentElement;
+ let display_mode = self.display_mode;
+ div()
+ .id("performance status")
+ .child(Label::new(text).size(LabelSize::Small))
+ .tooltip(move |cx| match display_mode {
+ DisplayMode::StartupTime => Tooltip::text("Time to first window draw", cx),
+ DisplayMode::Fps => cx
+ .new_view(|cx| {
+ let tooltip = Tooltip::new("Current FPS");
+ if let Some(time_to_first) = cx.time_to_first_window_draw() {
+ tooltip.meta(format!(
+ "Time to first window draw: {}ms",
+ time_to_first.as_millis()
+ ))
+ } else {
+ tooltip
+ }
+ })
+ .into(),
+ })
+ }
+}
+
+impl StatusItemView for PerformanceStatusBarItem {
+ fn set_active_pane_item(
+ &mut self,
+ _active_pane_item: Option<&dyn ItemHandle>,
+ _cx: &mut gpui::ViewContext<Self>,
+ ) {
+ // This is not currently used.
+ }
+}
+
+fn toggle_status_bar_item(
+ workspace: &mut Workspace,
+ enabled: bool,
+ start_time: Instant,
+ cx: &mut ViewContext<Workspace>,
+) {
+ if enabled {
+ workspace.status_bar().update(cx, |bar, cx| {
+ bar.add_right_item(
+ cx.new_view(|cx| PerformanceStatusBarItem::new(start_time, cx)),
+ cx,
+ )
+ });
+ } else {
+ workspace.status_bar().update(cx, |bar, cx| {
+ bar.remove_items_of_type::<PerformanceStatusBarItem>(cx);
+ });
+ }
+}
+
+/// Configuration of the display of performance details.
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
+#[serde(default)]
+pub struct PerformanceSettings {
+ /// Display the time to first window draw and frame rate in the status bar.
+ pub show_in_status_bar: bool,
+}
+
+impl Settings for PerformanceSettings {
+ const KEY: Option<&'static str> = Some("performance");
+
+ type FileContent = Self;
+
+ fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
+ sources.json_merge()
+ }
+}
@@ -20,6 +20,7 @@ use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId};
use crate::worktree_store::{WorktreeStore, WorktreeStoreEvent};
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct ProjectSettings {
/// Configuration for language servers.
///
@@ -41,7 +42,6 @@ pub struct ProjectSettings {
pub load_direnv: DirenvSettings,
/// Configuration for session-related features
- #[serde(default)]
pub session: SessionSettings,
}
@@ -59,36 +59,31 @@ pub enum DirenvSettings {
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct GitSettings {
/// Whether or not to show the git gutter.
///
/// Default: tracked_files
- pub git_gutter: Option<GitGutterSetting>,
+ pub git_gutter: GitGutterSetting,
pub gutter_debounce: Option<u64>,
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: on
- pub inline_blame: Option<InlineBlameSettings>,
+ pub inline_blame: InlineBlameSettings,
}
impl GitSettings {
pub fn inline_blame_enabled(&self) -> bool {
#[allow(unknown_lints, clippy::manual_unwrap_or_default)]
- match self.inline_blame {
- Some(InlineBlameSettings { enabled, .. }) => enabled,
- _ => false,
- }
+ self.inline_blame.enabled
}
pub fn inline_blame_delay(&self) -> Option<Duration> {
- match self.inline_blame {
- Some(InlineBlameSettings {
- delay_ms: Some(delay_ms),
- ..
- }) if delay_ms > 0 => Some(Duration::from_millis(delay_ms)),
- _ => None,
- }
+ self.inline_blame
+ .delay_ms
+ .gt(&0)
+ .then(|| Duration::from_millis(self.inline_blame.delay_ms))
}
}
@@ -102,28 +97,34 @@ pub enum GitGutterSetting {
Hide,
}
-#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
+#[serde(default)]
pub struct InlineBlameSettings {
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: true
- #[serde(default = "true_value")]
pub enabled: bool,
/// Whether to only show the inline blame information
/// after a delay once the cursor stops moving.
///
/// Default: 0
- pub delay_ms: Option<u64>,
+ pub delay_ms: u64,
/// The minimum column number to show the inline blame information at
///
/// Default: 0
- pub min_column: Option<u32>,
+ pub min_column: u32,
}
-const fn true_value() -> bool {
- true
+impl Default for InlineBlameSettings {
+ fn default() -> Self {
+ Self {
+ enabled: true,
+ delay_ms: 0,
+ min_column: 0,
+ }
+ }
}
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -2289,7 +2289,7 @@ impl ProjectPanel {
.child(
ListItem::new(entry_id.to_proto() as usize)
.indent_level(depth)
- .indent_step_size(px(settings.indent_size))
+ .indent_step_size(settings.indent_size)
.selected(is_marked || is_active)
.when_some(canonical_path, |this, path| {
this.end_slot::<AnyElement>(
@@ -2817,7 +2817,7 @@ impl Render for DraggedProjectEntryView {
this.bg(cx.theme().colors().background).w(self.width).child(
ListItem::new(self.selection.entry_id.to_proto() as usize)
.indent_level(self.details.depth)
- .indent_step_size(px(settings.indent_size))
+ .indent_step_size(settings.indent_size)
.child(if let Some(icon) = &self.details.icon {
div().child(Icon::from_path(icon.clone()))
} else {
@@ -2855,7 +2855,7 @@ impl Panel for ProjectPanel {
DockPosition::Left | DockPosition::Bottom => ProjectPanelDockPosition::Left,
DockPosition::Right => ProjectPanelDockPosition::Right,
};
- settings.dock = Some(dock);
+ settings.dock = dock;
},
);
}
@@ -3029,7 +3029,7 @@ mod tests {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
worktree_settings.file_scan_exclusions =
- Some(vec!["**/.git".to_string(), "**/4/**".to_string()]);
+ vec!["**/.git".to_string(), "**/4/**".to_string()];
});
});
});
@@ -4818,10 +4818,10 @@ mod tests {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
- worktree_settings.file_scan_exclusions = Some(Vec::new());
+ worktree_settings.file_scan_exclusions = Vec::new();
});
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
- project_panel_settings.auto_reveal_entries = Some(false)
+ project_panel_settings.auto_reveal_entries = false
});
})
});
@@ -4940,7 +4940,7 @@ mod tests {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
- project_panel_settings.auto_reveal_entries = Some(true)
+ project_panel_settings.auto_reveal_entries = true
});
})
});
@@ -5054,10 +5054,10 @@ mod tests {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
- worktree_settings.file_scan_exclusions = Some(Vec::new());
+ worktree_settings.file_scan_exclusions = Vec::new();
});
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
- project_panel_settings.auto_reveal_entries = Some(false)
+ project_panel_settings.auto_reveal_entries = false
});
})
});
@@ -5256,7 +5256,7 @@ mod tests {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
project_settings.file_scan_exclusions =
- Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]);
+ vec!["excluded_dir".to_string(), "**/.git".to_string()];
});
});
});
@@ -5569,10 +5569,10 @@ mod tests {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
- project_panel_settings.auto_fold_dirs = Some(false);
+ project_panel_settings.auto_fold_dirs = false;
});
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
- worktree_settings.file_scan_exclusions = Some(Vec::new());
+ worktree_settings.file_scan_exclusions = Vec::new();
});
});
});
@@ -5591,10 +5591,10 @@ mod tests {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<ProjectPanelSettings>(cx, |project_panel_settings| {
- project_panel_settings.auto_fold_dirs = Some(false);
+ project_panel_settings.auto_fold_dirs = false;
});
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
- worktree_settings.file_scan_exclusions = Some(Vec::new());
+ worktree_settings.file_scan_exclusions = Vec::new();
});
});
});
@@ -2,6 +2,7 @@ use gpui::Pixels;
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
+use ui::px;
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Copy, PartialEq)]
#[serde(rename_all = "snake_case")]
@@ -10,20 +11,50 @@ pub enum ProjectPanelDockPosition {
Right,
}
-#[derive(Deserialize, Debug, Clone, Copy, PartialEq)]
+#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, JsonSchema)]
+#[serde(default)]
pub struct ProjectPanelSettings {
+ /// Whether to show the project panel button in the status bar.
pub button: bool,
+ /// Customize default width (in pixels) taken by project panel
pub default_width: Pixels,
+ /// The position of project panel
pub dock: ProjectPanelDockPosition,
+ /// Whether to show file icons in the project panel.
pub file_icons: bool,
+ /// Whether to show folder icons or chevrons for directories in the project panel.
pub folder_icons: bool,
+ /// Whether to show the git status in the project panel.
pub git_status: bool,
- pub indent_size: f32,
+ /// Amount of indentation (in pixels) for nested items.
+ pub indent_size: Pixels,
+ /// Whether to reveal it in the project panel automatically,
+ /// when a corresponding project entry becomes active.
+ /// Gitignored entries are never auto revealed.
pub auto_reveal_entries: bool,
+ /// Whether to fold directories automatically
+ /// when directory has only one directory inside.
pub auto_fold_dirs: bool,
+ /// Scrollbar-related settings
pub scrollbar: ScrollbarSettings,
}
+impl Default for ProjectPanelSettings {
+ fn default() -> Self {
+ Self {
+ button: true,
+ default_width: px(240.),
+ dock: ProjectPanelDockPosition::Left,
+ file_icons: true,
+ folder_icons: true,
+ git_status: true,
+ indent_size: px(20.),
+ auto_reveal_entries: true,
+ auto_fold_dirs: true,
+ scrollbar: Default::default(),
+ }
+ }
+}
/// When to show the scrollbar in the project panel.
///
/// Default: always
@@ -37,7 +68,7 @@ pub enum ShowScrollbar {
Never,
}
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct ScrollbarSettings {
/// When to show the scrollbar in the project panel.
///
@@ -45,63 +76,10 @@ pub struct ScrollbarSettings {
pub show: ShowScrollbar,
}
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
-pub struct ScrollbarSettingsContent {
- /// When to show the scrollbar in the project panel.
- ///
- /// Default: always
- pub show: Option<ShowScrollbar>,
-}
-
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct ProjectPanelSettingsContent {
- /// Whether to show the project panel button in the status bar.
- ///
- /// Default: true
- pub button: Option<bool>,
- /// Customize default width (in pixels) taken by project panel
- ///
- /// Default: 240
- pub default_width: Option<f32>,
- /// The position of project panel
- ///
- /// Default: left
- pub dock: Option<ProjectPanelDockPosition>,
- /// Whether to show file icons in the project panel.
- ///
- /// Default: true
- pub file_icons: Option<bool>,
- /// Whether to show folder icons or chevrons for directories in the project panel.
- ///
- /// Default: true
- pub folder_icons: Option<bool>,
- /// Whether to show the git status in the project panel.
- ///
- /// Default: true
- pub git_status: Option<bool>,
- /// Amount of indentation (in pixels) for nested items.
- ///
- /// Default: 20
- pub indent_size: Option<f32>,
- /// Whether to reveal it in the project panel automatically,
- /// when a corresponding project entry becomes active.
- /// Gitignored entries are never auto revealed.
- ///
- /// Default: true
- pub auto_reveal_entries: Option<bool>,
- /// Whether to fold directories automatically
- /// when directory has only one directory inside.
- ///
- /// Default: false
- pub auto_fold_dirs: Option<bool>,
- /// Scrollbar-related settings
- pub scrollbar: Option<ScrollbarSettingsContent>,
-}
-
impl Settings for ProjectPanelSettings {
const KEY: Option<&'static str> = Some("project_panel");
- type FileContent = ProjectPanelSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -48,7 +48,6 @@ use workspace::{notifications::DetachAndPromptErr, AppState, ModalView, Workspac
use crate::open_dev_server_project;
use crate::ssh_connections::connect_over_ssh;
use crate::ssh_connections::open_ssh_project;
-use crate::ssh_connections::RemoteSettingsContent;
use crate::ssh_connections::SshConnection;
use crate::ssh_connections::SshConnectionModal;
use crate::ssh_connections::SshProject;
@@ -1024,7 +1023,7 @@ impl DevServerProjects {
fn update_settings_file(
&mut self,
cx: &mut ViewContext<Self>,
- f: impl FnOnce(&mut RemoteSettingsContent) + Send + Sync + 'static,
+ f: impl FnOnce(&mut SshSettings) + Send + Sync + 'static,
) {
let Some(fs) = self
.workspace
@@ -22,8 +22,24 @@ use ui::{
use util::paths::PathWithPosition;
use workspace::{AppState, ModalView, Workspace};
-#[derive(Deserialize)]
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct SshSettings {
+ /// ssh_connections is an array of ssh connections.
+ /// By default this setting is null, which disables the direct ssh connection support.
+ /// You can configure these from `project: Open Remote` in the command palette.
+ /// Zed's ssh support will pull configuration from your ~/.ssh too.
+ /// Examples:
+ /// [
+ /// {
+ /// "host": "example-box",
+ /// "projects": [
+ /// {
+ /// "paths": ["/home/user/code/zed"]
+ /// }
+ /// ]
+ /// }
+ /// ]
pub ssh_connections: Option<Vec<SshConnection>>,
}
@@ -62,15 +78,10 @@ pub struct SshProject {
pub paths: Vec<String>,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct RemoteSettingsContent {
- pub ssh_connections: Option<Vec<SshConnection>>,
-}
-
impl Settings for SshSettings {
const KEY: Option<&'static str> = None;
- type FileContent = RemoteSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -6,8 +6,10 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Debug, Default)]
+#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct JupyterSettings {
+ /// Default kernels to select for each language.
pub kernel_selections: HashMap<String, String>,
}
@@ -20,26 +22,10 @@ impl JupyterSettings {
}
}
-#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
-pub struct JupyterSettingsContent {
- /// Default kernels to select for each language.
- ///
- /// Default: `{}`
- pub kernel_selections: Option<HashMap<String, String>>,
-}
-
-impl Default for JupyterSettingsContent {
- fn default() -> Self {
- JupyterSettingsContent {
- kernel_selections: Some(HashMap::new()),
- }
- }
-}
-
impl Settings for JupyterSettings {
const KEY: Option<&'static str> = Some("jupyter");
- type FileContent = JupyterSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -51,10 +37,8 @@ impl Settings for JupyterSettings {
let mut settings = JupyterSettings::default();
for value in sources.defaults_and_customizations() {
- if let Some(source) = &value.kernel_selections {
- for (k, v) in source {
- settings.kernel_selections.insert(k.clone(), v.clone());
- }
+ for (k, v) in &value.kernel_selections {
+ settings.kernel_selections.insert(k.clone(), v.clone());
}
}
@@ -2,22 +2,26 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Serialize, Deserialize, PartialEq, Default)]
+#[derive(Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
+#[serde(default)]
+/// Task-related settings.
pub(crate) struct TaskSettings {
+ /// Whether to show task status indicator in the status bar. Default: true
pub(crate) show_status_indicator: bool,
}
-/// Task-related settings.
-#[derive(Serialize, Deserialize, PartialEq, Default, Clone, JsonSchema)]
-pub(crate) struct TaskSettingsContent {
- /// Whether to show task status indicator in the status bar. Default: true
- show_status_indicator: Option<bool>,
+impl Default for TaskSettings {
+ fn default() -> Self {
+ Self {
+ show_status_indicator: true,
+ }
+ }
}
impl Settings for TaskSettings {
const KEY: Option<&'static str> = Some("task");
- type FileContent = TaskSettingsContent;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
@@ -132,7 +132,7 @@ mod test {
let mut custom_digraphs = HashMap::default();
custom_digraphs.insert("|-".into(), "⊢".into());
custom_digraphs.insert(":)".into(), "👨💻".into());
- s.custom_digraphs = Some(custom_digraphs);
+ s.custom_digraphs = custom_digraphs;
});
});
@@ -1184,7 +1184,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_multiline_find = Some(true);
+ s.use_multiline_find = true;
});
});
@@ -1226,7 +1226,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_multiline_find = Some(true);
+ s.use_multiline_find = true;
});
});
@@ -1268,7 +1268,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_smartcase_find = Some(true);
+ s.use_smartcase_find = true;
});
});
@@ -291,7 +291,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::Never)
+ s.use_system_clipboard = UseSystemClipboard::Never
});
});
@@ -327,7 +327,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::OnYank)
+ s.use_system_clipboard = UseSystemClipboard::OnYank
});
});
@@ -584,7 +584,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::Never)
+ s.use_system_clipboard = UseSystemClipboard::Never
});
});
@@ -630,7 +630,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::Never)
+ s.use_system_clipboard = UseSystemClipboard::Never
});
});
@@ -659,7 +659,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::Never)
+ s.use_system_clipboard = UseSystemClipboard::Never
});
});
@@ -707,7 +707,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimSettings>(cx, |s| {
- s.use_system_clipboard = Some(UseSystemClipboard::Never)
+ s.use_system_clipboard = UseSystemClipboard::Never
});
});
@@ -294,7 +294,7 @@ mod test {
cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<EditorSettings>(cx, |s| {
- s.scroll_beyond_last_line = Some(ScrollBeyondLastLine::Off)
+ s.scroll_beyond_last_line = ScrollBeyondLastLine::Off
});
});
@@ -542,7 +542,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await;
cx.update_global(|store: &mut SettingsStore, cx| {
- store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
+ store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = false);
});
cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal);
@@ -655,7 +655,7 @@ mod test {
// check that searching with unable search wrap
cx.update_global(|store: &mut SettingsStore, cx| {
- store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = Some(false));
+ store.update_user_settings::<EditorSettings>(cx, |s| s.search_wrap = false);
});
cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
cx.simulate_keystrokes("/ c c enter");
@@ -1300,7 +1300,7 @@ async fn test_command_alias(cx: &mut gpui::TestAppContext) {
store.update_user_settings::<WorkspaceSettings>(cx, |s| {
let mut aliases = HashMap::default();
aliases.insert("Q".to_string(), "upper".to_string());
- s.command_aliases = Some(aliases)
+ s.command_aliases = aliases
});
});
@@ -57,7 +57,7 @@ impl VimTestContext {
pub fn new_with_lsp(mut cx: EditorLspTestContext, enabled: bool) -> VimTestContext {
cx.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
- store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(enabled));
+ store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(enabled));
});
settings::KeymapFile::load_asset("keymaps/default-macos.json", cx).unwrap();
if enabled {
@@ -105,7 +105,7 @@ impl VimTestContext {
pub fn enable_vim(&mut self) {
self.cx.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
- store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(true));
+ store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(true));
});
})
}
@@ -113,7 +113,7 @@ impl VimTestContext {
pub fn disable_vim(&mut self) {
self.cx.update(|cx| {
SettingsStore::update_global(cx, |store, cx| {
- store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(false));
+ store.update_user_settings::<VimModeSetting>(cx, |s| *s = VimModeSetting(false));
});
})
}
@@ -46,6 +46,8 @@ use crate::state::ReplayableAction;
/// Whether or not to enable Vim mode.
///
/// Default: false
+#[derive(Copy, Clone, Default, Deserialize, Serialize, JsonSchema)]
+#[serde(default, transparent)]
pub struct VimModeSetting(pub bool);
/// An Action to Switch between modes
@@ -99,7 +101,7 @@ pub fn init(cx: &mut AppContext) {
let fs = workspace.app_state().fs.clone();
let currently_enabled = Vim::enabled(cx);
update_settings_file::<VimModeSetting>(fs, cx, move |setting, _| {
- *setting = Some(!currently_enabled)
+ *setting = VimModeSetting(!currently_enabled);
})
});
@@ -1068,12 +1070,10 @@ impl Vim {
impl Settings for VimModeSetting {
const KEY: Option<&'static str> = Some("vim_mode");
- type FileContent = Option<bool>;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
- Ok(Self(sources.user.copied().flatten().unwrap_or(
- sources.default.ok_or_else(Self::missing_default)?,
- )))
+ Ok(sources.user.copied().unwrap_or(*sources.default))
}
}
@@ -1089,7 +1089,8 @@ pub enum UseSystemClipboard {
OnYank,
}
-#[derive(Deserialize)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
struct VimSettings {
pub toggle_relative_line_numbers: bool,
pub use_system_clipboard: UseSystemClipboard,
@@ -1098,19 +1099,22 @@ struct VimSettings {
pub custom_digraphs: HashMap<String, Arc<str>>,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-struct VimSettingsContent {
- pub toggle_relative_line_numbers: Option<bool>,
- pub use_system_clipboard: Option<UseSystemClipboard>,
- pub use_multiline_find: Option<bool>,
- pub use_smartcase_find: Option<bool>,
- pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
+impl Default for VimSettings {
+ fn default() -> Self {
+ Self {
+ toggle_relative_line_numbers: false,
+ use_system_clipboard: UseSystemClipboard::Always,
+ use_multiline_find: false,
+ use_smartcase_find: false,
+ custom_digraphs: Default::default(),
+ }
+ }
}
impl Settings for VimSettings {
const KEY: Option<&'static str> = Some("vim");
- type FileContent = VimSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -177,7 +177,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
.report_setting_event("keymap", base_keymap.to_string());
update_settings_file::<BaseKeymap>(self.fs.clone(), cx, move |setting, _| {
- *setting = Some(base_keymap)
+ *setting = base_keymap;
});
}
@@ -87,15 +87,15 @@ impl BaseKeymap {
impl Settings for BaseKeymap {
const KEY: Option<&'static str> = Some("base_keymap");
- type FileContent = Option<Self>;
+ type FileContent = Self;
fn load(
sources: SettingsSources<Self::FileContent>,
_: &mut gpui::AppContext,
) -> anyhow::Result<Self> {
- if let Some(Some(user_value)) = sources.user.copied() {
+ if let Some(user_value) = sources.user.copied() {
return Ok(user_value);
}
- sources.default.ok_or_else(Self::missing_default)
+ Ok(*sources.default)
}
}
@@ -188,7 +188,7 @@ impl Render for WelcomePage {
this.update_settings::<VimModeSetting>(
selection,
cx,
- |setting, value| *setting = Some(value),
+ |setting, value| *setting = VimModeSetting(value),
);
}),
))
@@ -36,20 +36,49 @@ use util::ResultExt;
pub const LEADER_UPDATE_THROTTLE: Duration = Duration::from_millis(200);
-#[derive(Deserialize)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct ItemSettings {
+ /// Whether to show the Git file status on a tab item.
pub git_status: bool,
+ /// Position of the close button in a tab.
pub close_position: ClosePosition,
+ /// Whether to show the file icon for a tab.
pub file_icons: bool,
}
-#[derive(Deserialize)]
+impl Default for ItemSettings {
+ fn default() -> Self {
+ Self {
+ git_status: false,
+ close_position: ClosePosition::Right,
+ file_icons: false,
+ }
+ }
+}
+
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct PreviewTabsSettings {
+ /// Whether to show opened editors as preview tabs.
+ /// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.
pub enabled: bool,
+ /// Whether to open tabs in preview mode when selected from the file finder.
pub enable_preview_from_file_finder: bool,
+ /// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
pub enable_preview_from_code_navigation: bool,
}
+impl Default for PreviewTabsSettings {
+ fn default() -> Self {
+ Self {
+ enabled: true,
+ enable_preview_from_file_finder: false,
+ enable_preview_from_code_navigation: false,
+ }
+ }
+}
+
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ClosePosition {
@@ -67,43 +96,10 @@ impl ClosePosition {
}
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct ItemSettingsContent {
- /// Whether to show the Git file status on a tab item.
- ///
- /// Default: false
- git_status: Option<bool>,
- /// Position of the close button in a tab.
- ///
- /// Default: right
- close_position: Option<ClosePosition>,
- /// Whether to show the file icon for a tab.
- ///
- /// Default: false
- file_icons: Option<bool>,
-}
-
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct PreviewTabsSettingsContent {
- /// Whether to show opened editors as preview tabs.
- /// Preview tabs do not stay open, are reused until explicitly set to be kept open opened (via double-click or editing) and show file names in italic.
- ///
- /// Default: true
- enabled: Option<bool>,
- /// Whether to open tabs in preview mode when selected from the file finder.
- ///
- /// Default: false
- enable_preview_from_file_finder: Option<bool>,
- /// Whether a preview tab gets replaced when code navigation is used to navigate away from the tab.
- ///
- /// Default: false
- enable_preview_from_code_navigation: Option<bool>,
-}
-
impl Settings for ItemSettings {
const KEY: Option<&'static str> = Some("tabs");
- type FileContent = ItemSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -113,7 +109,7 @@ impl Settings for ItemSettings {
impl Settings for PreviewTabsSettings {
const KEY: Option<&'static str> = Some("preview_tabs");
- type FileContent = PreviewTabsSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -6418,7 +6418,7 @@ mod tests {
item.update(cx, |item, cx| {
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
- settings.autosave = Some(AutosaveSetting::OnWindowChange);
+ settings.autosave = AutosaveSetting::OnWindowChange;
})
});
item.is_dirty = true;
@@ -6438,7 +6438,7 @@ mod tests {
cx.focus_self();
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
- settings.autosave = Some(AutosaveSetting::OnFocusChange);
+ settings.autosave = AutosaveSetting::OnFocusChange;
})
});
item.is_dirty = true;
@@ -6461,7 +6461,7 @@ mod tests {
item.update(cx, |item, cx| {
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
- settings.autosave = Some(AutosaveSetting::AfterDelay { milliseconds: 500 });
+ settings.autosave = AutosaveSetting::AfterDelay { milliseconds: 500 };
})
});
item.is_dirty = true;
@@ -6480,7 +6480,7 @@ mod tests {
item.update(cx, |item, cx| {
SettingsStore::update_global(cx, |settings, cx| {
settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
- settings.autosave = Some(AutosaveSetting::OnFocusChange);
+ settings.autosave = AutosaveSetting::OnFocusChange;
})
});
item.is_dirty = true;
@@ -5,22 +5,58 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
-#[derive(Deserialize)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct WorkspaceSettings {
+ /// Scale by which to zoom the active pane.
+ /// When set to 1.0, the active pane has the same size as others,
+ /// but when set to a larger value, the active pane takes up more space.
pub active_pane_magnification: f32,
+ /// Direction to split horizontally.
pub pane_split_direction_horizontal: PaneSplitDirectionHorizontal,
+ /// Direction to split vertically.
pub pane_split_direction_vertical: PaneSplitDirectionVertical,
+ /// Centered layout related settings.
pub centered_layout: CenteredLayoutSettings,
+ /// Whether or not to prompt the user to confirm before closing the application.
pub confirm_quit: bool,
+ /// Whether or not to show the call status icon in the status bar.
pub show_call_status_icon: bool,
+ /// When to automatically save edited buffers.
pub autosave: AutosaveSetting,
+ /// Controls previous session restoration in freshly launched Zed instance.
pub restore_on_startup: RestoreOnStartupBehavior,
+ /// The size of the workspace split drop targets on the outer edges.
+ /// Given as a fraction that will be multiplied by the smaller dimension of the workspace.
pub drop_target_size: f32,
+ /// Whether to close the window when using 'close active item' on a workspace with no tabs
pub when_closing_with_no_tabs: CloseWindowWhenNoItems,
+ /// Whether to use the system provided dialogs for Open and Save As.
+ /// When set to false, Zed will use the built-in keyboard-first pickers.
pub use_system_path_prompts: bool,
+ /// Aliases for the command palette. When you type a key in this map,
+ /// it will be assumed to equal the value.
pub command_aliases: HashMap<String, String>,
}
+impl Default for WorkspaceSettings {
+ fn default() -> Self {
+ Self {
+ active_pane_magnification: 1.0,
+ pane_split_direction_horizontal: PaneSplitDirectionHorizontal::Up,
+ pane_split_direction_vertical: PaneSplitDirectionVertical::Left,
+ centered_layout: CenteredLayoutSettings::default(),
+ confirm_quit: false,
+ show_call_status_icon: true,
+ autosave: AutosaveSetting::Off,
+ restore_on_startup: RestoreOnStartupBehavior::default(),
+ drop_target_size: 0.2,
+ when_closing_with_no_tabs: CloseWindowWhenNoItems::default(),
+ use_system_path_prompts: true,
+ command_aliases: HashMap::default(),
+ }
+ }
+}
#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CloseWindowWhenNoItems {
@@ -55,77 +91,22 @@ pub enum RestoreOnStartupBehavior {
LastSession,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct WorkspaceSettingsContent {
- /// Scale by which to zoom the active pane.
- /// When set to 1.0, the active pane has the same size as others,
- /// but when set to a larger value, the active pane takes up more space.
- ///
- /// Default: `1.0`
- pub active_pane_magnification: Option<f32>,
- // Direction to split horizontally.
- //
- // Default: "up"
- pub pane_split_direction_horizontal: Option<PaneSplitDirectionHorizontal>,
- // Direction to split vertically.
- //
- // Default: "left"
- pub pane_split_direction_vertical: Option<PaneSplitDirectionVertical>,
- // Centered layout related settings.
- pub centered_layout: Option<CenteredLayoutSettings>,
- /// Whether or not to prompt the user to confirm before closing the application.
- ///
- /// Default: false
- pub confirm_quit: Option<bool>,
- /// Whether or not to show the call status icon in the status bar.
- ///
- /// Default: true
- pub show_call_status_icon: Option<bool>,
- /// When to automatically save edited buffers.
- ///
- /// Default: off
- pub autosave: Option<AutosaveSetting>,
- /// Controls previous session restoration in freshly launched Zed instance.
- /// Values: none, last_workspace, last_session
- /// Default: last_session
- pub restore_on_startup: Option<RestoreOnStartupBehavior>,
- /// The size of the workspace split drop targets on the outer edges.
- /// Given as a fraction that will be multiplied by the smaller dimension of the workspace.
- ///
- /// Default: `0.2` (20% of the smaller dimension of the workspace)
- pub drop_target_size: Option<f32>,
- /// Whether to close the window when using 'close active item' on a workspace with no tabs
- ///
- /// Default: auto ("on" on macOS, "off" otherwise)
- pub when_closing_with_no_tabs: Option<CloseWindowWhenNoItems>,
- /// Whether to use the system provided dialogs for Open and Save As.
- /// When set to false, Zed will use the built-in keyboard-first pickers.
- ///
- /// Default: true
- pub use_system_path_prompts: Option<bool>,
- /// Aliases for the command palette. When you type a key in this map,
- /// it will be assumed to equal the value.
- ///
- /// Default: true
- pub command_aliases: Option<HashMap<String, String>>,
-}
-
-#[derive(Deserialize)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct TabBarSettings {
+ /// Whether or not to show the tab bar in the editor.
pub show: bool,
+ /// Whether or not to show the navigation history buttons in the tab bar.
pub show_nav_history_buttons: bool,
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
-pub struct TabBarSettingsContent {
- /// Whether or not to show the tab bar in the editor.
- ///
- /// Default: true
- pub show: Option<bool>,
- /// Whether or not to show the navigation history buttons in the tab bar.
- ///
- /// Default: true
- pub show_nav_history_buttons: Option<bool>,
+impl Default for TabBarSettings {
+ fn default() -> Self {
+ Self {
+ show_nav_history_buttons: true,
+ show: true,
+ }
+ }
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -163,17 +144,26 @@ pub struct CenteredLayoutSettings {
///
/// Default: 0.2
pub left_padding: Option<f32>,
- // The relative width of the right padding of the central pane from the
- // workspace when the centered layout is used.
+ /// The relative width of the right padding of the central pane from the
+ /// workspace when the centered layout is used.
///
/// Default: 0.2
pub right_padding: Option<f32>,
}
+impl Default for CenteredLayoutSettings {
+ fn default() -> Self {
+ Self {
+ left_padding: Some(0.2),
+ right_padding: Some(0.2),
+ }
+ }
+}
+
impl Settings for WorkspaceSettings {
const KEY: Option<&'static str> = None;
- type FileContent = WorkspaceSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -183,7 +173,7 @@ impl Settings for WorkspaceSettings {
impl Settings for TabBarSettings {
const KEY: Option<&'static str> = Some("tab_bar");
- type FileContent = TabBarSettingsContent;
+ type FileContent = Self;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
sources.json_merge()
@@ -25,7 +25,8 @@ impl WorktreeSettings {
}
}
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Serialize, Deserialize, JsonSchema)]
+#[serde(default)]
pub struct WorktreeSettingsContent {
/// Completely ignore files matching globs from `file_scan_exclusions`
///
@@ -39,12 +40,42 @@ pub struct WorktreeSettingsContent {
/// "**/.classpath",
/// "**/.settings"
/// ]
- #[serde(default)]
- pub file_scan_exclusions: Option<Vec<String>>,
+ pub file_scan_exclusions: Vec<String>,
/// Treat the files matching these globs as `.env` files.
/// Default: [ "**/.env*" ]
- pub private_files: Option<Vec<String>>,
+ pub private_files: Vec<String>,
+}
+
+impl Default for WorktreeSettingsContent {
+ fn default() -> Self {
+ Self {
+ private_files: [
+ "**/.env*",
+ "**/*.pem",
+ "**/*.key",
+ "**/*.cert",
+ "**/*.crt",
+ "**/secrets.yml",
+ ]
+ .into_iter()
+ .map(str::to_owned)
+ .collect(),
+ file_scan_exclusions: [
+ "**/.git",
+ "**/.svn",
+ "**/.hg",
+ "**/CVS",
+ "**/.DS_Store",
+ "**/Thumbs.db",
+ "**/.classpath",
+ "**/.settings",
+ ]
+ .into_iter()
+ .map(str::to_owned)
+ .collect(),
+ }
+ }
}
impl Settings for WorktreeSettings {
@@ -57,8 +88,8 @@ impl Settings for WorktreeSettings {
_: &mut AppContext,
) -> anyhow::Result<Self> {
let result: WorktreeSettingsContent = sources.json_merge()?;
- let mut file_scan_exclusions = result.file_scan_exclusions.unwrap_or_default();
- let mut private_files = result.private_files.unwrap_or_default();
+ let mut file_scan_exclusions = result.file_scan_exclusions;
+ let mut private_files = result.private_files;
file_scan_exclusions.sort();
private_files.sort();
Ok(Self {
@@ -673,7 +673,7 @@ async fn test_rescan_with_gitignore(cx: &mut TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(Vec::new());
+ project_settings.file_scan_exclusions = Vec::new();
});
});
});
@@ -910,7 +910,7 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
project_settings.file_scan_exclusions =
- Some(vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()]);
+ vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()];
});
});
});
@@ -945,8 +945,7 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions =
- Some(vec!["**/node_modules/**".to_string()]);
+ project_settings.file_scan_exclusions = vec!["**/node_modules/**".to_string()];
});
});
});
@@ -1009,11 +1008,11 @@ async fn test_fs_events_in_exclusions(cx: &mut TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec![
+ project_settings.file_scan_exclusions = vec![
"**/.git".to_string(),
"node_modules/".to_string(),
"build_output".to_string(),
- ]);
+ ];
});
});
});
@@ -1996,7 +1996,7 @@ mod tests {
cx.update_global::<SettingsStore, _>(|store, cx| {
store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
project_settings.file_scan_exclusions =
- Some(vec!["excluded_dir".to_string(), "**/.git".to_string()]);
+ vec!["excluded_dir".to_string(), "**/.git".to_string()];
});
});
});