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