1use gpui::{App, Div, Entity, InteractiveElement as _, IntoElement, RenderOnce, Stateful, Window};
2
3use super::{EditorMode, InputBaseState, InputModeKind};
4
5pub type EditorState = InputBaseState<EditorMode>;
12
13impl InputModeKind for EditorMode {
14 const MULTI_LINE: bool = true;
15 const CODE_EDITOR: bool = true;
16
17 type Extras = super::EditorExtras;
18
19 fn hover_definition_style(
20 state: &InputBaseState<Self>,
21 _cx: &App,
22 ) -> Option<(std::ops::Range<usize>, gpui::HighlightStyle)> {
23 state.hover_definition_style()
24 }
25
26 fn hover_definition_hitbox(
27 state: &InputBaseState<Self>,
28 window: &mut Window,
29 _cx: &App,
30 ) -> Option<gpui::Hitbox> {
31 state.hover_definition_hitbox(window)
32 }
33
34 fn reset_language_features(state: &mut InputBaseState<Self>) {
35 state.extras.lsp.reset();
36 }
37
38 fn reset_annotations(state: &mut InputBaseState<Self>) {
39 state.extras.hover_popover = None;
40 state.extras.decorations.clear();
41 state.extras.range_decorations.clear();
42 state.extras.gutter_decorations.clear();
43 state.extras.overview_ruler_decorations.clear();
44 }
45
46 fn editing_syntax_context(state: &InputBaseState<Self>, offset: usize) -> super::SyntaxContext {
47 state.syntax_context_at(offset)
48 }
49
50 fn adjust_annotations(
51 state: &mut InputBaseState<Self>,
52 range: &std::ops::Range<usize>,
53 new_len: usize,
54 ) {
55 state.extras.decorations.adjust_for_edit(range, new_len);
56 state
57 .extras
58 .range_decorations
59 .adjust_for_edit(range, new_len);
60 state
61 .extras
62 .gutter_decorations
63 .adjust_for_edit(range, new_len);
64 state
65 .extras
66 .overview_ruler_decorations
67 .adjust_for_edit(range, new_len);
68 }
69
70 fn refresh_language_features(
71 state: &mut InputBaseState<Self>,
72 window: &mut Window,
73 cx: &mut gpui::Context<InputBaseState<Self>>,
74 ) {
75 let text = state.text().clone();
76 state.extras.lsp.update(&text, window, cx);
77 }
78
79 fn accept_inline_completion(
80 state: &mut InputBaseState<Self>,
81 window: &mut Window,
82 cx: &mut gpui::Context<InputBaseState<Self>>,
83 ) -> bool {
84 state.accept_inline_completion(window, cx)
85 }
86
87 fn has_inline_completion(state: &InputBaseState<Self>) -> bool {
88 state.has_inline_completion()
89 }
90
91 fn on_click(
92 state: &mut InputBaseState<Self>,
93 event: &gpui::MouseDownEvent,
94 offset: usize,
95 window: &mut Window,
96 cx: &mut gpui::Context<InputBaseState<Self>>,
97 ) -> bool {
98 state.handle_click_hover_definition(event, offset, window, cx)
99 }
100
101 fn clear_hover_state(
102 state: &mut InputBaseState<Self>,
103 cx: &mut gpui::Context<InputBaseState<Self>>,
104 ) {
105 state.clear_hover_state(cx);
106 }
107
108 fn on_text_typed(
109 state: &mut InputBaseState<Self>,
110 range: &std::ops::Range<usize>,
111 text: &str,
112 window: &mut Window,
113 cx: &mut gpui::Context<InputBaseState<Self>>,
114 ) {
115 state.handle_completion_trigger(range, text, window, cx);
116 }
117
118 fn clear_inline_completion(
119 state: &mut InputBaseState<Self>,
120 cx: &mut gpui::Context<InputBaseState<Self>>,
121 ) {
122 state.clear_inline_completion(cx);
123 }
124
125 fn hide_context_menu(
126 state: &mut InputBaseState<Self>,
127 cx: &mut gpui::Context<InputBaseState<Self>>,
128 ) {
129 state.hide_context_menu(cx);
130 }
131
132 fn is_context_menu_open(state: &InputBaseState<Self>, cx: &App) -> bool {
133 state.is_context_menu_open(cx)
134 }
135
136 fn handle_context_menu_action(
137 state: &mut InputBaseState<Self>,
138 action: Box<dyn gpui::Action>,
139 window: &mut Window,
140 cx: &mut gpui::Context<InputBaseState<Self>>,
141 ) -> bool {
142 state.handle_action_for_context_menu(action, window, cx)
143 }
144
145 fn on_hover_definition(
146 state: &mut InputBaseState<Self>,
147 offset: usize,
148 window: &mut Window,
149 cx: &mut gpui::Context<InputBaseState<Self>>,
150 ) {
151 state.handle_hover_definition(offset, window, cx);
152 }
153
154 fn on_mouse_move(
155 state: &mut InputBaseState<Self>,
156 offset: usize,
157 event: &gpui::MouseMoveEvent,
158 window: &mut Window,
159 cx: &mut gpui::Context<InputBaseState<Self>>,
160 ) {
161 state.handle_mouse_move(offset, event, window, cx);
162 }
163
164 fn drive_highlighter(
165 highlighter: &std::rc::Rc<std::cell::RefCell<Option<Box<dyn super::InputHighlighter>>>>,
166 edit: super::InputEdit,
167 text: &ropey::Rope,
168 folding: bool,
169 window: &mut Window,
170 cx: &mut gpui::Context<InputBaseState<Self>>,
171 ) {
172 let mut highlighter = highlighter.borrow_mut();
173 let Some(highlighter) = highlighter.as_mut() else {
174 return;
175 };
176 highlighter.update(Some(edit), text, folding, window, cx);
177 }
178
179 fn drive_highlighter_batch(
180 highlighter: &std::rc::Rc<std::cell::RefCell<Option<Box<dyn super::InputHighlighter>>>>,
181 edits: &[(super::InputEdit, ropey::Rope)],
182 folding: bool,
183 window: &mut Window,
184 cx: &mut gpui::Context<InputBaseState<Self>>,
185 ) {
186 let mut highlighter = highlighter.borrow_mut();
187 let Some(highlighter) = highlighter.as_mut() else {
188 return;
189 };
190 highlighter.update_batch(edits, folding, window, cx);
191 }
192
193 fn register_actions(
194 element: Stateful<Div>,
195 entity: &Entity<InputBaseState<Self>>,
196 window: &mut Window,
197 ) -> Stateful<Div> {
198 element
199 .key_context("Input mode=editor")
200 .on_action(window.listener_for(entity, InputBaseState::on_action_toggle_code_actions))
201 .on_action(window.listener_for(entity, InputBaseState::on_action_show_completions))
202 .on_action(window.listener_for(entity, InputBaseState::on_action_go_to_definition))
203 }
204}
205
206impl EditorState {
207 pub fn lsp(&self) -> &super::Lsp {
212 &self.extras.lsp
213 }
214
215 pub fn lsp_mut(&mut self) -> &mut super::Lsp {
217 &mut self.extras.lsp
218 }
219
220 pub(crate) fn syntax_context_at(&self, offset: usize) -> super::SyntaxContext {
222 self.mode.syntax_context_at(&self.text, offset)
223 }
224}
225
226#[derive(IntoElement)]
228pub struct Editor {
229 state: Entity<EditorState>,
230}
231
232impl Editor {
233 pub fn new(state: &Entity<EditorState>) -> Self {
234 Self {
235 state: state.clone(),
236 }
237 }
238}
239
240impl RenderOnce for Editor {
241 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
242 self.state
243 }
244}
245
246impl crate::input::InputExtras for super::EditorExtras {
248 fn decoration_layers(&self) -> Vec<&[super::TextDecoration]> {
249 self.decorations.iter().collect()
250 }
251
252 fn range_decorations(&self, ranges: &[std::ops::Range<usize>]) -> Vec<&super::RangeDecoration> {
253 self.range_decorations.intersecting(ranges)
254 }
255
256 fn gutter_decorations_width(&self) -> Option<gpui::Pixels> {
257 self.gutter_decorations
258 .has_collections()
259 .then_some(self.gutter_decorations_width)
260 }
261
262 fn gutter_decorations(&self, range: std::ops::Range<usize>) -> Vec<&super::GutterDecoration> {
263 self.gutter_decorations.intersecting(&[range])
264 }
265
266 fn overview_ruler_decorations(&self) -> Vec<&super::OverviewRulerDecoration> {
267 self.overview_ruler_decorations.iter().flatten().collect()
268 }
269
270 fn overview_ruler_revision(&self) -> u64 {
271 self.overview_ruler_decorations.revision()
272 }
273
274 fn semantic_token_styles(
275 &self,
276 text: &ropey::Rope,
277 range: &std::ops::Range<usize>,
278 resolver: &dyn crate::input::HighlightStyleResolver,
279 ) -> Vec<(std::ops::Range<usize>, gpui::HighlightStyle)> {
280 self.lsp.semantic_tokens_for_range(text, range, resolver)
281 }
282
283 fn document_color_swatches(
284 &self,
285 text: &ropey::Rope,
286 range: &std::ops::Range<usize>,
287 ) -> Vec<(std::ops::Range<usize>, gpui::Hsla)> {
288 self.lsp.document_colors_for_range(text, range)
289 }
290
291 fn hover_symbol_range(&self) -> Option<std::ops::Range<usize>> {
292 self.hover_popover
293 .as_ref()
294 .map(|session| session.symbol_range.clone())
295 }
296
297 fn inline_completion_item(&self) -> Option<&lsp_types::InlineCompletionItem> {
298 self.inline_completion.item.as_ref()
299 }
300
301 fn context_menu_capabilities(&self) -> (bool, bool) {
302 (
303 self.lsp.definition_provider.is_some(),
304 !self.lsp.code_action_providers.is_empty(),
305 )
306 }
307}