gpui_component/input/
state.rs

1//! A text input field that allows the user to enter text.
2//!
3//! Based on the `Input` example from the `gpui` crate.
4//! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs
5use 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    /// Is confirm with secondary.
45    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    /// The visible range (no wrap) of lines in the viewport, the value is row (0-based) index.
235    pub(super) visible_range: Range<usize>,
236    /// The first visible line top position in scroll viewport.
237    pub(super) visible_top: Pixels,
238    /// The range of byte offset of the visible lines.
239    pub(super) visible_range_offset: Range<usize>,
240    /// The last layout lines (Only have visible lines).
241    pub(super) lines: Rc<Vec<LineLayout>>,
242    /// The line_height of text layout, this will change will InputElement painted.
243    pub(super) line_height: Pixels,
244    /// The wrap width of text layout, this will change will InputElement painted.
245    pub(super) wrap_width: Option<Pixels>,
246    /// The line number area width of text layout, if not line number, this will be 0px.
247    pub(super) line_number_width: Pixels,
248    /// The cursor position (top, left) in pixels.
249    pub(super) cursor_bounds: Option<Bounds<Pixels>>,
250}
251
252impl LastLayout {
253    /// Get the line layout for the given row (0-based).
254    ///
255    /// 0 is the viewport first visible line.
256    ///
257    /// Returns None if the row is out of range.
258    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
267/// InputState to keep editing state of the [`super::TextInput`].
268pub 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    /// Range in UTF-8 length for the selected text.
277    ///
278    /// - "Hello 世界💝" = 16
279    /// - "💝" = 4
280    pub(super) selected_range: Selection,
281    pub(super) search_panel: Option<Entity<SearchPanel>>,
282    pub(super) searchable: bool,
283    /// Range for save the selected word, use to keep word range when drag move.
284    pub(super) selected_word_range: Option<Selection>,
285    pub(super) selection_reversed: bool,
286    /// The marked range is the temporary insert text on IME typing.
287    pub(super) ime_marked_range: Option<Selection>,
288    pub(super) last_layout: Option<LastLayout>,
289    pub(super) last_cursor: Option<usize>,
290    /// The input container bounds
291    pub(super) input_bounds: Bounds<Pixels>,
292    /// The text bounds
293    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    /// The deferred scroll offset to apply on next layout.
304    pub(crate) deferred_scroll_offset: Option<Point<Pixels>>,
305    pub(super) scroll_state: ScrollbarState,
306    /// The size of the scrollable content.
307    pub(crate) scroll_size: gpui::Size<Pixels>,
308
309    /// The mask pattern for formatting the input text
310    pub(crate) mask_pattern: MaskPattern,
311    pub(super) placeholder: SharedString,
312
313    /// Popover
314    diagnostic_popover: Option<Entity<DiagnosticPopover>>,
315    /// Completion/CodeAction context menu
316    pub(super) context_menu: Option<ContextMenu>,
317    pub(super) mouse_context_menu: Entity<MouseContextMenu>,
318    /// A flag to indicate if we are currently inserting a completion item.
319    pub(super) completion_inserting: bool,
320    pub(super) hover_popover: Option<Entity<HoverPopover>>,
321    /// The LSP definitions locations for "Go to Definition" feature.
322    pub(super) hover_definition: HoverDefinition,
323
324    pub lsp: Lsp,
325
326    /// A flag to indicate if we have a pending update to the text.
327    ///
328    /// If true, will call some update (for example LSP, Syntax Highlight) before render.
329    _pending_update: bool,
330    /// A flag to indicate if we should ignore the next completion event.
331    pub(super) silent_replace_text: bool,
332
333    /// To remember the horizontal column (x-coordinate) of the cursor position for keep column for move up/down.
334    ///
335    /// The first element is the x-coordinate (Pixels), preferred to use this.
336    /// The second element is the column (usize), fallback to use this.
337    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    /// Create a Input state with default [`InputMode::SingleLine`] mode.
347    ///
348    /// See also: [`Self::multi_line`], [`Self::auto_grow`] to set other mode.
349    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            // Observe the blink cursor to repaint the view when it changes.
356            cx.observe(&blink_cursor, |_, _, cx| cx.notify()),
357            // Blink the cursor when the window is active, pause when it's not.
358            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    /// Set Input to use [`InputMode::MultiLine`] mode.
427    ///
428    /// Default rows is 2.
429    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    /// Set Input to use [`InputMode::AutoGrow`] mode with min, max rows limit.
438    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    /// Set Input to use [`InputMode::CodeEditor`] mode.
448    ///
449    /// Default options:
450    ///
451    /// - line_number: true
452    /// - tab_size: 2
453    /// - hard_tabs: false
454    /// - height: full
455    ///
456    /// If `highlighter` is None, will use the default highlighter.
457    ///
458    /// Code Editor aim for help used to simple code editing or display, not a full-featured code editor.
459    ///
460    /// ## Features
461    ///
462    /// - Syntax Highlighting
463    /// - Auto Indent
464    /// - Line Number
465    /// - Large Text support, up to 50K lines.
466    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    /// Set this input is searchable, default is false (Default true for Code Editor).
481    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    /// Set placeholder
488    pub fn placeholder(mut self, placeholder: impl Into<SharedString>) -> Self {
489        self.placeholder = placeholder.into();
490        self
491    }
492
493    /// Set enable/disable line number, only for [`InputMode::CodeEditor`] mode.
494    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    /// Set line number, only for [`InputMode::CodeEditor`] mode.
503    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    /// Set the tab size for the input.
512    ///
513    /// Only for [`InputMode::MultiLine`] and [`InputMode::CodeEditor`] mode.
514    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    /// Set the number of rows for the multi-line Textarea.
525    ///
526    /// This is only used when `multi_line` is set to true.
527    ///
528    /// default: 2
529    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    /// Set highlighter language for for [`InputMode::CodeEditor`] mode.
546    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    /// Set placeholder
586    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    /// Find which line and sub-line the given offset belongs to, along with the position within that sub-line.
597    ///
598    /// Returns:
599    ///
600    /// - The index of the line (zero-based) containing the offset.
601    /// - The index of the sub-line (zero-based) within the line containing the offset.
602    /// - The position of the offset.
603    #[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    /// Set the text of the input field.
630    ///
631    /// And the selection_range will be reset to 0..0.
632    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        // Ensure cursor to start when set text
644        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        // Move scroll to top
653        self.scroll_handle.set_offset(point(px(0.), px(0.)));
654
655        cx.notify();
656    }
657
658    /// Insert text at the current cursor position.
659    ///
660    /// And the cursor will be moved to the end of inserted text.
661    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    /// Replace text at the current cursor position.
674    ///
675    /// And the cursor will be moved to the end of replaced text.
676    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    /// Set with disabled mode.
700    ///
701    /// See also: [`Self::set_disabled`], [`Self::is_disabled`].
702    #[allow(unused)]
703    pub(crate) fn disabled(mut self, disabled: bool) -> Self {
704        self.disabled = disabled;
705        self
706    }
707
708    /// Set with password masked state.
709    ///
710    /// Only for [`InputMode::SingleLine`] mode.
711    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    /// Set the password masked state of the input field.
718    ///
719    /// Only for [`InputMode::SingleLine`] mode.
720    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    /// Set true to clear the input by pressing Escape key.
727    pub fn clean_on_escape(mut self) -> Self {
728        self.clean_on_escape = true;
729        self
730    }
731
732    /// Set the soft wrap mode for multi-line input, default is true.
733    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    /// Update the soft wrap mode for multi-line input, default is true.
740    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            // Reset scroll to left 0
753            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    /// Set the regular expression pattern of the input field.
763    ///
764    /// Only for [`InputMode::SingleLine`] mode.
765    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    /// Set the regular expression pattern of the input field with reference.
772    ///
773    /// Only for [`InputMode::SingleLine`] mode.
774    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    /// Set the validation function of the input field.
785    ///
786    /// Only for [`InputMode::SingleLine`] mode.
787    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    /// Set true to show indicator at the input right.
794    ///
795    /// Only for [`InputMode::SingleLine`] mode.
796    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    /// Set the default value of the input field.
803    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    /// Return the value of the input field.
815    pub fn value(&self) -> SharedString {
816        SharedString::new(self.text.to_string())
817    }
818
819    /// Return the value without mask.
820    pub fn unmask_value(&self) -> SharedString {
821        self.mask_pattern.unmask(&self.text.to_string()).into()
822    }
823
824    /// Return the text [`Rope`] of the input field.
825    pub fn text(&self) -> &Rope {
826        &self.text
827    }
828
829    /// Return the (0-based) [`Position`] of the cursor.
830    pub fn cursor_position(&self) -> Position {
831        let offset = self.cursor();
832        self.text.offset_to_position(offset)
833    }
834
835    /// Set (0-based) [`Position`] of the cursor.
836    ///
837    /// This will move the cursor to the specified line and column, and update the selection range.
838    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    /// Focus the input field.
853    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    /// Return the start offset of the previous word.
949    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        // FIXME: Avoid to_string
953        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    /// Return the next end offset of the next word.
963    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    /// Get start of line byte offset of cursor
975    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    /// Get end of line byte offset of cursor
985    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    /// Get start line of selection start or end (The min value).
995    ///
996    /// This is means is always get the first line of selection.
997    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    /// Get indent string of next line.
1018    ///
1019    /// To get current and next line indent, to return more depth one.
1020    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            // Get current line indent
1150            let indent = if self.mode.is_code_editor() {
1151                self.indent_of_next_line()
1152            } else {
1153                "".to_string()
1154            };
1155
1156            // Add newline and indent
1157            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            // Single line input, just emit the event (e.g.: In a modal dialog to confirm).
1162            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                // +1 for "\n", the `\r` is included in the `line`.
1234                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            // Selected none
1245            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                    // +1 for "\n"
1294                    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            // Selected none
1310            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            // FIXME: To improve performance
1314            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 there have IME marked range and is empty (Means pressed Esc to abort IME typing)
1362        // Clear the marked range.
1363        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        // Double click to select word
1377        if event.button == MouseButton::Left && event.click_count == 2 {
1378            self.select_word(offset, window, cx);
1379            return;
1380        }
1381
1382        // Show Mouse context menu
1383        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        // Show diagnostic popover on mouse move
1412        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            // Check to scroll horizontally
1505            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                    // If the position is out of the visible area, scroll to make it visible
1510                    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        // Check if row_offset_y is out of the viewport
1518        // If row offset is not in the viewport, scroll to make it visible
1519        let edge_height = 3 * line_height;
1520        if row_offset_y - edge_height < -scroll_offset.y {
1521            // Scroll up
1522            scroll_offset.y = -row_offset_y + edge_height;
1523        } else if row_offset_y + edge_height > -scroll_offset.y + bounds.size.height {
1524            // Scroll down
1525            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    /// Get byte offset of the cursor.
1611    ///
1612    /// The offset is the UTF-8 offset.
1613    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 the text is empty, always return 0
1627        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        // TIP: About the IBeam cursor
1641        //
1642        // If cursor style is IBeam, the mouse mouse position is in the middle of the cursor (This is special in OS)
1643
1644        // The position is relative to the bounds of the text input
1645        //
1646        // bounds.origin:
1647        //
1648        // - included the input padding.
1649        // - included the scroll offset.
1650        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            // Return offset by use closest_index_for_x if is single line mode.
1673            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            // +1 for `\n`
1685            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    /// Returns a y offsetted point for the line origin.
1696    fn line_origin_with_y_offset(
1697        &self,
1698        y_offset: &mut Pixels,
1699        line: &LineItem,
1700        line_height: Pixels,
1701    ) -> Point<Pixels> {
1702        // NOTE: About line.wrap_boundaries.len()
1703        //
1704        // If only 1 line, the value is 0
1705        // If have 2 line, the value is 1
1706        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    /// Select the text from the current cursor position to the given offset.
1716    ///
1717    /// The offset is the UTF-8 offset.
1718    ///
1719    /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset.
1720    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        // Ensure keep word selected range
1734        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    /// Select the word at the given offset.
1749    ///
1750    /// The offset is the UTF-8 offset.
1751    ///
1752    /// FIXME: When click on a non-word character, the word is not selected.
1753    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    /// Unselects the currently selected text.
1805    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    /// Returns the true to let InputElement to render cursor, when Input is focused and current BlinkCursor is visible.
1854    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    /// Set the mask pattern for formatting the input text.
1945    ///
1946    /// The pattern can contain:
1947    /// - 9: Any digit or dot
1948    /// - A: Any letter
1949    /// - *: Any character
1950    /// - Other characters will be treated as literal mask characters
1951    ///
1952    /// Example: "(999)999-999" for phone numbers
1953    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        // Update text_wrapper wrap_width if changed.
1979        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 to disable wrapping (will use Pixels::MAX)
1983                    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    /// Replace text by [`lsp_types::Range`].
2027    ///
2028    /// See also: [`EntityInputHandler::replace_text_in_range`]
2029    #[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    /// Replace text in range in silent.
2048    ///
2049    /// This will not trigger any UI interaction, such as auto-completion.
2050    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    /// Replace text in range.
2102    ///
2103    /// - If the new text is invalid, it will not be replaced.
2104    /// - If `range_utf16` is not provided, the current selected range will be used.
2105    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            // Check if the new text is valid
2135            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    /// Mark text is the IME temporary insert on typing.
2171    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            // Cancel selection, when cancel IME input.
2216            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    /// Used to position IME candidates.
2233    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        // Ensure at same line.
2279        end_origin.y = start_origin.y;
2280
2281        Some(Bounds::from_corners(
2282            bounds.origin + line_number_origin + start_origin,
2283            // + line_height for show IME panel under the cursor line.
2284            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}