1use anyhow::Result;
6use gpui::{
7 actions, div, point, prelude::FluentBuilder as _, px, Action, App, AppContext, Bounds,
8 ClipboardItem, Context, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable,
9 InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent,
10 MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, ScrollHandle,
11 ScrollWheelEvent, SharedString, Styled as _, Subscription, Task, UTF16Selection, Window,
12};
13use ropey::{Rope, RopeSlice};
14use serde::Deserialize;
15use std::cell::RefCell;
16use std::ops::Range;
17use std::rc::Rc;
18use sum_tree::Bias;
19use unicode_segmentation::*;
20
21use super::{
22 blink_cursor::BlinkCursor,
23 change::Change,
24 element::TextElement,
25 mask_pattern::MaskPattern,
26 mode::{InputMode, TabSize},
27 number_input,
28 text_wrapper::TextWrapper,
29};
30use crate::input::{
31 element::RIGHT_MARGIN,
32 popovers::{ContextMenu, DiagnosticPopover, HoverPopover, MouseContextMenu},
33 search::{self, SearchPanel},
34 text_wrapper::LineLayout,
35 HoverDefinition, Lsp, Position,
36};
37use crate::input::{RopeExt as _, Selection};
38use crate::{highlighter::DiagnosticSet, input::text_wrapper::LineItem};
39use crate::{history::History, scroll::ScrollbarState, Root};
40
41#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
42#[action(namespace = input, no_json)]
43pub struct Enter {
44 pub secondary: bool,
46}
47
48actions!(
49 input,
50 [
51 Backspace,
52 Delete,
53 DeleteToBeginningOfLine,
54 DeleteToEndOfLine,
55 DeleteToPreviousWordStart,
56 DeleteToNextWordEnd,
57 Indent,
58 Outdent,
59 IndentInline,
60 OutdentInline,
61 MoveUp,
62 MoveDown,
63 MoveLeft,
64 MoveRight,
65 MoveHome,
66 MoveEnd,
67 MovePageUp,
68 MovePageDown,
69 SelectUp,
70 SelectDown,
71 SelectLeft,
72 SelectRight,
73 SelectAll,
74 SelectToStartOfLine,
75 SelectToEndOfLine,
76 SelectToStart,
77 SelectToEnd,
78 SelectToPreviousWordStart,
79 SelectToNextWordEnd,
80 ShowCharacterPalette,
81 Copy,
82 Cut,
83 Paste,
84 Undo,
85 Redo,
86 MoveToStartOfLine,
87 MoveToEndOfLine,
88 MoveToStart,
89 MoveToEnd,
90 MoveToPreviousWord,
91 MoveToNextWord,
92 Escape,
93 ToggleCodeActions,
94 Search,
95 GoToDefinition,
96 ]
97);
98
99#[derive(Clone)]
100pub enum InputEvent {
101 Change,
102 PressEnter { secondary: bool },
103 Focus,
104 Blur,
105}
106
107pub(super) const CONTEXT: &str = "Input";
108
109pub(crate) fn init(cx: &mut App) {
110 cx.bind_keys([
111 KeyBinding::new("backspace", Backspace, Some(CONTEXT)),
112 KeyBinding::new("delete", Delete, Some(CONTEXT)),
113 #[cfg(target_os = "macos")]
114 KeyBinding::new("cmd-backspace", DeleteToBeginningOfLine, Some(CONTEXT)),
115 #[cfg(target_os = "macos")]
116 KeyBinding::new("cmd-delete", DeleteToEndOfLine, Some(CONTEXT)),
117 #[cfg(target_os = "macos")]
118 KeyBinding::new("alt-backspace", DeleteToPreviousWordStart, Some(CONTEXT)),
119 #[cfg(not(target_os = "macos"))]
120 KeyBinding::new("ctrl-backspace", DeleteToPreviousWordStart, Some(CONTEXT)),
121 #[cfg(target_os = "macos")]
122 KeyBinding::new("alt-delete", DeleteToNextWordEnd, Some(CONTEXT)),
123 #[cfg(not(target_os = "macos"))]
124 KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)),
125 KeyBinding::new("enter", Enter { secondary: false }, Some(CONTEXT)),
126 KeyBinding::new("secondary-enter", Enter { secondary: true }, Some(CONTEXT)),
127 KeyBinding::new("escape", Escape, Some(CONTEXT)),
128 KeyBinding::new("up", MoveUp, Some(CONTEXT)),
129 KeyBinding::new("down", MoveDown, Some(CONTEXT)),
130 KeyBinding::new("left", MoveLeft, Some(CONTEXT)),
131 KeyBinding::new("right", MoveRight, Some(CONTEXT)),
132 KeyBinding::new("pageup", MovePageUp, Some(CONTEXT)),
133 KeyBinding::new("pagedown", MovePageDown, Some(CONTEXT)),
134 KeyBinding::new("tab", IndentInline, Some(CONTEXT)),
135 KeyBinding::new("shift-tab", OutdentInline, Some(CONTEXT)),
136 #[cfg(target_os = "macos")]
137 KeyBinding::new("cmd-]", Indent, Some(CONTEXT)),
138 #[cfg(not(target_os = "macos"))]
139 KeyBinding::new("ctrl-]", Indent, Some(CONTEXT)),
140 #[cfg(target_os = "macos")]
141 KeyBinding::new("cmd-[", Outdent, Some(CONTEXT)),
142 #[cfg(not(target_os = "macos"))]
143 KeyBinding::new("ctrl-[", Outdent, Some(CONTEXT)),
144 KeyBinding::new("shift-left", SelectLeft, Some(CONTEXT)),
145 KeyBinding::new("shift-right", SelectRight, Some(CONTEXT)),
146 KeyBinding::new("shift-up", SelectUp, Some(CONTEXT)),
147 KeyBinding::new("shift-down", SelectDown, Some(CONTEXT)),
148 KeyBinding::new("home", MoveHome, Some(CONTEXT)),
149 KeyBinding::new("end", MoveEnd, Some(CONTEXT)),
150 KeyBinding::new("shift-home", SelectToStartOfLine, Some(CONTEXT)),
151 KeyBinding::new("shift-end", SelectToEndOfLine, Some(CONTEXT)),
152 #[cfg(target_os = "macos")]
153 KeyBinding::new("ctrl-shift-a", SelectToStartOfLine, Some(CONTEXT)),
154 #[cfg(target_os = "macos")]
155 KeyBinding::new("ctrl-shift-e", SelectToEndOfLine, Some(CONTEXT)),
156 #[cfg(target_os = "macos")]
157 KeyBinding::new("shift-cmd-left", SelectToStartOfLine, Some(CONTEXT)),
158 #[cfg(target_os = "macos")]
159 KeyBinding::new("shift-cmd-right", SelectToEndOfLine, Some(CONTEXT)),
160 #[cfg(target_os = "macos")]
161 KeyBinding::new("alt-shift-left", SelectToPreviousWordStart, Some(CONTEXT)),
162 #[cfg(not(target_os = "macos"))]
163 KeyBinding::new("ctrl-shift-left", SelectToPreviousWordStart, Some(CONTEXT)),
164 #[cfg(target_os = "macos")]
165 KeyBinding::new("alt-shift-right", SelectToNextWordEnd, Some(CONTEXT)),
166 #[cfg(not(target_os = "macos"))]
167 KeyBinding::new("ctrl-shift-right", SelectToNextWordEnd, Some(CONTEXT)),
168 #[cfg(target_os = "macos")]
169 KeyBinding::new("ctrl-cmd-space", ShowCharacterPalette, Some(CONTEXT)),
170 #[cfg(target_os = "macos")]
171 KeyBinding::new("cmd-a", SelectAll, Some(CONTEXT)),
172 #[cfg(not(target_os = "macos"))]
173 KeyBinding::new("ctrl-a", SelectAll, Some(CONTEXT)),
174 #[cfg(target_os = "macos")]
175 KeyBinding::new("cmd-c", Copy, Some(CONTEXT)),
176 #[cfg(not(target_os = "macos"))]
177 KeyBinding::new("ctrl-c", Copy, Some(CONTEXT)),
178 #[cfg(target_os = "macos")]
179 KeyBinding::new("cmd-x", Cut, Some(CONTEXT)),
180 #[cfg(not(target_os = "macos"))]
181 KeyBinding::new("ctrl-x", Cut, Some(CONTEXT)),
182 #[cfg(target_os = "macos")]
183 KeyBinding::new("cmd-v", Paste, Some(CONTEXT)),
184 #[cfg(not(target_os = "macos"))]
185 KeyBinding::new("ctrl-v", Paste, Some(CONTEXT)),
186 #[cfg(target_os = "macos")]
187 KeyBinding::new("ctrl-a", MoveHome, Some(CONTEXT)),
188 #[cfg(target_os = "macos")]
189 KeyBinding::new("cmd-left", MoveHome, Some(CONTEXT)),
190 #[cfg(target_os = "macos")]
191 KeyBinding::new("ctrl-e", MoveEnd, Some(CONTEXT)),
192 #[cfg(target_os = "macos")]
193 KeyBinding::new("cmd-right", MoveEnd, Some(CONTEXT)),
194 #[cfg(target_os = "macos")]
195 KeyBinding::new("cmd-z", Undo, Some(CONTEXT)),
196 #[cfg(target_os = "macos")]
197 KeyBinding::new("cmd-shift-z", Redo, Some(CONTEXT)),
198 #[cfg(target_os = "macos")]
199 KeyBinding::new("cmd-up", MoveToStart, Some(CONTEXT)),
200 #[cfg(target_os = "macos")]
201 KeyBinding::new("cmd-down", MoveToEnd, Some(CONTEXT)),
202 #[cfg(target_os = "macos")]
203 KeyBinding::new("alt-left", MoveToPreviousWord, Some(CONTEXT)),
204 #[cfg(target_os = "macos")]
205 KeyBinding::new("alt-right", MoveToNextWord, Some(CONTEXT)),
206 #[cfg(not(target_os = "macos"))]
207 KeyBinding::new("ctrl-left", MoveToPreviousWord, Some(CONTEXT)),
208 #[cfg(not(target_os = "macos"))]
209 KeyBinding::new("ctrl-right", MoveToNextWord, Some(CONTEXT)),
210 #[cfg(target_os = "macos")]
211 KeyBinding::new("cmd-shift-up", SelectToStart, Some(CONTEXT)),
212 #[cfg(target_os = "macos")]
213 KeyBinding::new("cmd-shift-down", SelectToEnd, Some(CONTEXT)),
214 #[cfg(not(target_os = "macos"))]
215 KeyBinding::new("ctrl-z", Undo, Some(CONTEXT)),
216 #[cfg(not(target_os = "macos"))]
217 KeyBinding::new("ctrl-y", Redo, Some(CONTEXT)),
218 #[cfg(target_os = "macos")]
219 KeyBinding::new("cmd-.", ToggleCodeActions, Some(CONTEXT)),
220 #[cfg(not(target_os = "macos"))]
221 KeyBinding::new("ctrl-.", ToggleCodeActions, Some(CONTEXT)),
222 #[cfg(target_os = "macos")]
223 KeyBinding::new("cmd-f", Search, Some(CONTEXT)),
224 #[cfg(not(target_os = "macos"))]
225 KeyBinding::new("ctrl-f", Search, Some(CONTEXT)),
226 ]);
227
228 search::init(cx);
229 number_input::init(cx);
230}
231
232#[derive(Clone)]
233pub(super) struct LastLayout {
234 pub(super) visible_range: Range<usize>,
236 pub(super) visible_top: Pixels,
238 pub(super) visible_range_offset: Range<usize>,
240 pub(super) lines: Rc<Vec<LineLayout>>,
242 pub(super) line_height: Pixels,
244 pub(super) wrap_width: Option<Pixels>,
246 pub(super) line_number_width: Pixels,
248 pub(super) cursor_bounds: Option<Bounds<Pixels>>,
250}
251
252impl LastLayout {
253 pub(crate) fn line(&self, row: usize) -> Option<&LineLayout> {
259 if row < self.visible_range.start || row >= self.visible_range.end {
260 return None;
261 }
262
263 self.lines.get(row.saturating_sub(self.visible_range.start))
264 }
265}
266
267pub struct InputState {
269 pub(super) focus_handle: FocusHandle,
270 pub(super) mode: InputMode,
271 pub(super) text: Rope,
272 pub(super) text_wrapper: TextWrapper,
273 pub(super) history: History<Change>,
274 pub(super) blink_cursor: Entity<BlinkCursor>,
275 pub(super) loading: bool,
276 pub(super) selected_range: Selection,
281 pub(super) search_panel: Option<Entity<SearchPanel>>,
282 pub(super) searchable: bool,
283 pub(super) selected_word_range: Option<Selection>,
285 pub(super) selection_reversed: bool,
286 pub(super) ime_marked_range: Option<Selection>,
288 pub(super) last_layout: Option<LastLayout>,
289 pub(super) last_cursor: Option<usize>,
290 pub(super) input_bounds: Bounds<Pixels>,
292 pub(super) last_bounds: Option<Bounds<Pixels>>,
294 pub(super) last_selected_range: Option<Selection>,
295 pub(super) selecting: bool,
296 pub(super) disabled: bool,
297 pub(super) masked: bool,
298 pub(super) clean_on_escape: bool,
299 pub(super) soft_wrap: bool,
300 pub(super) pattern: Option<regex::Regex>,
301 pub(super) validate: Option<Box<dyn Fn(&str, &mut Context<Self>) -> bool + 'static>>,
302 pub(crate) scroll_handle: ScrollHandle,
303 pub(crate) deferred_scroll_offset: Option<Point<Pixels>>,
305 pub(super) scroll_state: ScrollbarState,
306 pub(crate) scroll_size: gpui::Size<Pixels>,
308
309 pub(crate) mask_pattern: MaskPattern,
311 pub(super) placeholder: SharedString,
312
313 diagnostic_popover: Option<Entity<DiagnosticPopover>>,
315 pub(super) context_menu: Option<ContextMenu>,
317 pub(super) mouse_context_menu: Entity<MouseContextMenu>,
318 pub(super) completion_inserting: bool,
320 pub(super) hover_popover: Option<Entity<HoverPopover>>,
321 pub(super) hover_definition: HoverDefinition,
323
324 pub lsp: Lsp,
325
326 _pending_update: bool,
330 pub(super) silent_replace_text: bool,
332
333 pub(super) preferred_column: Option<(Pixels, usize)>,
338 _subscriptions: Vec<Subscription>,
339
340 pub(super) _context_menu_task: Task<Result<()>>,
341}
342
343impl EventEmitter<InputEvent> for InputState {}
344
345impl InputState {
346 pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
350 let focus_handle = cx.focus_handle().tab_stop(true);
351 let blink_cursor = cx.new(|_| BlinkCursor::new());
352 let history = History::new().group_interval(std::time::Duration::from_secs(1));
353
354 let _subscriptions = vec![
355 cx.observe(&blink_cursor, |_, _, cx| cx.notify()),
357 cx.observe_window_activation(window, |input, window, cx| {
359 if window.is_window_active() {
360 let focus_handle = input.focus_handle.clone();
361 if focus_handle.is_focused(window) {
362 input.blink_cursor.update(cx, |blink_cursor, cx| {
363 blink_cursor.start(cx);
364 });
365 }
366 }
367 }),
368 cx.on_focus(&focus_handle, window, Self::on_focus),
369 cx.on_blur(&focus_handle, window, Self::on_blur),
370 ];
371
372 let text_style = window.text_style();
373 let mouse_context_menu = MouseContextMenu::new(cx.entity(), window, cx);
374
375 Self {
376 focus_handle: focus_handle.clone(),
377 text: "".into(),
378 text_wrapper: TextWrapper::new(
379 text_style.font(),
380 text_style.font_size.to_pixels(window.rem_size()),
381 None,
382 ),
383 blink_cursor,
384 history,
385 selected_range: Selection::default(),
386 search_panel: None,
387 searchable: false,
388 selected_word_range: None,
389 selection_reversed: false,
390 ime_marked_range: None,
391 input_bounds: Bounds::default(),
392 selecting: false,
393 disabled: false,
394 masked: false,
395 clean_on_escape: false,
396 soft_wrap: true,
397 loading: false,
398 pattern: None,
399 validate: None,
400 mode: InputMode::SingleLine,
401 last_layout: None,
402 last_bounds: None,
403 last_selected_range: None,
404 last_cursor: None,
405 scroll_handle: ScrollHandle::new(),
406 scroll_state: ScrollbarState::default(),
407 scroll_size: gpui::size(px(0.), px(0.)),
408 deferred_scroll_offset: None,
409 preferred_column: None,
410 placeholder: SharedString::default(),
411 mask_pattern: MaskPattern::default(),
412 lsp: Lsp::default(),
413 diagnostic_popover: None,
414 context_menu: None,
415 mouse_context_menu,
416 completion_inserting: false,
417 hover_popover: None,
418 hover_definition: HoverDefinition::default(),
419 silent_replace_text: false,
420 _subscriptions,
421 _context_menu_task: Task::ready(Ok(())),
422 _pending_update: false,
423 }
424 }
425
426 pub fn multi_line(mut self) -> Self {
430 self.mode = InputMode::MultiLine {
431 rows: 2,
432 tab: TabSize::default(),
433 };
434 self
435 }
436
437 pub fn auto_grow(mut self, min_rows: usize, max_rows: usize) -> Self {
439 self.mode = InputMode::AutoGrow {
440 rows: min_rows,
441 min_rows: min_rows,
442 max_rows: max_rows,
443 };
444 self
445 }
446
447 pub fn code_editor(mut self, language: impl Into<SharedString>) -> Self {
467 let language: SharedString = language.into();
468 self.mode = InputMode::CodeEditor {
469 rows: 2,
470 tab: TabSize::default(),
471 language,
472 highlighter: Rc::new(RefCell::new(None)),
473 line_number: true,
474 diagnostics: DiagnosticSet::new(&Rope::new()),
475 };
476 self.searchable = true;
477 self
478 }
479
480 pub fn searchable(mut self, searchable: bool) -> Self {
482 debug_assert!(self.mode.is_multi_line());
483 self.searchable = searchable;
484 self
485 }
486
487 pub fn placeholder(mut self, placeholder: impl Into<SharedString>) -> Self {
489 self.placeholder = placeholder.into();
490 self
491 }
492
493 pub fn line_number(mut self, line_number: bool) -> Self {
495 debug_assert!(self.mode.is_code_editor());
496 if let InputMode::CodeEditor { line_number: l, .. } = &mut self.mode {
497 *l = line_number;
498 }
499 self
500 }
501
502 pub fn set_line_number(&mut self, line_number: bool, _: &mut Window, cx: &mut Context<Self>) {
504 debug_assert!(self.mode.is_code_editor());
505 if let InputMode::CodeEditor { line_number: l, .. } = &mut self.mode {
506 *l = line_number;
507 }
508 cx.notify();
509 }
510
511 pub fn tab_size(mut self, tab: TabSize) -> Self {
515 debug_assert!(self.mode.is_multi_line() || self.mode.is_code_editor());
516 match &mut self.mode {
517 InputMode::MultiLine { tab: t, .. } => *t = tab,
518 InputMode::CodeEditor { tab: t, .. } => *t = tab,
519 _ => {}
520 }
521 self
522 }
523
524 pub fn rows(mut self, rows: usize) -> Self {
530 match &mut self.mode {
531 InputMode::MultiLine { rows: r, .. } => *r = rows,
532 InputMode::AutoGrow {
533 max_rows: max_r,
534 rows: r,
535 ..
536 } => {
537 *r = rows;
538 *max_r = rows;
539 }
540 _ => {}
541 }
542 self
543 }
544
545 pub fn set_highlighter(
547 &mut self,
548 new_language: impl Into<SharedString>,
549 cx: &mut Context<Self>,
550 ) {
551 match &mut self.mode {
552 InputMode::CodeEditor {
553 language,
554 highlighter,
555 ..
556 } => {
557 *language = new_language.into();
558 *highlighter.borrow_mut() = None;
559 }
560 _ => {}
561 }
562 cx.notify();
563 }
564
565 fn reset_highlighter(&mut self, cx: &mut Context<Self>) {
566 match &mut self.mode {
567 InputMode::CodeEditor { highlighter, .. } => {
568 *highlighter.borrow_mut() = None;
569 }
570 _ => {}
571 }
572 cx.notify();
573 }
574
575 #[inline]
576 pub fn diagnostics(&self) -> Option<&DiagnosticSet> {
577 self.mode.diagnostics()
578 }
579
580 #[inline]
581 pub fn diagnostics_mut(&mut self) -> Option<&mut DiagnosticSet> {
582 self.mode.diagnostics_mut()
583 }
584
585 pub fn set_placeholder(
587 &mut self,
588 placeholder: impl Into<SharedString>,
589 _: &mut Window,
590 cx: &mut Context<Self>,
591 ) {
592 self.placeholder = placeholder.into();
593 cx.notify();
594 }
595
596 #[allow(unused)]
604 pub(super) fn line_and_position_for_offset(
605 &self,
606 offset: usize,
607 ) -> (usize, usize, Option<Point<Pixels>>) {
608 let Some(last_layout) = &self.last_layout else {
609 return (0, 0, None);
610 };
611 let line_height = last_layout.line_height;
612
613 let mut prev_lines_offset = last_layout.visible_range_offset.start;
614 let mut y_offset = last_layout.visible_top;
615 for (line_index, line) in last_layout.lines.iter().enumerate() {
616 let local_offset = offset.saturating_sub(prev_lines_offset);
617 if let Some(pos) = line.position_for_index(local_offset, line_height) {
618 let sub_line_index = (pos.y / line_height) as usize;
619 let adjusted_pos = point(pos.x + last_layout.line_number_width, pos.y + y_offset);
620 return (line_index, sub_line_index, Some(adjusted_pos));
621 }
622
623 y_offset += line.size(line_height).height;
624 prev_lines_offset += line.len() + 1;
625 }
626 (0, 0, None)
627 }
628
629 pub fn set_value(
633 &mut self,
634 value: impl Into<SharedString>,
635 window: &mut Window,
636 cx: &mut Context<Self>,
637 ) {
638 self.history.ignore = true;
639 let was_disabled = self.disabled;
640 self.replace_text(value, window, cx);
641 self.disabled = was_disabled;
642 self.history.ignore = false;
643 if self.mode.is_single_line() {
645 self.selected_range = (self.text.len()..self.text.len()).into();
646 } else {
647 self.selected_range.clear();
648
649 self._pending_update = true;
650 self.lsp.reset();
651 }
652 self.scroll_handle.set_offset(point(px(0.), px(0.)));
654
655 cx.notify();
656 }
657
658 pub fn insert(
662 &mut self,
663 text: impl Into<SharedString>,
664 window: &mut Window,
665 cx: &mut Context<Self>,
666 ) {
667 let text: SharedString = text.into();
668 let range_utf16 = self.range_to_utf16(&(self.cursor()..self.cursor()));
669 self.replace_text_in_range_silent(Some(range_utf16), &text, window, cx);
670 self.selected_range = (self.selected_range.end..self.selected_range.end).into();
671 }
672
673 pub fn replace(
677 &mut self,
678 text: impl Into<SharedString>,
679 window: &mut Window,
680 cx: &mut Context<Self>,
681 ) {
682 let text: SharedString = text.into();
683 self.replace_text_in_range_silent(None, &text, window, cx);
684 self.selected_range = (self.selected_range.end..self.selected_range.end).into();
685 }
686
687 fn replace_text(
688 &mut self,
689 text: impl Into<SharedString>,
690 window: &mut Window,
691 cx: &mut Context<Self>,
692 ) {
693 let text: SharedString = text.into();
694 let range = 0..self.text.chars().map(|c| c.len_utf16()).sum();
695 self.replace_text_in_range_silent(Some(range), &text, window, cx);
696 self.reset_highlighter(cx);
697 }
698
699 #[allow(unused)]
703 pub(crate) fn disabled(mut self, disabled: bool) -> Self {
704 self.disabled = disabled;
705 self
706 }
707
708 pub fn masked(mut self, masked: bool) -> Self {
712 debug_assert!(self.mode.is_single_line());
713 self.masked = masked;
714 self
715 }
716
717 pub fn set_masked(&mut self, masked: bool, _: &mut Window, cx: &mut Context<Self>) {
721 debug_assert!(self.mode.is_single_line());
722 self.masked = masked;
723 cx.notify();
724 }
725
726 pub fn clean_on_escape(mut self) -> Self {
728 self.clean_on_escape = true;
729 self
730 }
731
732 pub fn soft_wrap(mut self, wrap: bool) -> Self {
734 debug_assert!(self.mode.is_multi_line());
735 self.soft_wrap = wrap;
736 self
737 }
738
739 pub fn set_soft_wrap(&mut self, wrap: bool, _: &mut Window, cx: &mut Context<Self>) {
741 debug_assert!(self.mode.is_multi_line());
742 self.soft_wrap = wrap;
743 if wrap {
744 let wrap_width = self
745 .last_layout
746 .as_ref()
747 .and_then(|b| b.wrap_width)
748 .unwrap_or(self.input_bounds.size.width);
749
750 self.text_wrapper.set_wrap_width(Some(wrap_width), cx);
751
752 let mut offset = self.scroll_handle.offset();
754 offset.x = px(0.);
755 self.scroll_handle.set_offset(offset);
756 } else {
757 self.text_wrapper.set_wrap_width(None, cx);
758 }
759 cx.notify();
760 }
761
762 pub fn pattern(mut self, pattern: regex::Regex) -> Self {
766 debug_assert!(self.mode.is_single_line());
767 self.pattern = Some(pattern);
768 self
769 }
770
771 pub fn set_pattern(
775 &mut self,
776 pattern: regex::Regex,
777 _window: &mut Window,
778 _cx: &mut Context<Self>,
779 ) {
780 debug_assert!(self.mode.is_single_line());
781 self.pattern = Some(pattern);
782 }
783
784 pub fn validate(mut self, f: impl Fn(&str, &mut Context<Self>) -> bool + 'static) -> Self {
788 debug_assert!(self.mode.is_single_line());
789 self.validate = Some(Box::new(f));
790 self
791 }
792
793 pub fn set_loading(&mut self, loading: bool, _: &mut Window, cx: &mut Context<Self>) {
797 debug_assert!(self.mode.is_single_line());
798 self.loading = loading;
799 cx.notify();
800 }
801
802 pub fn default_value(mut self, value: impl Into<SharedString>) -> Self {
804 let text: SharedString = value.into();
805 self.text = Rope::from(text.as_str());
806 if let Some(diagnostics) = self.mode.diagnostics_mut() {
807 diagnostics.reset(&self.text)
808 }
809 self.text_wrapper.set_default_text(&self.text);
810 self._pending_update = true;
811 self
812 }
813
814 pub fn value(&self) -> SharedString {
816 SharedString::new(self.text.to_string())
817 }
818
819 pub fn unmask_value(&self) -> SharedString {
821 self.mask_pattern.unmask(&self.text.to_string()).into()
822 }
823
824 pub fn text(&self) -> &Rope {
826 &self.text
827 }
828
829 pub fn cursor_position(&self) -> Position {
831 let offset = self.cursor();
832 self.text.offset_to_position(offset)
833 }
834
835 pub fn set_cursor_position(
839 &mut self,
840 position: impl Into<Position>,
841 window: &mut Window,
842 cx: &mut Context<Self>,
843 ) {
844 let position: Position = position.into();
845 let offset = self.text.position_to_offset(&position);
846
847 self.move_to(offset, cx);
848 self.update_preferred_column();
849 self.focus(window, cx);
850 }
851
852 pub fn focus(&self, window: &mut Window, cx: &mut Context<Self>) {
854 self.focus_handle.focus(window);
855 self.blink_cursor.update(cx, |cursor, cx| {
856 cursor.start(cx);
857 });
858 }
859
860 pub(super) fn select_left(&mut self, _: &SelectLeft, _: &mut Window, cx: &mut Context<Self>) {
861 self.select_to(self.previous_boundary(self.cursor()), cx);
862 }
863
864 pub(super) fn select_right(&mut self, _: &SelectRight, _: &mut Window, cx: &mut Context<Self>) {
865 self.select_to(self.next_boundary(self.cursor()), cx);
866 }
867
868 pub(super) fn select_up(&mut self, _: &SelectUp, _: &mut Window, cx: &mut Context<Self>) {
869 if self.mode.is_single_line() {
870 return;
871 }
872 let offset = self.start_of_line().saturating_sub(1);
873 self.select_to(self.previous_boundary(offset), cx);
874 }
875
876 pub(super) fn select_down(&mut self, _: &SelectDown, _: &mut Window, cx: &mut Context<Self>) {
877 if self.mode.is_single_line() {
878 return;
879 }
880 let offset = (self.end_of_line() + 1).min(self.text.len());
881 self.select_to(self.next_boundary(offset), cx);
882 }
883
884 pub(super) fn select_all(&mut self, _: &SelectAll, _: &mut Window, cx: &mut Context<Self>) {
885 self.selected_range = (0..self.text.len()).into();
886 cx.notify();
887 }
888
889 pub(super) fn select_to_start(
890 &mut self,
891 _: &SelectToStart,
892 _: &mut Window,
893 cx: &mut Context<Self>,
894 ) {
895 self.select_to(0, cx);
896 }
897
898 pub(super) fn select_to_end(
899 &mut self,
900 _: &SelectToEnd,
901 _: &mut Window,
902 cx: &mut Context<Self>,
903 ) {
904 let end = self.text.len();
905 self.select_to(end, cx);
906 }
907
908 pub(super) fn select_to_start_of_line(
909 &mut self,
910 _: &SelectToStartOfLine,
911 _: &mut Window,
912 cx: &mut Context<Self>,
913 ) {
914 let offset = self.start_of_line();
915 self.select_to(offset, cx);
916 }
917
918 pub(super) fn select_to_end_of_line(
919 &mut self,
920 _: &SelectToEndOfLine,
921 _: &mut Window,
922 cx: &mut Context<Self>,
923 ) {
924 let offset = self.end_of_line();
925 self.select_to(offset, cx);
926 }
927
928 pub(super) fn select_to_previous_word(
929 &mut self,
930 _: &SelectToPreviousWordStart,
931 _: &mut Window,
932 cx: &mut Context<Self>,
933 ) {
934 let offset = self.previous_start_of_word();
935 self.select_to(offset, cx);
936 }
937
938 pub(super) fn select_to_next_word(
939 &mut self,
940 _: &SelectToNextWordEnd,
941 _: &mut Window,
942 cx: &mut Context<Self>,
943 ) {
944 let offset = self.next_end_of_word();
945 self.select_to(offset, cx);
946 }
947
948 pub(super) fn previous_start_of_word(&mut self) -> usize {
950 let offset = self.selected_range.start;
951 let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
952 let left_part = self.text.slice(0..offset).to_string();
954
955 UnicodeSegmentation::split_word_bound_indices(left_part.as_str())
956 .filter(|(_, s)| !s.trim_start().is_empty())
957 .next_back()
958 .map(|(i, _)| i)
959 .unwrap_or(0)
960 }
961
962 pub(super) fn next_end_of_word(&mut self) -> usize {
964 let offset = self.cursor();
965 let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
966 let right_part = self.text.slice(offset..self.text.len()).to_string();
967
968 UnicodeSegmentation::split_word_bound_indices(right_part.as_str())
969 .find(|(_, s)| !s.trim_start().is_empty())
970 .map(|(i, s)| offset + i + s.len())
971 .unwrap_or(self.text.len())
972 }
973
974 pub(super) fn start_of_line(&self) -> usize {
976 if self.mode.is_single_line() {
977 return 0;
978 }
979
980 let row = self.text.offset_to_point(self.cursor()).row;
981 self.text.line_start_offset(row)
982 }
983
984 pub(super) fn end_of_line(&self) -> usize {
986 if self.mode.is_single_line() {
987 return self.text.len();
988 }
989
990 let row = self.text.offset_to_point(self.cursor()).row;
991 self.text.line_end_offset(row)
992 }
993
994 fn start_of_line_of_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) -> usize {
998 if self.mode.is_single_line() {
999 return 0;
1000 }
1001
1002 let mut offset =
1003 self.previous_boundary(self.selected_range.start.min(self.selected_range.end));
1004 if self.text.char_at(offset) == Some('\r') {
1005 offset += 1;
1006 }
1007
1008 let line = self
1009 .text_for_range(self.range_to_utf16(&(0..offset + 1)), &mut None, window, cx)
1010 .unwrap_or_default()
1011 .rfind('\n')
1012 .map(|i| i + 1)
1013 .unwrap_or(0);
1014 line
1015 }
1016
1017 pub(super) fn indent_of_next_line(&mut self) -> String {
1021 if self.mode.is_single_line() {
1022 return "".into();
1023 }
1024
1025 let mut current_indent = String::new();
1026 let mut next_indent = String::new();
1027 let current_line_start_pos = self.start_of_line();
1028 let next_line_start_pos = self.end_of_line();
1029 for c in self.text.slice(current_line_start_pos..).chars() {
1030 if !c.is_whitespace() {
1031 break;
1032 }
1033 if c == '\n' || c == '\r' {
1034 break;
1035 }
1036 current_indent.push(c);
1037 }
1038
1039 for c in self.text.slice(next_line_start_pos..).chars() {
1040 if !c.is_whitespace() {
1041 break;
1042 }
1043 if c == '\n' || c == '\r' {
1044 break;
1045 }
1046 next_indent.push(c);
1047 }
1048
1049 if next_indent.len() > current_indent.len() {
1050 return next_indent;
1051 } else {
1052 return current_indent;
1053 }
1054 }
1055
1056 pub(super) fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
1057 if self.selected_range.is_empty() {
1058 self.select_to(self.previous_boundary(self.cursor()), cx)
1059 }
1060 self.replace_text_in_range(None, "", window, cx);
1061 self.pause_blink_cursor(cx);
1062 }
1063
1064 pub(super) fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
1065 if self.selected_range.is_empty() {
1066 self.select_to(self.next_boundary(self.cursor()), cx)
1067 }
1068 self.replace_text_in_range(None, "", window, cx);
1069 self.pause_blink_cursor(cx);
1070 }
1071
1072 pub(super) fn delete_to_beginning_of_line(
1073 &mut self,
1074 _: &DeleteToBeginningOfLine,
1075 window: &mut Window,
1076 cx: &mut Context<Self>,
1077 ) {
1078 let mut offset = self.start_of_line();
1079 if offset == self.cursor() {
1080 offset = offset.saturating_sub(1);
1081 }
1082 self.replace_text_in_range_silent(
1083 Some(self.range_to_utf16(&(offset..self.cursor()))),
1084 "",
1085 window,
1086 cx,
1087 );
1088
1089 self.pause_blink_cursor(cx);
1090 }
1091
1092 pub(super) fn delete_to_end_of_line(
1093 &mut self,
1094 _: &DeleteToEndOfLine,
1095 window: &mut Window,
1096 cx: &mut Context<Self>,
1097 ) {
1098 let mut offset = self.end_of_line();
1099 if offset == self.cursor() {
1100 offset = (offset + 1).clamp(0, self.text.len());
1101 }
1102 self.replace_text_in_range_silent(
1103 Some(self.range_to_utf16(&(self.cursor()..offset))),
1104 "",
1105 window,
1106 cx,
1107 );
1108 self.pause_blink_cursor(cx);
1109 }
1110
1111 pub(super) fn delete_previous_word(
1112 &mut self,
1113 _: &DeleteToPreviousWordStart,
1114 window: &mut Window,
1115 cx: &mut Context<Self>,
1116 ) {
1117 let offset = self.previous_start_of_word();
1118 self.replace_text_in_range_silent(
1119 Some(self.range_to_utf16(&(offset..self.cursor()))),
1120 "",
1121 window,
1122 cx,
1123 );
1124 self.pause_blink_cursor(cx);
1125 }
1126
1127 pub(super) fn delete_next_word(
1128 &mut self,
1129 _: &DeleteToNextWordEnd,
1130 window: &mut Window,
1131 cx: &mut Context<Self>,
1132 ) {
1133 let offset = self.next_end_of_word();
1134 self.replace_text_in_range_silent(
1135 Some(self.range_to_utf16(&(self.cursor()..offset))),
1136 "",
1137 window,
1138 cx,
1139 );
1140 self.pause_blink_cursor(cx);
1141 }
1142
1143 pub(super) fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) {
1144 if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1145 return;
1146 }
1147
1148 if self.mode.is_multi_line() {
1149 let indent = if self.mode.is_code_editor() {
1151 self.indent_of_next_line()
1152 } else {
1153 "".to_string()
1154 };
1155
1156 let new_line_text = format!("\n{}", indent);
1158 self.replace_text_in_range_silent(None, &new_line_text, window, cx);
1159 self.pause_blink_cursor(cx);
1160 } else {
1161 cx.propagate();
1163 }
1164
1165 cx.emit(InputEvent::PressEnter {
1166 secondary: action.secondary,
1167 });
1168 }
1169
1170 pub(super) fn indent_inline(
1171 &mut self,
1172 _: &IndentInline,
1173 window: &mut Window,
1174 cx: &mut Context<Self>,
1175 ) {
1176 self.indent(false, window, cx);
1177 }
1178
1179 pub(super) fn indent_block(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
1180 self.indent(true, window, cx);
1181 }
1182
1183 pub(super) fn outdent_inline(
1184 &mut self,
1185 _: &OutdentInline,
1186 window: &mut Window,
1187 cx: &mut Context<Self>,
1188 ) {
1189 self.outdent(false, window, cx);
1190 }
1191
1192 pub(super) fn outdent_block(
1193 &mut self,
1194 _: &Outdent,
1195 window: &mut Window,
1196 cx: &mut Context<Self>,
1197 ) {
1198 self.outdent(true, window, cx);
1199 }
1200
1201 pub(super) fn indent(&mut self, block: bool, window: &mut Window, cx: &mut Context<Self>) {
1202 let Some(tab_size) = self.mode.tab_size() else {
1203 cx.propagate();
1204 return;
1205 };
1206
1207 let tab_indent = tab_size.to_string();
1208 let selected_range = self.selected_range;
1209 let mut added_len = 0;
1210 let is_selected = !self.selected_range.is_empty();
1211
1212 if is_selected || block {
1213 let start_offset = self.start_of_line_of_selection(window, cx);
1214 let mut offset = start_offset;
1215
1216 let selected_text = self
1217 .text_for_range(
1218 self.range_to_utf16(&(offset..selected_range.end)),
1219 &mut None,
1220 window,
1221 cx,
1222 )
1223 .unwrap_or("".into());
1224
1225 for line in selected_text.split('\n') {
1226 self.replace_text_in_range_silent(
1227 Some(self.range_to_utf16(&(offset..offset))),
1228 &tab_indent,
1229 window,
1230 cx,
1231 );
1232 added_len += tab_indent.len();
1233 offset += line.len() + tab_indent.len() + 1;
1235 }
1236
1237 if is_selected {
1238 self.selected_range = (start_offset..selected_range.end + added_len).into();
1239 } else {
1240 self.selected_range =
1241 (selected_range.start + added_len..selected_range.end + added_len).into();
1242 }
1243 } else {
1244 let offset = self.selected_range.start;
1246 self.replace_text_in_range_silent(
1247 Some(self.range_to_utf16(&(offset..offset))),
1248 &tab_indent,
1249 window,
1250 cx,
1251 );
1252 added_len = tab_indent.len();
1253
1254 self.selected_range =
1255 (selected_range.start + added_len..selected_range.end + added_len).into();
1256 }
1257 }
1258
1259 pub(super) fn outdent(&mut self, block: bool, window: &mut Window, cx: &mut Context<Self>) {
1260 let Some(tab_size) = self.mode.tab_size() else {
1261 cx.propagate();
1262 return;
1263 };
1264
1265 let tab_indent = tab_size.to_string();
1266 let selected_range = self.selected_range;
1267 let mut removed_len = 0;
1268 let is_selected = !self.selected_range.is_empty();
1269
1270 if is_selected || block {
1271 let start_offset = self.start_of_line_of_selection(window, cx);
1272 let mut offset = start_offset;
1273
1274 let selected_text = self
1275 .text_for_range(
1276 self.range_to_utf16(&(offset..selected_range.end)),
1277 &mut None,
1278 window,
1279 cx,
1280 )
1281 .unwrap_or("".into());
1282
1283 for line in selected_text.split('\n') {
1284 if line.starts_with(tab_indent.as_ref()) {
1285 self.replace_text_in_range_silent(
1286 Some(self.range_to_utf16(&(offset..offset + tab_indent.len()))),
1287 "",
1288 window,
1289 cx,
1290 );
1291 removed_len += tab_indent.len();
1292
1293 offset += line.len().saturating_sub(tab_indent.len()) + 1;
1295 } else {
1296 offset += line.len() + 1;
1297 }
1298 }
1299
1300 if is_selected {
1301 self.selected_range =
1302 (start_offset..selected_range.end.saturating_sub(removed_len)).into();
1303 } else {
1304 self.selected_range = (selected_range.start.saturating_sub(removed_len)
1305 ..selected_range.end.saturating_sub(removed_len))
1306 .into();
1307 }
1308 } else {
1309 let start_offset = self.selected_range.start;
1311 let offset = self.start_of_line_of_selection(window, cx);
1312 let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
1313 if self
1315 .text
1316 .slice(offset..self.text.len())
1317 .to_string()
1318 .starts_with(tab_indent.as_ref())
1319 {
1320 self.replace_text_in_range_silent(
1321 Some(self.range_to_utf16(&(offset..offset + tab_indent.len()))),
1322 "",
1323 window,
1324 cx,
1325 );
1326 removed_len = tab_indent.len();
1327 let new_offset = start_offset.saturating_sub(removed_len);
1328 self.selected_range = (new_offset..new_offset).into();
1329 }
1330 }
1331 }
1332
1333 pub(super) fn clean(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1334 self.replace_text("", window, cx);
1335 self.selected_range = (0..0).into();
1336 self.scroll_to(0, cx);
1337 }
1338
1339 pub(super) fn escape(&mut self, action: &Escape, window: &mut Window, cx: &mut Context<Self>) {
1340 if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1341 return;
1342 }
1343
1344 if self.ime_marked_range.is_some() {
1345 self.unmark_text(window, cx);
1346 }
1347
1348 if self.clean_on_escape {
1349 return self.clean(window, cx);
1350 }
1351
1352 cx.propagate();
1353 }
1354
1355 pub(super) fn on_mouse_down(
1356 &mut self,
1357 event: &MouseDownEvent,
1358 window: &mut Window,
1359 cx: &mut Context<Self>,
1360 ) {
1361 if let Some(ime_marked_range) = &self.ime_marked_range {
1364 if ime_marked_range.len() == 0 {
1365 self.ime_marked_range = None;
1366 }
1367 }
1368
1369 self.selecting = true;
1370 let offset = self.index_for_mouse_position(event.position);
1371
1372 if self.handle_click_hover_definition(event, offset, window, cx) {
1373 return;
1374 }
1375
1376 if event.button == MouseButton::Left && event.click_count == 2 {
1378 self.select_word(offset, window, cx);
1379 return;
1380 }
1381
1382 if event.button == MouseButton::Right {
1384 self.handle_right_click_menu(event, offset, window, cx);
1385 return;
1386 }
1387
1388 if event.modifiers.shift {
1389 self.select_to(offset, cx);
1390 } else {
1391 self.move_to(offset, cx)
1392 }
1393 }
1394
1395 pub(super) fn on_mouse_up(
1396 &mut self,
1397 _: &MouseUpEvent,
1398 _window: &mut Window,
1399 _cx: &mut Context<Self>,
1400 ) {
1401 self.selecting = false;
1402 self.selected_word_range = None;
1403 }
1404
1405 pub(super) fn on_mouse_move(
1406 &mut self,
1407 event: &MouseMoveEvent,
1408 window: &mut Window,
1409 cx: &mut Context<Self>,
1410 ) {
1411 let offset = self.index_for_mouse_position(event.position);
1413 self.handle_mouse_move(offset, event, window, cx);
1414
1415 if self.mode.is_code_editor() {
1416 if let Some(diagnostic) = self
1417 .mode
1418 .diagnostics()
1419 .and_then(|set| set.for_offset(offset))
1420 {
1421 if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
1422 if diagnostic_popover.read(cx).diagnostic.range == diagnostic.range {
1423 diagnostic_popover.update(cx, |this, cx| {
1424 this.show(cx);
1425 });
1426
1427 return;
1428 }
1429 }
1430
1431 self.diagnostic_popover = Some(DiagnosticPopover::new(diagnostic, cx.entity(), cx));
1432 cx.notify();
1433 } else {
1434 if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
1435 diagnostic_popover.update(cx, |this, cx| {
1436 this.check_to_hide(event.position, cx);
1437 })
1438 }
1439 }
1440 }
1441 }
1442
1443 pub(super) fn on_scroll_wheel(
1444 &mut self,
1445 event: &ScrollWheelEvent,
1446 window: &mut Window,
1447 cx: &mut Context<Self>,
1448 ) {
1449 let line_height = self
1450 .last_layout
1451 .as_ref()
1452 .map(|layout| layout.line_height)
1453 .unwrap_or(window.line_height());
1454 let delta = event.delta.pixel_delta(line_height);
1455 self.update_scroll_offset(Some(self.scroll_handle.offset() + delta), cx);
1456 self.diagnostic_popover = None;
1457 }
1458
1459 fn update_scroll_offset(&mut self, offset: Option<Point<Pixels>>, cx: &mut Context<Self>) {
1460 let mut offset = offset.unwrap_or(self.scroll_handle.offset());
1461
1462 let safe_y_range =
1463 (-self.scroll_size.height + self.input_bounds.size.height).min(px(0.0))..px(0.);
1464 let safe_x_range =
1465 (-self.scroll_size.width + self.input_bounds.size.width).min(px(0.0))..px(0.);
1466
1467 offset.y = if self.mode.is_single_line() {
1468 px(0.)
1469 } else {
1470 offset.y.clamp(safe_y_range.start, safe_y_range.end)
1471 };
1472 offset.x = offset.x.clamp(safe_x_range.start, safe_x_range.end);
1473 self.scroll_handle.set_offset(offset);
1474 cx.notify();
1475 }
1476
1477 pub(crate) fn scroll_to(&mut self, offset: usize, cx: &mut Context<Self>) {
1478 let Some(last_layout) = self.last_layout.as_ref() else {
1479 return;
1480 };
1481 let Some(bounds) = self.last_bounds.as_ref() else {
1482 return;
1483 };
1484
1485 let mut scroll_offset = self.scroll_handle.offset();
1486 let line_height = last_layout.line_height;
1487
1488 let point = self.text.offset_to_point(offset);
1489 let row = point.row;
1490
1491 let mut row_offset_y = px(0.);
1492 for (ix, wrap_line) in self.text_wrapper.lines.iter().enumerate() {
1493 if ix == row {
1494 break;
1495 }
1496
1497 row_offset_y += wrap_line.height(line_height);
1498 }
1499
1500 if let Some(line) = last_layout
1501 .lines
1502 .get(row.saturating_sub(last_layout.visible_range.start))
1503 {
1504 if let Some(pos) = line.position_for_index(point.column, line_height) {
1506 let bounds_width = bounds.size.width - last_layout.line_number_width;
1507 let col_offset_x = pos.x;
1508 if col_offset_x - RIGHT_MARGIN < -scroll_offset.x {
1509 scroll_offset.x = -col_offset_x + RIGHT_MARGIN;
1511 } else if col_offset_x + RIGHT_MARGIN > -scroll_offset.x + bounds_width {
1512 scroll_offset.x = -(col_offset_x - bounds_width + RIGHT_MARGIN);
1513 }
1514 }
1515 }
1516
1517 let edge_height = 3 * line_height;
1520 if row_offset_y - edge_height < -scroll_offset.y {
1521 scroll_offset.y = -row_offset_y + edge_height;
1523 } else if row_offset_y + edge_height > -scroll_offset.y + bounds.size.height {
1524 scroll_offset.y = -(row_offset_y - bounds.size.height + edge_height);
1526 }
1527
1528 scroll_offset.x = scroll_offset.x.min(px(0.));
1529 scroll_offset.y = scroll_offset.y.min(px(0.));
1530 self.deferred_scroll_offset = Some(scroll_offset);
1531 cx.notify();
1532 }
1533
1534 pub(super) fn show_character_palette(
1535 &mut self,
1536 _: &ShowCharacterPalette,
1537 window: &mut Window,
1538 _: &mut Context<Self>,
1539 ) {
1540 window.show_character_palette();
1541 }
1542
1543 pub(super) fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
1544 if self.selected_range.is_empty() {
1545 return;
1546 }
1547
1548 let selected_text = self.text.slice(self.selected_range).to_string();
1549 cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1550 }
1551
1552 pub(super) fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
1553 if self.selected_range.is_empty() {
1554 return;
1555 }
1556
1557 let selected_text = self.text.slice(self.selected_range).to_string();
1558 cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1559
1560 self.replace_text_in_range_silent(None, "", window, cx);
1561 }
1562
1563 pub(super) fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
1564 if let Some(clipboard) = cx.read_from_clipboard() {
1565 let mut new_text = clipboard.text().unwrap_or_default();
1566 if !self.mode.is_multi_line() {
1567 new_text = new_text.replace('\n', "");
1568 }
1569
1570 self.replace_text_in_range_silent(None, &new_text, window, cx);
1571 self.scroll_to(self.cursor(), cx);
1572 }
1573 }
1574
1575 fn push_history(&mut self, text: &Rope, range: &Range<usize>, new_text: &str) {
1576 if self.history.ignore {
1577 return;
1578 }
1579
1580 let old_text = text.slice(range.clone()).to_string();
1581
1582 let new_range = range.start..range.start + new_text.len();
1583
1584 self.history
1585 .push(Change::new(range.clone(), &old_text, new_range, new_text));
1586 }
1587
1588 pub(super) fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
1589 self.history.ignore = true;
1590 if let Some(changes) = self.history.undo() {
1591 for change in changes {
1592 let range_utf16 = self.range_to_utf16(&change.new_range.into());
1593 self.replace_text_in_range_silent(Some(range_utf16), &change.old_text, window, cx);
1594 }
1595 }
1596 self.history.ignore = false;
1597 }
1598
1599 pub(super) fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
1600 self.history.ignore = true;
1601 if let Some(changes) = self.history.redo() {
1602 for change in changes {
1603 let range_utf16 = self.range_to_utf16(&change.old_range.into());
1604 self.replace_text_in_range_silent(Some(range_utf16), &change.new_text, window, cx);
1605 }
1606 }
1607 self.history.ignore = false;
1608 }
1609
1610 pub fn cursor(&self) -> usize {
1614 if let Some(ime_marked_range) = &self.ime_marked_range {
1615 return ime_marked_range.end;
1616 }
1617
1618 if self.selection_reversed {
1619 self.selected_range.start
1620 } else {
1621 self.selected_range.end
1622 }
1623 }
1624
1625 pub(crate) fn index_for_mouse_position(&self, position: Point<Pixels>) -> usize {
1626 if self.text.len() == 0 {
1628 return 0;
1629 }
1630
1631 let (Some(bounds), Some(last_layout)) =
1632 (self.last_bounds.as_ref(), self.last_layout.as_ref())
1633 else {
1634 return 0;
1635 };
1636
1637 let line_height = last_layout.line_height;
1638 let line_number_width = last_layout.line_number_width;
1639
1640 let inner_position = position - bounds.origin - point(line_number_width, px(0.));
1651
1652 let mut index = last_layout.visible_range_offset.start;
1653 let mut y_offset = last_layout.visible_top;
1654 for (ix, line) in self
1655 .text_wrapper
1656 .lines
1657 .iter()
1658 .skip(last_layout.visible_range.start)
1659 .enumerate()
1660 {
1661 let line_origin = self.line_origin_with_y_offset(&mut y_offset, line, line_height);
1662 let pos = inner_position - line_origin;
1663
1664 let Some(line_layout) = last_layout.lines.get(ix) else {
1665 if pos.y < line_origin.y + line_height {
1666 break;
1667 }
1668
1669 continue;
1670 };
1671
1672 if self.mode.is_single_line() {
1674 return line_layout.closest_index_for_x(pos.x);
1675 }
1676
1677 if let Some(v) = line_layout.closest_index_for_position(pos, line_height) {
1678 index += v;
1679 break;
1680 } else if pos.y < px(0.) {
1681 break;
1682 }
1683
1684 index += line_layout.len() + 1;
1686 }
1687
1688 if index > self.text.len() {
1689 self.text.len()
1690 } else {
1691 index
1692 }
1693 }
1694
1695 fn line_origin_with_y_offset(
1697 &self,
1698 y_offset: &mut Pixels,
1699 line: &LineItem,
1700 line_height: Pixels,
1701 ) -> Point<Pixels> {
1702 if self.mode.is_multi_line() {
1707 let p = point(px(0.), *y_offset);
1708 *y_offset += line.height(line_height);
1709 p
1710 } else {
1711 point(px(0.), px(0.))
1712 }
1713 }
1714
1715 pub(crate) fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
1721 let offset = offset.clamp(0, self.text.len());
1722 if self.selection_reversed {
1723 self.selected_range.start = offset
1724 } else {
1725 self.selected_range.end = offset
1726 };
1727
1728 if self.selected_range.end < self.selected_range.start {
1729 self.selection_reversed = !self.selection_reversed;
1730 self.selected_range = (self.selected_range.end..self.selected_range.start).into();
1731 }
1732
1733 if let Some(word_range) = self.selected_word_range.as_ref() {
1735 if self.selected_range.start > word_range.start {
1736 self.selected_range.start = word_range.start;
1737 }
1738 if self.selected_range.end < word_range.end {
1739 self.selected_range.end = word_range.end;
1740 }
1741 }
1742 if self.selected_range.is_empty() {
1743 self.update_preferred_column();
1744 }
1745 cx.notify()
1746 }
1747
1748 fn select_word(&mut self, offset: usize, window: &mut Window, cx: &mut Context<Self>) {
1754 #[inline(always)]
1755 fn is_word(c: char) -> bool {
1756 c.is_alphanumeric() || matches!(c, '_')
1757 }
1758
1759 let mut start = offset;
1760 let mut end = start;
1761 let prev_text = self
1762 .text_for_range(self.range_to_utf16(&(0..start)), &mut None, window, cx)
1763 .unwrap_or_default();
1764 let next_text = self
1765 .text_for_range(
1766 self.range_to_utf16(&(end..self.text.len())),
1767 &mut None,
1768 window,
1769 cx,
1770 )
1771 .unwrap_or_default();
1772
1773 let prev_chars = prev_text.chars().rev();
1774 let next_chars = next_text.chars();
1775
1776 let pre_chars_count = prev_chars.clone().count();
1777 for (ix, c) in prev_chars.enumerate() {
1778 if !is_word(c) {
1779 break;
1780 }
1781
1782 if ix < pre_chars_count {
1783 start = start.saturating_sub(c.len_utf8());
1784 }
1785 }
1786
1787 for (_, c) in next_chars.enumerate() {
1788 if !is_word(c) {
1789 break;
1790 }
1791
1792 end += c.len_utf8();
1793 }
1794
1795 if start == end {
1796 return;
1797 }
1798
1799 self.selected_range = (start..end).into();
1800 self.selected_word_range = Some(self.selected_range);
1801 cx.notify()
1802 }
1803
1804 pub fn unselect(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1806 let offset = self.cursor();
1807 self.selected_range = (offset..offset).into();
1808 cx.notify()
1809 }
1810
1811 #[inline]
1812 pub(super) fn offset_from_utf16(&self, offset: usize) -> usize {
1813 self.text.offset_utf16_to_offset(offset)
1814 }
1815
1816 #[inline]
1817 pub(super) fn offset_to_utf16(&self, offset: usize) -> usize {
1818 self.text.offset_to_offset_utf16(offset)
1819 }
1820
1821 #[inline]
1822 pub(super) fn range_to_utf16(&self, range: &Range<usize>) -> Range<usize> {
1823 self.offset_to_utf16(range.start)..self.offset_to_utf16(range.end)
1824 }
1825
1826 #[inline]
1827 pub(super) fn range_from_utf16(&self, range_utf16: &Range<usize>) -> Range<usize> {
1828 self.offset_from_utf16(range_utf16.start)..self.offset_from_utf16(range_utf16.end)
1829 }
1830
1831 pub(super) fn previous_boundary(&self, offset: usize) -> usize {
1832 let mut offset = self.text.clip_offset(offset.saturating_sub(1), Bias::Left);
1833 if let Some(ch) = self.text.char_at(offset) {
1834 if ch == '\r' {
1835 offset -= 1;
1836 }
1837 }
1838
1839 offset
1840 }
1841
1842 pub(super) fn next_boundary(&self, offset: usize) -> usize {
1843 let mut offset = self.text.clip_offset(offset + 1, Bias::Right);
1844 if let Some(ch) = self.text.char_at(offset) {
1845 if ch == '\r' {
1846 offset += 1;
1847 }
1848 }
1849
1850 offset
1851 }
1852
1853 pub(crate) fn show_cursor(&self, window: &Window, cx: &App) -> bool {
1855 (self.focus_handle.is_focused(window) || self.is_context_menu_open(cx))
1856 && self.blink_cursor.read(cx).visible()
1857 && window.is_window_active()
1858 }
1859
1860 fn on_focus(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1861 self.blink_cursor.update(cx, |cursor, cx| {
1862 cursor.start(cx);
1863 });
1864 cx.emit(InputEvent::Focus);
1865 }
1866
1867 fn on_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1868 if self.is_context_menu_open(cx) {
1869 return;
1870 }
1871
1872 self.hover_popover = None;
1873 self.diagnostic_popover = None;
1874 self.context_menu = None;
1875 self.unselect(window, cx);
1876 self.blink_cursor.update(cx, |cursor, cx| {
1877 cursor.stop(cx);
1878 });
1879 Root::update(window, cx, |root, _, _| {
1880 root.focused_input = None;
1881 });
1882 cx.emit(InputEvent::Blur);
1883 cx.notify();
1884 }
1885
1886 pub(super) fn pause_blink_cursor(&mut self, cx: &mut Context<Self>) {
1887 self.blink_cursor.update(cx, |cursor, cx| {
1888 cursor.pause(cx);
1889 });
1890 }
1891
1892 pub(super) fn on_key_down(&mut self, _: &KeyDownEvent, _: &mut Window, cx: &mut Context<Self>) {
1893 self.pause_blink_cursor(cx);
1894 }
1895
1896 pub(super) fn on_drag_move(
1897 &mut self,
1898 event: &MouseMoveEvent,
1899 window: &mut Window,
1900 cx: &mut Context<Self>,
1901 ) {
1902 if self.text.len() == 0 {
1903 return;
1904 }
1905
1906 if self.last_layout.is_none() {
1907 return;
1908 }
1909
1910 if !self.focus_handle.is_focused(window) {
1911 return;
1912 }
1913
1914 if !self.selecting {
1915 return;
1916 }
1917
1918 let offset = self.index_for_mouse_position(event.position);
1919 self.select_to(offset, cx);
1920 }
1921
1922 fn is_valid_input(&self, new_text: &str, cx: &mut Context<Self>) -> bool {
1923 if new_text.is_empty() {
1924 return true;
1925 }
1926
1927 if let Some(validate) = &self.validate {
1928 if !validate(new_text, cx) {
1929 return false;
1930 }
1931 }
1932
1933 if !self.mask_pattern.is_valid(new_text) {
1934 return false;
1935 }
1936
1937 let Some(pattern) = &self.pattern else {
1938 return true;
1939 };
1940
1941 pattern.is_match(new_text)
1942 }
1943
1944 pub fn mask_pattern(mut self, pattern: impl Into<MaskPattern>) -> Self {
1954 self.mask_pattern = pattern.into();
1955 if let Some(placeholder) = self.mask_pattern.placeholder() {
1956 self.placeholder = placeholder.into();
1957 }
1958 self
1959 }
1960
1961 pub fn set_mask_pattern(
1962 &mut self,
1963 pattern: impl Into<MaskPattern>,
1964 _: &mut Window,
1965 cx: &mut Context<Self>,
1966 ) {
1967 self.mask_pattern = pattern.into();
1968 if let Some(placeholder) = self.mask_pattern.placeholder() {
1969 self.placeholder = placeholder.into();
1970 }
1971 cx.notify();
1972 }
1973
1974 pub(super) fn set_input_bounds(&mut self, new_bounds: Bounds<Pixels>, cx: &mut Context<Self>) {
1975 let wrap_width_changed = self.input_bounds.size.width != new_bounds.size.width;
1976 self.input_bounds = new_bounds;
1977
1978 if let Some(last_layout) = self.last_layout.as_ref() {
1980 if wrap_width_changed {
1981 let wrap_width = if !self.soft_wrap {
1982 None
1984 } else {
1985 last_layout.wrap_width
1986 };
1987
1988 self.text_wrapper.set_wrap_width(wrap_width, cx);
1989 self.mode.update_auto_grow(&self.text_wrapper);
1990 cx.notify();
1991 }
1992 }
1993 }
1994
1995 pub(super) fn selected_text(&self) -> RopeSlice<'_> {
1996 let range_utf16 = self.range_to_utf16(&self.selected_range.into());
1997 let range = self.range_from_utf16(&range_utf16);
1998 self.text.slice(range)
1999 }
2000
2001 pub(crate) fn range_to_bounds(&self, range: &Range<usize>) -> Option<Bounds<Pixels>> {
2002 let Some(last_layout) = self.last_layout.as_ref() else {
2003 return None;
2004 };
2005
2006 let Some(last_bounds) = self.last_bounds else {
2007 return None;
2008 };
2009
2010 let (_, _, start_pos) = self.line_and_position_for_offset(range.start);
2011 let (_, _, end_pos) = self.line_and_position_for_offset(range.end);
2012
2013 let Some(start_pos) = start_pos else {
2014 return None;
2015 };
2016 let Some(end_pos) = end_pos else {
2017 return None;
2018 };
2019
2020 Some(Bounds::from_corners(
2021 last_bounds.origin + start_pos,
2022 last_bounds.origin + end_pos + point(px(0.), last_layout.line_height),
2023 ))
2024 }
2025
2026 #[allow(unused)]
2030 pub(crate) fn replace_text_in_lsp_range(
2031 &mut self,
2032 lsp_range: &lsp_types::Range,
2033 new_text: &str,
2034 window: &mut Window,
2035 cx: &mut Context<Self>,
2036 ) {
2037 let start = self.text.position_to_offset(&lsp_range.start);
2038 let end = self.text.position_to_offset(&lsp_range.end);
2039 self.replace_text_in_range_silent(
2040 Some(self.range_to_utf16(&(start..end))),
2041 new_text,
2042 window,
2043 cx,
2044 );
2045 }
2046
2047 pub(crate) fn replace_text_in_range_silent(
2051 &mut self,
2052 range_utf16: Option<Range<usize>>,
2053 new_text: &str,
2054 window: &mut Window,
2055 cx: &mut Context<Self>,
2056 ) {
2057 self.silent_replace_text = true;
2058 self.replace_text_in_range(range_utf16, new_text, window, cx);
2059 self.silent_replace_text = false;
2060 }
2061}
2062
2063impl EntityInputHandler for InputState {
2064 fn text_for_range(
2065 &mut self,
2066 range_utf16: Range<usize>,
2067 adjusted_range: &mut Option<Range<usize>>,
2068 _window: &mut Window,
2069 _cx: &mut Context<Self>,
2070 ) -> Option<String> {
2071 let range = self.range_from_utf16(&range_utf16);
2072 adjusted_range.replace(self.range_to_utf16(&range));
2073 Some(self.text.slice(range).to_string())
2074 }
2075
2076 fn selected_text_range(
2077 &mut self,
2078 _ignore_disabled_input: bool,
2079 _window: &mut Window,
2080 _cx: &mut Context<Self>,
2081 ) -> Option<UTF16Selection> {
2082 Some(UTF16Selection {
2083 range: self.range_to_utf16(&self.selected_range.into()),
2084 reversed: false,
2085 })
2086 }
2087
2088 fn marked_text_range(
2089 &self,
2090 _window: &mut Window,
2091 _cx: &mut Context<Self>,
2092 ) -> Option<Range<usize>> {
2093 self.ime_marked_range
2094 .map(|range| self.range_to_utf16(&range.into()))
2095 }
2096
2097 fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
2098 self.ime_marked_range = None;
2099 }
2100
2101 fn replace_text_in_range(
2106 &mut self,
2107 range_utf16: Option<Range<usize>>,
2108 new_text: &str,
2109 window: &mut Window,
2110 cx: &mut Context<Self>,
2111 ) {
2112 if self.disabled {
2113 return;
2114 }
2115
2116 self.pause_blink_cursor(cx);
2117
2118 let range = range_utf16
2119 .as_ref()
2120 .map(|range_utf16| self.range_from_utf16(range_utf16))
2121 .or(self.ime_marked_range.map(|range| {
2122 let range = self.range_to_utf16(&(range.start..range.end));
2123 self.range_from_utf16(&range)
2124 }))
2125 .unwrap_or(self.selected_range.into());
2126
2127 let old_text = self.text.clone();
2128 self.text.replace(range.clone(), new_text);
2129
2130 let mut new_offset = (range.start + new_text.len()).min(self.text.len());
2131
2132 if self.mode.is_single_line() {
2133 let pending_text = self.text.to_string();
2134 if !self.is_valid_input(&pending_text, cx) {
2136 self.text = old_text;
2137 return;
2138 }
2139
2140 if !self.mask_pattern.is_none() {
2141 let mask_text = self.mask_pattern.mask(&pending_text);
2142 self.text = Rope::from(mask_text.as_str());
2143 let new_text_len =
2144 (new_text.len() + mask_text.len()).saturating_sub(pending_text.len());
2145 new_offset = (range.start + new_text_len).min(mask_text.len());
2146 }
2147 }
2148
2149 self.push_history(&old_text, &range, &new_text);
2150 if let Some(diagnostics) = self.mode.diagnostics_mut() {
2151 diagnostics.reset(&self.text)
2152 }
2153 self.text_wrapper
2154 .update(&self.text, &range, &Rope::from(new_text), cx);
2155 self.mode
2156 .update_highlighter(&range, &self.text, &new_text, true, cx);
2157 self.lsp.update(&self.text, window, cx);
2158 self.selected_range = (new_offset..new_offset).into();
2159 self.ime_marked_range.take();
2160 self.update_preferred_column();
2161 self.update_search(cx);
2162 self.mode.update_auto_grow(&self.text_wrapper);
2163 if !self.silent_replace_text {
2164 self.handle_completion_trigger(&range, &new_text, window, cx);
2165 }
2166 cx.emit(InputEvent::Change);
2167 cx.notify();
2168 }
2169
2170 fn replace_and_mark_text_in_range(
2172 &mut self,
2173 range_utf16: Option<Range<usize>>,
2174 new_text: &str,
2175 new_selected_range_utf16: Option<Range<usize>>,
2176 window: &mut Window,
2177 cx: &mut Context<Self>,
2178 ) {
2179 if self.disabled {
2180 return;
2181 }
2182
2183 self.lsp.reset();
2184
2185 let range = range_utf16
2186 .as_ref()
2187 .map(|range_utf16| self.range_from_utf16(range_utf16))
2188 .or(self.ime_marked_range.map(|range| {
2189 let range = self.range_to_utf16(&(range.start..range.end));
2190 self.range_from_utf16(&range)
2191 }))
2192 .unwrap_or(self.selected_range.into());
2193
2194 let old_text = self.text.clone();
2195 self.text.replace(range.clone(), new_text);
2196
2197 if self.mode.is_single_line() {
2198 let pending_text = self.text.to_string();
2199 if !self.is_valid_input(&pending_text, cx) {
2200 self.text = old_text;
2201 return;
2202 }
2203 }
2204
2205 self.push_history(&old_text, &range, new_text);
2206 if let Some(diagnostics) = self.mode.diagnostics_mut() {
2207 diagnostics.reset(&self.text)
2208 }
2209 self.text_wrapper
2210 .update(&self.text, &range, &Rope::from(new_text), cx);
2211 self.mode
2212 .update_highlighter(&range, &self.text, &new_text, true, cx);
2213 self.lsp.update(&self.text, window, cx);
2214 if new_text.is_empty() {
2215 self.selected_range = (range.start..range.start).into();
2217 self.ime_marked_range = None;
2218 } else {
2219 self.ime_marked_range = Some((range.start..range.start + new_text.len()).into());
2220 self.selected_range = new_selected_range_utf16
2221 .as_ref()
2222 .map(|range_utf16| self.range_from_utf16(range_utf16))
2223 .map(|new_range| new_range.start + range.start..new_range.end + range.end)
2224 .unwrap_or_else(|| range.start + new_text.len()..range.start + new_text.len())
2225 .into();
2226 }
2227 self.mode.update_auto_grow(&self.text_wrapper);
2228 cx.emit(InputEvent::Change);
2229 cx.notify();
2230 }
2231
2232 fn bounds_for_range(
2234 &mut self,
2235 range_utf16: Range<usize>,
2236 bounds: Bounds<Pixels>,
2237 _window: &mut Window,
2238 _cx: &mut Context<Self>,
2239 ) -> Option<Bounds<Pixels>> {
2240 let last_layout = self.last_layout.as_ref()?;
2241 let line_height = last_layout.line_height;
2242 let line_number_width = last_layout.line_number_width;
2243 let range = self.range_from_utf16(&range_utf16);
2244
2245 let mut start_origin = None;
2246 let mut end_origin = None;
2247 let line_number_origin = point(line_number_width, px(0.));
2248 let mut y_offset = last_layout.visible_top;
2249 let mut index_offset = last_layout.visible_range_offset.start;
2250
2251 for line in last_layout.lines.iter() {
2252 if start_origin.is_some() && end_origin.is_some() {
2253 break;
2254 }
2255
2256 if start_origin.is_none() {
2257 if let Some(p) =
2258 line.position_for_index(range.start.saturating_sub(index_offset), line_height)
2259 {
2260 start_origin = Some(p + point(px(0.), y_offset));
2261 }
2262 }
2263
2264 if end_origin.is_none() {
2265 if let Some(p) =
2266 line.position_for_index(range.end.saturating_sub(index_offset), line_height)
2267 {
2268 end_origin = Some(p + point(px(0.), y_offset));
2269 }
2270 }
2271
2272 index_offset += line.len() + 1;
2273 y_offset += line.size(line_height).height;
2274 }
2275
2276 let start_origin = start_origin.unwrap_or_default();
2277 let mut end_origin = end_origin.unwrap_or_default();
2278 end_origin.y = start_origin.y;
2280
2281 Some(Bounds::from_corners(
2282 bounds.origin + line_number_origin + start_origin,
2283 bounds.origin + line_number_origin + point(end_origin.x, end_origin.y + line_height),
2285 ))
2286 }
2287
2288 fn character_index_for_point(
2289 &mut self,
2290 point: gpui::Point<Pixels>,
2291 _window: &mut Window,
2292 _cx: &mut Context<Self>,
2293 ) -> Option<usize> {
2294 let last_layout = self.last_layout.as_ref()?;
2295 let line_height = last_layout.line_height;
2296 let line_point = self.last_bounds?.localize(&point)?;
2297 let offset = last_layout.visible_range_offset.start;
2298
2299 for line in last_layout.lines.iter() {
2300 if let Some(utf8_index) = line.index_for_position(line_point, line_height) {
2301 return Some(self.offset_to_utf16(offset + utf8_index));
2302 }
2303 }
2304
2305 None
2306 }
2307}
2308
2309impl Focusable for InputState {
2310 fn focus_handle(&self, _cx: &App) -> FocusHandle {
2311 self.focus_handle.clone()
2312 }
2313}
2314
2315impl Render for InputState {
2316 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
2317 if self._pending_update {
2318 self.mode
2319 .update_highlighter(&(0..0), &self.text, "", false, cx);
2320 self.lsp.update(&self.text, window, cx);
2321 self._pending_update = false;
2322 }
2323
2324 div()
2325 .id("input-state")
2326 .flex_1()
2327 .when(self.mode.is_multi_line(), |this| this.h_full())
2328 .flex_grow()
2329 .overflow_x_hidden()
2330 .child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone()))
2331 .children(self.diagnostic_popover.clone())
2332 .children(self.context_menu.as_ref().map(|menu| menu.render()))
2333 .children(self.hover_popover.clone())
2334 }
2335}