gpui_component/input/lsp/
hover.rs1use anyhow::Result;
2use gpui::{App, Context, Task, Window};
3use ropey::Rope;
4
5use crate::input::{popovers::HoverPopover, InputState, RopeExt};
6
7pub trait HoverProvider {
11 fn hover(
15 &self,
16 _text: &Rope,
17 _offset: usize,
18 _window: &mut Window,
19 _cx: &mut App,
20 ) -> Task<Result<Option<lsp_types::Hover>>>;
21}
22
23impl InputState {
24 pub(super) fn handle_hover_popover(
26 &mut self,
27 offset: usize,
28 window: &mut Window,
29 cx: &mut Context<InputState>,
30 ) {
31 if self.selecting {
32 return;
33 }
34
35 let Some(provider) = self.lsp.hover_provider.clone() else {
36 return;
37 };
38
39 if let Some(hover_popover) = self.hover_popover.as_ref() {
40 if hover_popover.read(cx).is_same(offset) {
41 return;
42 }
43 }
44
45 let task = provider.hover(&self.text, offset, window, cx);
47 let mut symbol_range = self.text.word_range(offset).unwrap_or(offset..offset);
48 let editor = cx.entity();
49 self.lsp._hover_task = cx.spawn_in(window, async move |_, cx| {
50 let result = task.await?;
51
52 _ = editor.update(cx, |editor, cx| match result {
53 Some(hover) => {
54 if let Some(range) = hover.range {
55 let start = editor.text.position_to_offset(&range.start);
56 let end = editor.text.position_to_offset(&range.end);
57 symbol_range = start..end;
58 }
59 let hover_popover = HoverPopover::new(cx.entity(), symbol_range, &hover, cx);
60 editor.hover_popover = Some(hover_popover);
61 }
62 None => {
63 editor.hover_popover = None;
64 }
65 });
66
67 Ok(())
68 });
69 }
70}