gpui_component/input/lsp/
mod.rs1use anyhow::Result;
2use gpui::{App, Context, Hsla, MouseMoveEvent, Task, Window};
3use ropey::Rope;
4use std::rc::Rc;
5
6use crate::input::{popovers::ContextMenu, InputState, RopeExt};
7
8mod code_actions;
9mod completions;
10mod definitions;
11mod document_colors;
12mod hover;
13
14pub use code_actions::*;
15pub use completions::*;
16pub use definitions::*;
17pub use document_colors::*;
18pub use hover::*;
19
20pub struct Lsp {
24 pub completion_provider: Option<Rc<dyn CompletionProvider>>,
26 pub code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
28 pub hover_provider: Option<Rc<dyn HoverProvider>>,
30 pub definition_provider: Option<Rc<dyn DefinitionProvider>>,
32 pub document_color_provider: Option<Rc<dyn DocumentColorProvider>>,
34
35 document_colors: Vec<(lsp_types::Range, Hsla)>,
36 _hover_task: Task<Result<()>>,
37 _document_color_task: Task<Result<()>>,
38}
39
40impl Default for Lsp {
41 fn default() -> Self {
42 Self {
43 completion_provider: None,
44 code_action_providers: vec![],
45 hover_provider: None,
46 definition_provider: None,
47 document_color_provider: None,
48 document_colors: vec![],
49 _hover_task: Task::ready(Ok(())),
50 _document_color_task: Task::ready(Ok(())),
51 }
52 }
53}
54
55impl Lsp {
56 pub(crate) fn update(
58 &mut self,
59 text: &Rope,
60 window: &mut Window,
61 cx: &mut Context<InputState>,
62 ) {
63 self.update_document_colors(text, window, cx);
64 }
65
66 pub(crate) fn reset(&mut self) {
68 self.document_colors.clear();
69 self._hover_task = Task::ready(Ok(()));
70 self._document_color_task = Task::ready(Ok(()));
71 }
72}
73
74impl InputState {
75 pub(crate) fn hide_context_menu(&mut self, cx: &mut Context<Self>) {
76 self.context_menu = None;
77 self._context_menu_task = Task::ready(Ok(()));
78 cx.notify();
79 }
80
81 pub(crate) fn is_context_menu_open(&self, cx: &App) -> bool {
82 let Some(menu) = self.context_menu.as_ref() else {
83 return false;
84 };
85
86 menu.is_open(cx)
87 }
88
89 pub fn handle_action_for_context_menu(
93 &mut self,
94 action: Box<dyn gpui::Action>,
95 window: &mut Window,
96 cx: &mut Context<Self>,
97 ) -> bool {
98 let Some(menu) = self.context_menu.as_ref() else {
99 return false;
100 };
101
102 let mut handled = false;
103
104 match menu {
105 ContextMenu::Completion(menu) => {
106 _ = menu.update(cx, |menu, cx| {
107 handled = menu.handle_action(action, window, cx)
108 });
109 }
110 ContextMenu::CodeAction(menu) => {
111 _ = menu.update(cx, |menu, cx| {
112 handled = menu.handle_action(action, window, cx)
113 });
114 }
115 ContextMenu::MouseContext(..) => {}
116 };
117
118 handled
119 }
120
121 pub fn apply_lsp_edits(
123 &mut self,
124 text_edits: &Vec<lsp_types::TextEdit>,
125 window: &mut Window,
126 cx: &mut Context<Self>,
127 ) {
128 for edit in text_edits {
129 let start = self.text.position_to_offset(&edit.range.start);
130 let end = self.text.position_to_offset(&edit.range.end);
131
132 let range_utf16 = self.range_to_utf16(&(start..end));
133 self.replace_text_in_range_silent(Some(range_utf16), &edit.new_text, window, cx);
134 }
135 }
136
137 pub(super) fn handle_mouse_move(
138 &mut self,
139 offset: usize,
140 event: &MouseMoveEvent,
141 window: &mut Window,
142 cx: &mut Context<InputState>,
143 ) {
144 if event.modifiers.secondary() {
145 self.handle_hover_definition(offset, window, cx);
146 } else {
147 self.hover_definition.clear();
148 self.handle_hover_popover(offset, window, cx);
149 }
150 cx.notify();
151 }
152}