WIP

Keith Simmons created

Change summary

crates/editor/src/editor.rs  | 81 +++++++++++++++++++++++++++++++++++++
crates/editor/src/element.rs |  3 
2 files changed, 81 insertions(+), 3 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -191,6 +191,7 @@ actions!(
         UnfoldLines,
         FoldSelectedRanges,
         ShowCompletions,
+        ShowHover,
         OpenExcerpts,
         RestartLanguageServer,
     ]
@@ -413,6 +414,7 @@ pub struct Editor {
     next_completion_id: CompletionId,
     available_code_actions: Option<(ModelHandle<Buffer>, Arc<[CodeAction]>)>,
     code_actions_task: Option<Task<()>>,
+    hover_task: Option<Task<()>>,
     document_highlights_task: Option<Task<()>>,
     pending_rename: Option<RenameState>,
     searchable: bool,
@@ -559,6 +561,7 @@ struct InvalidationStack<T>(Vec<T>);
 enum ContextMenu {
     Completions(CompletionsMenu),
     CodeActions(CodeActionsMenu),
+    Hover(HoverPopover),
 }
 
 impl ContextMenu {
@@ -567,6 +570,7 @@ impl ContextMenu {
             match self {
                 ContextMenu::Completions(menu) => menu.select_prev(cx),
                 ContextMenu::CodeActions(menu) => menu.select_prev(cx),
+                _ => {}
             }
             true
         } else {
@@ -579,6 +583,7 @@ impl ContextMenu {
             match self {
                 ContextMenu::Completions(menu) => menu.select_next(cx),
                 ContextMenu::CodeActions(menu) => menu.select_next(cx),
+                _ => {}
             }
             true
         } else {
@@ -590,6 +595,7 @@ impl ContextMenu {
         match self {
             ContextMenu::Completions(menu) => menu.visible(),
             ContextMenu::CodeActions(menu) => menu.visible(),
+            ContextMenu::Hover(_) => true,
         }
     }
 
@@ -602,6 +608,7 @@ impl ContextMenu {
         match self {
             ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
             ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
+            ContextMenu::Hover(popover) => (cursor_position, popover.render(style)),
         }
     }
 }
@@ -846,6 +853,22 @@ impl CodeActionsMenu {
     }
 }
 
+#[derive(Clone)]
+struct HoverPopover {
+    pub text: String,
+    pub runs: Vec<(Range<usize>, HighlightStyle)>,
+}
+
+impl HoverPopover {
+    fn render(&self, style: EditorStyle) -> ElementBox {
+        Text::new(self.text.clone(), style.text.clone())
+            .with_soft_wrap(false)
+            .with_highlights(self.runs.clone())
+            .contained()
+            .boxed()
+    }
+}
+
 #[derive(Debug)]
 struct ActiveDiagnosticGroup {
     primary_range: Range<Anchor>,
@@ -2385,6 +2408,59 @@ impl Editor {
         }))
     }
 
+    fn show_hover(&mut self, _: &ShowHover, cx: &mut ViewContext<Self>) {
+        if self.pending_rename.is_some() {
+            return;
+        }
+
+        let project = if let Some(project) = self.project.clone() {
+            project
+        } else {
+            return;
+        };
+
+        let position = self.selections.newest_anchor().head();
+        let (buffer, buffer_position) = if let Some(output) = self
+            .buffer
+            .read(cx)
+            .text_anchor_for_position(position.clone(), cx)
+        {
+            output
+        } else {
+            return;
+        };
+
+        let hover = HoverPopover {
+            text: "Test hover information".to_string(),
+            runs: Vec::new(),
+        };
+
+        let id = post_inc(&mut self.next_completion_id);
+        let task = cx.spawn_weak(|this, mut cx| {
+            async move {
+                if let Some(this) = this.upgrade(&cx) {
+                    this.update(&mut cx, |this, cx| {
+                        if !matches!(
+                            this.context_menu.as_ref(),
+                            None | Some(ContextMenu::Hover(_))
+                        ) {
+                            return;
+                        }
+
+                        if this.focused {
+                            this.show_context_menu(ContextMenu::Hover(hover), cx);
+                        }
+
+                        cx.notify();
+                    });
+                }
+                Ok::<_, anyhow::Error>(())
+            }
+            .log_err()
+        });
+        self.completion_tasks.push((id, task));
+    }
+
     async fn open_project_transaction(
         this: ViewHandle<Editor>,
         workspace: ViewHandle<Workspace>,
@@ -2628,7 +2704,7 @@ impl Editor {
     ) -> Option<(DisplayPoint, ElementBox)> {
         self.context_menu
             .as_ref()
-            .map(|menu| menu.render(cursor_position, style, cx))
+            .map(|menu| menu.render(cursor_position, style))
     }
 
     fn show_context_menu(&mut self, menu: ContextMenu, cx: &mut ViewContext<Self>) {
@@ -5665,6 +5741,9 @@ impl View for Editor {
             Some(ContextMenu::CodeActions(_)) => {
                 context.set.insert("showing_code_actions".into());
             }
+            Some(ContextMenu::Hover(_)) => {
+                context.set.insert("showing_hover".into());
+            }
             None => {}
         }
 

crates/editor/src/element.rs 🔗

@@ -1091,8 +1091,7 @@ impl Element for EditorElement {
             if (start_row..end_row).contains(&newest_selection_head.row()) {
                 let style = view.style(cx);
                 if view.context_menu_visible() {
-                    context_menu =
-                        view.render_context_menu(newest_selection_head, style.clone(), cx);
+                    context_menu = view.render_context_menu(newest_selection_head, style.clone());
                 }
 
                 code_actions_indicator = view