Add setting for hover delay (#22006)

Aaron Feickert created

This PR adds a new `hover_popover_delay` setting that allows the user to
specify how long to wait before showing informational hover boxes. It
defaults to the existing delay.

Release Notes:

- Added a setting to control the delay for informational hover boxes

Change summary

assets/settings/default.json         |  2 ++
crates/editor/src/editor_settings.rs |  6 +++++-
crates/editor/src/hover_popover.rs   | 29 ++++++++++++++++++-----------
3 files changed, 25 insertions(+), 12 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -101,6 +101,8 @@
   // Whether to show the informational hover box when moving the mouse
   // over symbols in the editor.
   "hover_popover_enabled": true,
+  // Time to wait before showing the informational hover box
+  "hover_popover_delay": 350,
   // Whether to confirm before quitting Zed.
   "confirm_quit": false,
   // Whether to restore last closed project when fresh Zed instance is opened.

crates/editor/src/editor_settings.rs 🔗

@@ -11,6 +11,7 @@ pub struct EditorSettings {
     pub current_line_highlight: CurrentLineHighlight,
     pub lsp_highlight_debounce: u64,
     pub hover_popover_enabled: bool,
+    pub hover_popover_delay: u64,
     pub toolbar: Toolbar,
     pub scrollbar: Scrollbar,
     pub gutter: Gutter,
@@ -196,7 +197,10 @@ pub struct EditorSettingsContent {
     ///
     /// Default: true
     pub hover_popover_enabled: Option<bool>,
-
+    /// Time to wait before showing the informational hover box
+    ///
+    /// Default: 350
+    pub hover_popover_delay: Option<u64>,
     /// Toolbar related settings
     pub toolbar: Option<ToolbarContent>,
     /// Scrollbar related settings

crates/editor/src/hover_popover.rs 🔗

@@ -23,7 +23,6 @@ use std::{ops::Range, sync::Arc, time::Duration};
 use theme::ThemeSettings;
 use ui::{prelude::*, window_is_transparent, Scrollbar, ScrollbarState};
 use util::TryFutureExt;
-pub const HOVER_DELAY_MILLIS: u64 = 350;
 pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
 
 pub const MIN_POPOVER_CHARACTER_WIDTH: f32 = 20.;
@@ -131,10 +130,12 @@ pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut Vie
             hide_hover(editor, cx);
         }
 
+        let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
+
         let task = cx.spawn(|this, mut cx| {
             async move {
                 cx.background_executor()
-                    .timer(Duration::from_millis(HOVER_DELAY_MILLIS))
+                    .timer(Duration::from_millis(hover_popover_delay))
                     .await;
                 this.update(&mut cx, |this, _| {
                     this.hover_state.diagnostic_popover = None;
@@ -236,6 +237,8 @@ fn show_hover(
         }
     }
 
+    let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
+
     let task = cx.spawn(|this, mut cx| {
         async move {
             // If we need to delay, delay a set amount initially before making the lsp request
@@ -245,7 +248,7 @@ fn show_hover(
                 // Construct delay task to wait for later
                 let total_delay = Some(
                     cx.background_executor()
-                        .timer(Duration::from_millis(HOVER_DELAY_MILLIS)),
+                        .timer(Duration::from_millis(hover_popover_delay)),
                 );
 
                 cx.background_executor()
@@ -856,6 +859,7 @@ mod tests {
         InlayId, PointForPosition,
     };
     use collections::BTreeSet;
+    use gpui::AppContext;
     use indoc::indoc;
     use language::{language_settings::InlayHintSettings, Diagnostic, DiagnosticSet};
     use lsp::LanguageServerId;
@@ -865,6 +869,10 @@ mod tests {
     use std::sync::atomic::AtomicUsize;
     use text::Bias;
 
+    fn get_hover_popover_delay(cx: &gpui::TestAppContext) -> u64 {
+        cx.read(|cx: &AppContext| -> u64 { EditorSettings::get_global(cx).hover_popover_delay })
+    }
+
     impl InfoPopover {
         fn get_rendered_text(&self, cx: &gpui::AppContext) -> String {
             let mut rendered_text = String::new();
@@ -889,7 +897,6 @@ mod tests {
         cx: &mut gpui::TestAppContext,
     ) {
         init_test(cx, |_| {});
-        const HOVER_DELAY_MILLIS: u64 = 350;
 
         let mut cx = EditorLspTestContext::new_rust(
             lsp::ServerCapabilities {
@@ -963,7 +970,7 @@ mod tests {
                 }))
             });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         requests.next().await;
 
         cx.editor(|editor, cx| {
@@ -1042,7 +1049,7 @@ mod tests {
             hover_at(editor, Some(anchor), cx)
         });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         request.next().await;
 
         // verify that the information popover is no longer visible
@@ -1096,7 +1103,7 @@ mod tests {
                 }))
             });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         requests.next().await;
 
         cx.editor(|editor, cx| {
@@ -1132,7 +1139,7 @@ mod tests {
             hover_at(editor, Some(anchor), cx)
         });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         request.next().await;
         cx.editor(|editor, _| {
             assert!(!editor.hover_state.visible());
@@ -1394,7 +1401,7 @@ mod tests {
             }))
         });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
 
         cx.background_executor.run_until_parked();
         cx.editor(|Editor { hover_state, .. }, _| {
@@ -1682,7 +1689,7 @@ mod tests {
             );
         });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         cx.background_executor.run_until_parked();
         cx.update_editor(|editor, cx| {
             let hover_state = &editor.hover_state;
@@ -1736,7 +1743,7 @@ mod tests {
             );
         });
         cx.background_executor
-            .advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
+            .advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
         cx.background_executor.run_until_parked();
         cx.update_editor(|editor, cx| {
             let hover_state = &editor.hover_state;