Add DelayMs type for settings (#40659)

Closes #40610

Release Notes:

- N/A
This commit is contained in:
Julia Ryan 2025-10-19 21:34:55 -07:00 committed by GitHub
parent 59b87d5c71
commit 1d3bf9789e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 132 additions and 127 deletions

View file

@ -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));

View file

@ -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))

View file

@ -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.

View file

@ -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(

View file

@ -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 {

View file

@ -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<Duration> {
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),

View file

@ -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<u64> 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)
}
}

View file

@ -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<u64>,
pub lsp_highlight_debounce: Option<DelayMs>,
/// 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<u64>,
pub hover_popover_delay: Option<DelayMs>,
/// Toolbar related settings
pub toolbar: Option<ToolbarContent>,
/// 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<u64>,
pub delay: Option<DelayMs>,
}
/// When to show the minimap in the editor.
@ -804,6 +804,12 @@ impl Display for MinimumContrast {
}
}
impl From<f32> 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<f32> for InactiveOpacity {
fn from(x: f32) -> Self {
Self(x)
}
}

View file

@ -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<u64>,
pub delay_ms: Option<DelayMs>,
/// 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<u64>,
pub debounce_ms: Option<DelayMs>,
}
#[skip_serializing_none]
@ -413,7 +414,7 @@ pub struct InlineDiagnosticsSettingsContent {
/// last editor event.
///
/// Default: 150
pub update_debounce_ms: Option<u64>,
pub update_debounce_ms: Option<DelayMs>,
/// The amount of padding between the end of the source line and the start
/// of the inline diagnostic in units of columns.
///

View file

@ -112,6 +112,12 @@ impl Display for CodeFade {
}
}
impl From<f32> for CodeFade {
fn from(x: f32) -> Self {
Self(x)
}
}
fn default_font_features() -> Option<FontFeatures> {
Some(FontFeatures::default())
}

View file

@ -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.

View file

@ -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),

View file

@ -417,6 +417,7 @@ fn init_renderers(cx: &mut App) {
.add_basic_renderer::<NonZero<usize>>(render_number_field)
.add_basic_renderer::<NonZeroU32>(render_number_field)
.add_basic_renderer::<settings::CodeFade>(render_number_field)
.add_basic_renderer::<settings::DelayMs>(render_number_field)
.add_basic_renderer::<gpui::FontWeight>(render_number_field)
.add_basic_renderer::<settings::InactiveOpacity>(render_number_field)
.add_basic_renderer::<settings::MinimumContrast>(render_number_field)

View file

@ -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,101 +31,46 @@ 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()
}
fn large_step() -> Self {
$large.into()
}
fn small_step() -> Self {
$small.into()
}
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))
}
}
};
}
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))
}
}
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))
}
}
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))
}
}
#[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) => {

View file

@ -811,7 +811,7 @@ impl<T: Item> ItemHandle for Entity<T> {
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,

View file

@ -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;