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 }
42
43 fn editing_syntax_context(state: &InputBaseState<Self>, offset: usize) -> super::SyntaxContext {
44 state.syntax_context_at(offset)
45 }
46
47 fn adjust_annotations(
48 state: &mut InputBaseState<Self>,
49 range: &std::ops::Range<usize>,
50 new_len: usize,
51 ) {
52 state.extras.decorations.adjust_for_edit(range, new_len);
53 }
54
55 fn refresh_language_features(
56 state: &mut InputBaseState<Self>,
57 window: &mut Window,
58 cx: &mut gpui::Context<InputBaseState<Self>>,
59 ) {
60 let text = state.text().clone();
61 state.extras.lsp.update(&text, window, cx);
62 }
63
64 fn accept_inline_completion(
65 state: &mut InputBaseState<Self>,
66 window: &mut Window,
67 cx: &mut gpui::Context<InputBaseState<Self>>,
68 ) -> bool {
69 state.accept_inline_completion(window, cx)
70 }
71
72 fn has_inline_completion(state: &InputBaseState<Self>) -> bool {
73 state.has_inline_completion()
74 }
75
76 fn on_click(
77 state: &mut InputBaseState<Self>,
78 event: &gpui::MouseDownEvent,
79 offset: usize,
80 window: &mut Window,
81 cx: &mut gpui::Context<InputBaseState<Self>>,
82 ) -> bool {
83 state.handle_click_hover_definition(event, offset, window, cx)
84 }
85
86 fn clear_hover_state(
87 state: &mut InputBaseState<Self>,
88 cx: &mut gpui::Context<InputBaseState<Self>>,
89 ) {
90 state.clear_hover_state(cx);
91 }
92
93 fn on_text_typed(
94 state: &mut InputBaseState<Self>,
95 range: &std::ops::Range<usize>,
96 text: &str,
97 window: &mut Window,
98 cx: &mut gpui::Context<InputBaseState<Self>>,
99 ) {
100 state.handle_completion_trigger(range, text, window, cx);
101 }
102
103 fn clear_inline_completion(
104 state: &mut InputBaseState<Self>,
105 cx: &mut gpui::Context<InputBaseState<Self>>,
106 ) {
107 state.clear_inline_completion(cx);
108 }
109
110 fn hide_context_menu(
111 state: &mut InputBaseState<Self>,
112 cx: &mut gpui::Context<InputBaseState<Self>>,
113 ) {
114 state.hide_context_menu(cx);
115 }
116
117 fn is_context_menu_open(state: &InputBaseState<Self>, cx: &App) -> bool {
118 state.is_context_menu_open(cx)
119 }
120
121 fn handle_context_menu_action(
122 state: &mut InputBaseState<Self>,
123 action: Box<dyn gpui::Action>,
124 window: &mut Window,
125 cx: &mut gpui::Context<InputBaseState<Self>>,
126 ) -> bool {
127 state.handle_action_for_context_menu(action, window, cx)
128 }
129
130 fn on_hover_definition(
131 state: &mut InputBaseState<Self>,
132 offset: usize,
133 window: &mut Window,
134 cx: &mut gpui::Context<InputBaseState<Self>>,
135 ) {
136 state.handle_hover_definition(offset, window, cx);
137 }
138
139 fn on_mouse_move(
140 state: &mut InputBaseState<Self>,
141 offset: usize,
142 event: &gpui::MouseMoveEvent,
143 window: &mut Window,
144 cx: &mut gpui::Context<InputBaseState<Self>>,
145 ) {
146 state.handle_mouse_move(offset, event, window, cx);
147 }
148
149 fn drive_highlighter(
150 highlighter: &std::rc::Rc<std::cell::RefCell<Option<Box<dyn super::InputHighlighter>>>>,
151 edit: super::InputEdit,
152 text: &ropey::Rope,
153 folding: bool,
154 window: &mut Window,
155 cx: &mut gpui::Context<InputBaseState<Self>>,
156 ) {
157 let mut highlighter = highlighter.borrow_mut();
158 let Some(highlighter) = highlighter.as_mut() else {
159 return;
160 };
161 highlighter.update(Some(edit), text, folding, window, cx);
162 }
163
164 fn register_actions(
165 element: Stateful<Div>,
166 entity: &Entity<InputBaseState<Self>>,
167 window: &mut Window,
168 ) -> Stateful<Div> {
169 element
170 .on_action(window.listener_for(entity, InputBaseState::on_action_toggle_code_actions))
171 .on_action(window.listener_for(entity, InputBaseState::on_action_go_to_definition))
172 }
173}
174
175impl EditorState {
176 pub fn lsp(&self) -> &super::Lsp {
181 &self.extras.lsp
182 }
183
184 pub fn lsp_mut(&mut self) -> &mut super::Lsp {
186 &mut self.extras.lsp
187 }
188
189 pub(crate) fn syntax_context_at(&self, offset: usize) -> super::SyntaxContext {
191 self.mode.syntax_context_at(&self.text, offset)
192 }
193}
194
195#[derive(IntoElement)]
197pub struct Editor {
198 state: Entity<EditorState>,
199}
200
201impl Editor {
202 pub fn new(state: &Entity<EditorState>) -> Self {
203 Self {
204 state: state.clone(),
205 }
206 }
207}
208
209impl RenderOnce for Editor {
210 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
211 self.state
212 }
213}
214
215impl crate::input::InputExtras for super::EditorExtras {
217 fn decoration_layers(&self) -> Vec<&[super::TextDecoration]> {
218 self.decorations.iter().collect()
219 }
220
221 fn semantic_token_styles(
222 &self,
223 text: &ropey::Rope,
224 range: &std::ops::Range<usize>,
225 resolver: &dyn crate::input::HighlightStyleResolver,
226 ) -> Vec<(std::ops::Range<usize>, gpui::HighlightStyle)> {
227 self.lsp.semantic_tokens_for_range(text, range, resolver)
228 }
229
230 fn document_color_swatches(
231 &self,
232 text: &ropey::Rope,
233 range: &std::ops::Range<usize>,
234 ) -> Vec<(std::ops::Range<usize>, gpui::Hsla)> {
235 self.lsp.document_colors_for_range(text, range)
236 }
237
238 fn hover_symbol_range(&self) -> Option<std::ops::Range<usize>> {
239 self.hover_popover
240 .as_ref()
241 .map(|session| session.symbol_range.clone())
242 }
243
244 fn inline_completion_item(&self) -> Option<&lsp_types::InlineCompletionItem> {
245 self.inline_completion.item.as_ref()
246 }
247
248 fn context_menu_capabilities(&self) -> (bool, bool) {
249 (
250 self.lsp.definition_provider.is_some(),
251 !self.lsp.code_action_providers.is_empty(),
252 )
253 }
254}