diff --git a/crates/diagnostics/src/diagnostics_tests.rs b/crates/diagnostics/src/diagnostics_tests.rs index 2d86361df003ceab114d1e4cd3adabbbfbf9b497..74a235697834b120dd1b0dbb55aae03fe950be64 100644 --- a/crates/diagnostics/src/diagnostics_tests.rs +++ b/crates/diagnostics/src/diagnostics_tests.rs @@ -1341,7 +1341,7 @@ async fn test_hover_diagnostic_and_info_popovers(cx: &mut gpui::TestAppContext) range: Some(range), })) }); - let delay = cx.update(|_, cx| EditorSettings::get_global(cx).hover_popover_delay + 1); + let delay = cx.update(|_, cx| EditorSettings::get_global(cx).hover_popover_delay.0 + 1); cx.background_executor .advance_clock(Duration::from_millis(delay)); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 2ff8b585c3f228f70246947bed8c2e6da221bd37..9baa1c892e8dc7e0f62cdc2c0e7abbed82ae9cdd 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6772,7 +6772,7 @@ impl Editor { if let Some(state) = &mut self.inline_blame_popover { state.hide_task.take(); } else { - let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay; + let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0; let blame_entry = blame_entry.clone(); let show_task = cx.spawn(async move |editor, cx| { if !ignore_timeout { @@ -6863,7 +6863,7 @@ impl Editor { return None; } - let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce; + let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0; self.document_highlights_task = Some(cx.spawn(async move |this, cx| { cx.background_executor() .timer(Duration::from_millis(debounce)) diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 9ecbbff97612d391e56271f19331160ef08ba534..dc67ab3ed6c8cfdbe88809e32d615789c01eef60 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -5,7 +5,7 @@ use language::CursorShape; use project::project_settings::DiagnosticSeverity; use settings::Settings; pub use settings::{ - CurrentLineHighlight, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer, + CurrentLineHighlight, DelayMs, DisplayIn, DocumentColorsRenderMode, DoubleClickInMultibuffer, GoToDefinitionFallback, HideMouseMode, MinimapThumb, MinimapThumbBorder, MultiCursorModifier, ScrollBeyondLastLine, ScrollbarDiagnostics, SeedQuerySetting, ShowMinimap, SnippetSortOrder, }; @@ -20,9 +20,9 @@ pub struct EditorSettings { pub current_line_highlight: CurrentLineHighlight, pub selection_highlight: bool, pub rounded_selection: bool, - pub lsp_highlight_debounce: u64, + pub lsp_highlight_debounce: DelayMs, pub hover_popover_enabled: bool, - pub hover_popover_delay: u64, + pub hover_popover_delay: DelayMs, pub toolbar: Toolbar, pub scrollbar: Scrollbar, pub minimap: Minimap, @@ -147,7 +147,7 @@ pub struct DragAndDropSelection { /// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created. /// /// Default: 300 - pub delay: u64, + pub delay: DelayMs, } /// Default options for buffer and project search items. diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2dcb9996c37d54ad352795b39a0b28ece2827759..52e73bd01c1712371805610f2aff2de6d7aa2d4b 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1070,7 +1070,10 @@ impl EditorElement { ref mouse_down_time, } => { let drag_and_drop_delay = Duration::from_millis( - EditorSettings::get_global(cx).drag_and_drop_selection.delay, + EditorSettings::get_global(cx) + .drag_and_drop_selection + .delay + .0, ); if mouse_down_time.elapsed() >= drag_and_drop_delay { let drop_cursor = Selection { @@ -6172,7 +6175,10 @@ impl EditorElement { } = &editor.selection_drag_state { let drag_and_drop_delay = Duration::from_millis( - EditorSettings::get_global(cx).drag_and_drop_selection.delay, + EditorSettings::get_global(cx) + .drag_and_drop_selection + .delay + .0, ); if mouse_down_time.elapsed() >= drag_and_drop_delay { window.set_cursor_style( diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 2b0ebf52805493d008c8b69ec4ff86991d6c743d..9db04363b27959d8f8b81539da4ba65c75fbeb02 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -154,7 +154,7 @@ pub fn hover_at_inlay( hide_hover(editor, cx); } - let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay; + let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0; let task = cx.spawn_in(window, async move |this, cx| { async move { @@ -275,7 +275,7 @@ fn show_hover( return None; } - let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay; + let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0; let all_diagnostics_active = editor.active_diagnostics == ActiveDiagnostic::All; let active_group_id = if let ActiveDiagnostic::Group(group) = &editor.active_diagnostics { Some(group.group_id) @@ -1004,7 +1004,7 @@ mod tests { use text::Bias; fn get_hover_popover_delay(cx: &gpui::TestAppContext) -> u64 { - cx.read(|cx: &App| -> u64 { EditorSettings::get_global(cx).hover_popover_delay }) + cx.read(|cx: &App| -> u64 { EditorSettings::get_global(cx).hover_popover_delay.0 }) } impl InfoPopover { diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 788cd0212a094154e6c4e3b3eb0d379ecadaf11c..676fac507252646a0650be87dc7a22689a1e70d0 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -331,7 +331,7 @@ pub struct InlineBlameSettings { /// after a delay once the cursor stops moving. /// /// Default: 0 - pub delay_ms: std::time::Duration, + pub delay_ms: settings::DelayMs, /// The amount of padding between the end of the source line and the start /// of the inline blame in units of columns. /// @@ -357,8 +357,8 @@ pub struct BlameSettings { impl GitSettings { pub fn inline_blame_delay(&self) -> Option { - if self.inline_blame.delay_ms.as_millis() > 0 { - Some(self.inline_blame.delay_ms) + if self.inline_blame.delay_ms.0 > 0 { + Some(Duration::from_millis(self.inline_blame.delay_ms.0)) } else { None } @@ -452,7 +452,7 @@ impl Settings for ProjectSettings { let inline = git.inline_blame.unwrap(); InlineBlameSettings { enabled: inline.enabled.unwrap(), - delay_ms: std::time::Duration::from_millis(inline.delay_ms.unwrap()), + delay_ms: inline.delay_ms.unwrap(), padding: inline.padding.unwrap(), min_column: inline.min_column.unwrap(), show_commit_summary: inline.show_commit_summary.unwrap(), @@ -504,11 +504,11 @@ impl Settings for ProjectSettings { include_warnings: diagnostics.include_warnings.unwrap(), lsp_pull_diagnostics: LspPullDiagnosticsSettings { enabled: lsp_pull_diagnostics.enabled.unwrap(), - debounce_ms: lsp_pull_diagnostics.debounce_ms.unwrap(), + debounce_ms: lsp_pull_diagnostics.debounce_ms.unwrap().0, }, inline: InlineDiagnosticsSettings { enabled: inline_diagnostics.enabled.unwrap(), - update_debounce_ms: inline_diagnostics.update_debounce_ms.unwrap(), + update_debounce_ms: inline_diagnostics.update_debounce_ms.unwrap().0, padding: inline_diagnostics.padding.unwrap(), min_column: inline_diagnostics.min_column.unwrap(), max_severity: inline_diagnostics.max_severity.map(Into::into), diff --git a/crates/settings/src/settings_content.rs b/crates/settings/src/settings_content.rs index 92493557eeeb5f28c6a4d25fca3f9e38f8eef6bb..045bc21613141ca30f125ab25757a3b3a97307b0 100644 --- a/crates/settings/src/settings_content.rs +++ b/crates/settings/src/settings_content.rs @@ -985,3 +985,33 @@ impl merge_from::MergeFrom for SaturatingBool { self.0 |= other.0 } } + +#[derive( + Copy, + Clone, + Default, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Serialize, + Deserialize, + MergeFrom, + JsonSchema, + derive_more::FromStr, +)] +#[serde(transparent)] +pub struct DelayMs(pub u64); + +impl From for DelayMs { + fn from(n: u64) -> Self { + Self(n) + } +} + +impl std::fmt::Display for DelayMs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}ms", self.0) + } +} diff --git a/crates/settings/src/settings_content/editor.rs b/crates/settings/src/settings_content/editor.rs index 7bc447346c8a20e53640928a6ba0ca28e10d92e7..4b00cd24500999eb917bf2117fd17b557d2509ae 100644 --- a/crates/settings/src/settings_content/editor.rs +++ b/crates/settings/src/settings_content/editor.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use settings_macros::MergeFrom; -use crate::{DiagnosticSeverityContent, ShowScrollbar}; +use crate::{DelayMs, DiagnosticSeverityContent, ShowScrollbar}; #[skip_serializing_none] #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)] @@ -45,7 +45,7 @@ pub struct EditorSettingsContent { /// server based on the current cursor location. /// /// Default: 75 - pub lsp_highlight_debounce: Option, + pub lsp_highlight_debounce: Option, /// Whether to show the informational hover box when moving the mouse /// over symbols in the editor. /// @@ -54,7 +54,7 @@ pub struct EditorSettingsContent { /// Time to wait in milliseconds before showing the informational hover box. /// /// Default: 300 - pub hover_popover_delay: Option, + pub hover_popover_delay: Option, /// Toolbar related settings pub toolbar: Option, /// Scrollbar related settings @@ -722,7 +722,7 @@ pub struct DragAndDropSelectionContent { /// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created. /// /// Default: 300 - pub delay: Option, + pub delay: Option, } /// When to show the minimap in the editor. @@ -804,6 +804,12 @@ impl Display for MinimumContrast { } } +impl From for MinimumContrast { + fn from(x: f32) -> Self { + Self(x) + } +} + /// Opacity of the inactive panes. 0 means transparent, 1 means opaque. /// /// Valid range: 0.0 to 1.0 @@ -828,3 +834,9 @@ impl Display for InactiveOpacity { write!(f, "{:.1}", self.0) } } + +impl From for InactiveOpacity { + fn from(x: f32) -> Self { + Self(x) + } +} diff --git a/crates/settings/src/settings_content/project.rs b/crates/settings/src/settings_content/project.rs index d421a7bb2aefb92f0c7cd1de1c89fe1fee95e3ec..a26a72e7aa32d513dd5afe3c7aa5078f3e3201a5 100644 --- a/crates/settings/src/settings_content/project.rs +++ b/crates/settings/src/settings_content/project.rs @@ -8,7 +8,8 @@ use settings_macros::MergeFrom; use util::serde::default_true; use crate::{ - AllLanguageSettingsContent, ExtendingVec, ProjectTerminalSettingsContent, SlashCommandSettings, + AllLanguageSettingsContent, DelayMs, ExtendingVec, ProjectTerminalSettingsContent, + SlashCommandSettings, }; #[skip_serializing_none] @@ -310,7 +311,7 @@ pub struct InlineBlameSettings { /// after a delay once the cursor stops moving. /// /// Default: 0 - pub delay_ms: Option, + pub delay_ms: Option, /// The amount of padding between the end of the source line and the start /// of the inline blame in units of columns. /// @@ -397,7 +398,7 @@ pub struct LspPullDiagnosticsSettingsContent { /// 0 turns the debounce off. /// /// Default: 50 - pub debounce_ms: Option, + pub debounce_ms: Option, } #[skip_serializing_none] @@ -413,7 +414,7 @@ pub struct InlineDiagnosticsSettingsContent { /// last editor event. /// /// Default: 150 - pub update_debounce_ms: Option, + pub update_debounce_ms: Option, /// The amount of padding between the end of the source line and the start /// of the inline diagnostic in units of columns. /// diff --git a/crates/settings/src/settings_content/theme.rs b/crates/settings/src/settings_content/theme.rs index 45640ae3ae37321498bb3dafd6d07b2ba1f2d92e..c988b98a4ef04c7ff5e9b20eaf9e2bebeccb88fb 100644 --- a/crates/settings/src/settings_content/theme.rs +++ b/crates/settings/src/settings_content/theme.rs @@ -112,6 +112,12 @@ impl Display for CodeFade { } } +impl From for CodeFade { + fn from(x: f32) -> Self { + Self(x) + } +} + fn default_font_features() -> Option { Some(FontFeatures::default()) } diff --git a/crates/settings/src/settings_content/workspace.rs b/crates/settings/src/settings_content/workspace.rs index 7ebb468f79bf195fb9d97b8d52dd6e728d8c8f99..78b17eeb883dd83b16f45c0cabfc3be9a7840eae 100644 --- a/crates/settings/src/settings_content/workspace.rs +++ b/crates/settings/src/settings_content/workspace.rs @@ -6,7 +6,9 @@ use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use settings_macros::MergeFrom; -use crate::{DockPosition, DockSide, InactiveOpacity, ScrollbarSettingsContent, ShowIndentGuides}; +use crate::{ + DelayMs, DockPosition, DockSide, InactiveOpacity, ScrollbarSettingsContent, ShowIndentGuides, +}; #[skip_serializing_none] #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema, MergeFrom)] @@ -386,7 +388,7 @@ pub enum AutosaveSetting { /// Disable autosave. Off, /// Save after inactivity period of `milliseconds`. - AfterDelay { milliseconds: u64 }, + AfterDelay { milliseconds: DelayMs }, /// Autosave when focus changes. OnFocusChange, /// Autosave when the active window changes. diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index e1cce43f6227bb26a36be871c31cf1143aab5c70..c07f75a9e3b96bea689f5d6dda22d0742800d321 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -259,7 +259,7 @@ impl VsCodeSettings { gutter: self.gutter_content(), hide_mouse: None, horizontal_scroll_margin: None, - hover_popover_delay: self.read_u64("editor.hover.delay"), + hover_popover_delay: self.read_u64("editor.hover.delay").map(Into::into), hover_popover_enabled: self.read_bool("editor.hover.enabled"), inline_code_actions: None, jupyter: None, @@ -791,7 +791,8 @@ impl VsCodeSettings { milliseconds: self .read_value("files.autoSaveDelay") .and_then(|v| v.as_u64()) - .unwrap_or(1000), + .unwrap_or(1000) + .into(), }), "onFocusChange" => Some(AutosaveSetting::OnFocusChange), "onWindowChange" => Some(AutosaveSetting::OnWindowChange), diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 7856164a12a34643b9a223023a8ab27922c68906..138d54fc4a539045b04ca1091ad8b55049fbf1d5 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -417,6 +417,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::>(render_number_field) .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) + .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) .add_basic_renderer::(render_number_field) diff --git a/crates/ui_input/src/number_field.rs b/crates/ui_input/src/number_field.rs index b72566947771be6411ce879a48092f508909b18f..3ae1d77c0400ea474864087bf3a4a5f4705a2e41 100644 --- a/crates/ui_input/src/number_field.rs +++ b/crates/ui_input/src/number_field.rs @@ -8,7 +8,7 @@ use std::{ use editor::{Editor, EditorStyle}; use gpui::{ClickEvent, Entity, FocusHandle, Focusable, FontWeight, Modifiers}; -use settings::{CodeFade, InactiveOpacity, MinimumContrast}; +use settings::{CodeFade, DelayMs, InactiveOpacity, MinimumContrast}; use ui::prelude::*; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] @@ -31,102 +31,47 @@ pub trait NumberFieldType: Display + Copy + Clone + Sized + PartialOrd + FromStr fn saturating_sub(self, rhs: Self) -> Self; } -impl NumberFieldType for gpui::FontWeight { - fn default_step() -> Self { - FontWeight(50.0) - } - fn large_step() -> Self { - FontWeight(100.0) - } - fn small_step() -> Self { - FontWeight(10.0) - } - fn min_value() -> Self { - gpui::FontWeight::THIN - } - fn max_value() -> Self { - gpui::FontWeight::BLACK - } - fn saturating_add(self, rhs: Self) -> Self { - FontWeight((self.0 + rhs.0).min(Self::max_value().0)) - } - fn saturating_sub(self, rhs: Self) -> Self { - FontWeight((self.0 - rhs.0).max(Self::min_value().0)) - } -} +macro_rules! impl_newtype_numeric_stepper { + ($type:ident, $default:expr, $large:expr, $small:expr, $min:expr, $max:expr) => { + impl NumberFieldType for $type { + fn default_step() -> Self { + $default.into() + } -impl NumberFieldType for settings::CodeFade { - fn default_step() -> Self { - CodeFade(0.10) - } - fn large_step() -> Self { - CodeFade(0.20) - } - fn small_step() -> Self { - CodeFade(0.05) - } - fn min_value() -> Self { - CodeFade(0.0) - } - fn max_value() -> Self { - CodeFade(0.9) - } - fn saturating_add(self, rhs: Self) -> Self { - CodeFade((self.0 + rhs.0).min(Self::max_value().0)) - } - fn saturating_sub(self, rhs: Self) -> Self { - CodeFade((self.0 - rhs.0).max(Self::min_value().0)) - } -} + fn large_step() -> Self { + $large.into() + } -impl NumberFieldType for settings::InactiveOpacity { - fn default_step() -> Self { - InactiveOpacity(0.10) - } - fn large_step() -> Self { - InactiveOpacity(0.20) - } - fn small_step() -> Self { - InactiveOpacity(0.05) - } - fn min_value() -> Self { - InactiveOpacity(0.0) - } - fn max_value() -> Self { - InactiveOpacity(1.0) - } - fn saturating_add(self, rhs: Self) -> Self { - InactiveOpacity((self.0 + rhs.0).min(Self::max_value().0)) - } - fn saturating_sub(self, rhs: Self) -> Self { - InactiveOpacity((self.0 - rhs.0).max(Self::min_value().0)) - } -} + fn small_step() -> Self { + $small.into() + } -impl NumberFieldType for settings::MinimumContrast { - fn default_step() -> Self { - MinimumContrast(1.0) - } - fn large_step() -> Self { - MinimumContrast(10.0) - } - fn small_step() -> Self { - MinimumContrast(0.5) - } - fn min_value() -> Self { - MinimumContrast(0.0) - } - fn max_value() -> Self { - MinimumContrast(106.0) - } - fn saturating_add(self, rhs: Self) -> Self { - MinimumContrast((self.0 + rhs.0).min(Self::max_value().0)) - } - fn saturating_sub(self, rhs: Self) -> Self { - MinimumContrast((self.0 - rhs.0).max(Self::min_value().0)) - } + fn min_value() -> Self { + $min.into() + } + + fn max_value() -> Self { + $max.into() + } + + fn saturating_add(self, rhs: Self) -> Self { + $type((self.0 + rhs.0).min(Self::max_value().0)) + } + + fn saturating_sub(self, rhs: Self) -> Self { + $type((self.0 - rhs.0).max(Self::min_value().0)) + } + } + }; } +#[rustfmt::skip] +impl_newtype_numeric_stepper!(FontWeight, 50., 100., 10., FontWeight::THIN, FontWeight::BLACK); +impl_newtype_numeric_stepper!(CodeFade, 0.1, 0.2, 0.05, 0.0, 0.9); +impl_newtype_numeric_stepper!(InactiveOpacity, 0.1, 0.2, 0.05, 0.0, 1.0); +impl_newtype_numeric_stepper!(MinimumContrast, 1., 10., 0.5, 0.0, 106.0); +impl_newtype_numeric_stepper!(DelayMs, 100, 500, 10, 0, 2000); + macro_rules! impl_numeric_stepper_int { ($type:ident) => { impl NumberFieldType for $type { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 1a6a09c38d0aea0c2df59947455628ec4a7ccd43..bc755d851036d10f04b76866b3d7b94673f2df84 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -811,7 +811,7 @@ impl ItemHandle for Entity { let autosave = item.workspace_settings(cx).autosave; if let AutosaveSetting::AfterDelay { milliseconds } = autosave { - let delay = Duration::from_millis(milliseconds); + let delay = Duration::from_millis(milliseconds.0); let item = item.clone(); pending_autosave.fire_new( delay, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index bbb9ee767196c062707efcc2618670cf09da4e87..053b578ff9082bd933440a36abab47c9b84928bd 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -8799,8 +8799,9 @@ mod tests { item.update(cx, |item, cx| { SettingsStore::update_global(cx, |settings, cx| { settings.update_user_settings(cx, |settings| { - settings.workspace.autosave = - Some(AutosaveSetting::AfterDelay { milliseconds: 500 }); + settings.workspace.autosave = Some(AutosaveSetting::AfterDelay { + milliseconds: 500.into(), + }); }) }); item.is_dirty = true;