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::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    /// Is confirm with secondary.
46    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    /// The visible range (no wrap) of lines in the viewport, the value is row (0-based) index.
232    pub(super) visible_range: Range<usize>,
233    /// The first visible line top position in scroll viewport.
234    pub(super) visible_top: Pixels,
235    /// The range of byte offset of the visible lines.
236    pub(super) visible_range_offset: Range<usize>,
237    /// The last layout lines (Only have visible lines).
238    pub(super) lines: Rc<Vec<LineLayout>>,
239    /// The line_height of text layout, this will change will InputElement painted.
240    pub(super) line_height: Pixels,
241    /// The wrap width of text layout, this will change will InputElement painted.
242    pub(super) wrap_width: Option<Pixels>,
243    /// The line number area width of text layout, if not line number, this will be 0px.
244    pub(super) line_number_width: Pixels,
245    /// The cursor position (top, left) in pixels.
246    pub(super) cursor_bounds: Option<Bounds<Pixels>>,
247}
248
249impl LastLayout {
250    /// Get the line layout for the given row (0-based).
251    ///
252    /// 0 is the viewport first visible line.
253    ///
254    /// Returns None if the row is out of range.
255    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
264/// InputState to keep editing state of the [`super::TextInput`].
265pub 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    /// Range in UTF-8 length for the selected text.
274    ///
275    /// - "Hello 世界💝" = 16
276    /// - "💝" = 4
277    pub(super) selected_range: Selection,
278    pub(super) search_panel: Option<Entity<SearchPanel>>,
279    pub(super) searchable: bool,
280    /// Range for save the selected word, use to keep word range when drag move.
281    pub(super) selected_word_range: Option<Selection>,
282    pub(super) selection_reversed: bool,
283    /// The marked range is the temporary insert text on IME typing.
284    pub(super) ime_marked_range: Option<Selection>,
285    pub(super) last_layout: Option<LastLayout>,
286    pub(super) last_cursor: Option<usize>,
287    /// The input container bounds
288    pub(super) input_bounds: Bounds<Pixels>,
289    /// The text bounds
290    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    /// The deferred scroll offset to apply on next layout.
301    pub(crate) deferred_scroll_offset: Option<Point<Pixels>>,
302    pub(super) scroll_state: ScrollbarState,
303    /// The size of the scrollable content.
304    pub(crate) scroll_size: gpui::Size<Pixels>,
305
306    /// The mask pattern for formatting the input text
307    pub(crate) mask_pattern: MaskPattern,
308    pub(super) placeholder: SharedString,
309
310    /// Popover
311    diagnostic_popover: Option<Entity<DiagnosticPopover>>,
312    /// Completion/CodeAction context menu
313    pub(super) context_menu: Option<ContextMenu>,
314    pub(super) mouse_context_menu: Entity<MouseContextMenu>,
315    /// A flag to indicate if we are currently inserting a completion item.
316    pub(super) completion_inserting: bool,
317    pub(super) hover_popover: Option<Entity<HoverPopover>>,
318    /// The LSP definitions locations for "Go to Definition" feature.
319    pub(super) hover_definition: HoverDefinition,
320
321    pub lsp: Lsp,
322
323    /// A flag to indicate if we have a pending update to the text.
324    ///
325    /// If true, will call some update (for example LSP, Syntax Highlight) before render.
326    _pending_update: bool,
327    /// A flag to indicate if we should ignore the next completion event.
328    pub(super) silent_replace_text: bool,
329
330    /// To remember the horizontal column (x-coordinate) of the cursor position for keep column for move up/down.
331    ///
332    /// The first element is the x-coordinate (Pixels), preferred to use this.
333    /// The second element is the column (usize), fallback to use this.
334    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    /// Create a Input state with default [`InputMode::SingleLine`] mode.
344    ///
345    /// See also: [`Self::multi_line`], [`Self::auto_grow`] to set other mode.
346    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            // Observe the blink cursor to repaint the view when it changes.
353            cx.observe(&blink_cursor, |_, _, cx| cx.notify()),
354            // Blink the cursor when the window is active, pause when it's not.
355            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    /// Set Input to use [`InputMode::MultiLine`] mode.
424    ///
425    /// Default rows is 2.
426    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    /// Set Input to use [`InputMode::AutoGrow`] mode with min, max rows limit.
435    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    /// Set Input to use [`InputMode::CodeEditor`] mode.
445    ///
446    /// Default options:
447    ///
448    /// - line_number: true
449    /// - tab_size: 2
450    /// - hard_tabs: false
451    /// - height: full
452    ///
453    /// If `highlighter` is None, will use the default highlighter.
454    ///
455    /// Code Editor aim for help used to simple code editing or display, not a full-featured code editor.
456    ///
457    /// ## Features
458    ///
459    /// - Syntax Highlighting
460    /// - Auto Indent
461    /// - Line Number
462    /// - Large Text support, up to 50K lines.
463    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    /// Set this input is searchable, default is false (Default true for Code Editor).
478    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    /// Set placeholder
485    pub fn placeholder(mut self, placeholder: impl Into<SharedString>) -> Self {
486        self.placeholder = placeholder.into();
487        self
488    }
489
490    /// Set enable/disable line number, only for [`InputMode::CodeEditor`] mode.
491    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    /// Set line number, only for [`InputMode::CodeEditor`] mode.
500    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    /// Set the tab size for the input.
509    ///
510    /// Only for [`InputMode::MultiLine`] and [`InputMode::CodeEditor`] mode.
511    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    /// Set the number of rows for the multi-line Textarea.
522    ///
523    /// This is only used when `multi_line` is set to true.
524    ///
525    /// default: 2
526    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    /// Set highlighter language for for [`InputMode::CodeEditor`] mode.
543    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    /// Set placeholder
583    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    /// Find which line and sub-line the given offset belongs to, along with the position within that sub-line.
594    ///
595    /// Returns:
596    ///
597    /// - The index of the line (zero-based) containing the offset.
598    /// - The index of the sub-line (zero-based) within the line containing the offset.
599    /// - The position of the offset.
600    #[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    /// Set the text of the input field.
627    ///
628    /// And the selection_range will be reset to 0..0.
629    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        // Ensure cursor to start when set text
642        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        // Move scroll to top
651        self.scroll_handle.set_offset(point(px(0.), px(0.)));
652
653        cx.notify();
654    }
655
656    /// Insert text at the current cursor position.
657    ///
658    /// And the cursor will be moved to the end of inserted text.
659    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    /// Replace text at the current cursor position.
672    ///
673    /// And the cursor will be moved to the end of replaced text.
674    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    /// Set with disabled mode.
698    ///
699    /// See also: [`Self::set_disabled`], [`Self::is_disabled`].
700    #[allow(unused)]
701    pub(crate) fn disabled(mut self, disabled: bool) -> Self {
702        self.disabled = disabled;
703        self
704    }
705
706    /// Set with password masked state.
707    ///
708    /// Only for [`InputMode::SingleLine`] mode.
709    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    /// Set the password masked state of the input field.
716    ///
717    /// Only for [`InputMode::SingleLine`] mode.
718    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    /// Set true to clear the input by pressing Escape key.
725    pub fn clean_on_escape(mut self) -> Self {
726        self.clean_on_escape = true;
727        self
728    }
729
730    /// Set the soft wrap mode for multi-line input, default is true.
731    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    /// Update the soft wrap mode for multi-line input, default is true.
738    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            // Reset scroll to left 0
751            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    /// Set the regular expression pattern of the input field.
761    ///
762    /// Only for [`InputMode::SingleLine`] mode.
763    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    /// Set the regular expression pattern of the input field with reference.
770    ///
771    /// Only for [`InputMode::SingleLine`] mode.
772    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    /// Set the validation function of the input field.
783    ///
784    /// Only for [`InputMode::SingleLine`] mode.
785    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    /// Set true to show indicator at the input right.
792    ///
793    /// Only for [`InputMode::SingleLine`] mode.
794    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    /// Set the default value of the input field.
801    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    /// Return the value of the input field.
813    pub fn value(&self) -> SharedString {
814        SharedString::new(self.text.to_string())
815    }
816
817    /// Return the value without mask.
818    pub fn unmask_value(&self) -> SharedString {
819        self.mask_pattern.unmask(&self.text.to_string()).into()
820    }
821
822    /// Return the text [`Rope`] of the input field.
823    pub fn text(&self) -> &Rope {
824        &self.text
825    }
826
827    /// Return the (0-based) [`Position`] of the cursor.
828    pub fn cursor_position(&self) -> Position {
829        let offset = self.cursor();
830        self.text.offset_to_position(offset)
831    }
832
833    /// Set (0-based) [`Position`] of the cursor.
834    ///
835    /// This will move the cursor to the specified line and column, and update the selection range.
836    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    /// Focus the input field.
851    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    /// Return the start offset of the previous word.
947    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        // FIXME: Avoid to_string
951        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    /// Return the next end offset of the next word.
961    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    /// Get start of line byte offset of cursor
973    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    /// Get end of line byte offset of cursor
983    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    /// Get start line of selection start or end (The min value).
993    ///
994    /// This is means is always get the first line of selection.
995    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    /// Get indent string of next line.
1016    ///
1017    /// To get current and next line indent, to return more depth one.
1018    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            // Get current line indent
1148            let indent = if self.mode.is_code_editor() {
1149                self.indent_of_next_line()
1150            } else {
1151                "".to_string()
1152            };
1153
1154            // Add newline and indent
1155            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            // Single line input, just emit the event (e.g.: In a modal dialog to confirm).
1160            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                // +1 for "\n", the `\r` is included in the `line`.
1232                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            // Selected none
1243            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                    // +1 for "\n"
1292                    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            // Selected none
1308            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            // FIXME: To improve performance
1312            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 there have IME marked range and is empty (Means pressed Esc to abort IME typing)
1360        // Clear the marked range.
1361        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        // Double click to select word
1375        if event.button == MouseButton::Left && event.click_count == 2 {
1376            self.select_word(offset, window, cx);
1377            return;
1378        }
1379
1380        // Show Mouse context menu
1381        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        // Show diagnostic popover on mouse move
1410        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            // 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        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    /// Get byte offset of the cursor.
1610    ///
1611    /// The offset is the UTF-8 offset.
1612    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 the text is empty, always return 0
1626        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        // TIP: About the IBeam cursor
1640        //
1641        // If cursor style is IBeam, the mouse mouse position is in the middle of the cursor (This is special in OS)
1642
1643        // The position is relative to the bounds of the text input
1644        //
1645        // bounds.origin:
1646        //
1647        // - included the input padding.
1648        // - included the scroll offset.
1649        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            // Return offset by use closest_index_for_x if is single line mode.
1672            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            // +1 for `\n`
1685            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            // When is masked, the index is char index, need convert to byte index.
1696            self.text.char_index_to_offset(index)
1697        } else {
1698            index
1699        }
1700    }
1701
1702    /// Returns a y offsetted point for the line origin.
1703    fn line_origin_with_y_offset(
1704        &self,
1705        y_offset: &mut Pixels,
1706        line: &LineItem,
1707        line_height: Pixels,
1708    ) -> Point<Pixels> {
1709        // NOTE: About line.wrap_boundaries.len()
1710        //
1711        // If only 1 line, the value is 0
1712        // If have 2 line, the value is 1
1713        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    /// Select the text from the current cursor position to the given offset.
1723    ///
1724    /// The offset is the UTF-8 offset.
1725    ///
1726    /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset.
1727    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        // Ensure keep word selected range
1741        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    /// Select the word at the given offset.
1756    ///
1757    /// The offset is the UTF-8 offset.
1758    ///
1759    /// FIXME: When click on a non-word character, the word is not selected.
1760    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    /// Unselects the currently selected text.
1812    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    /// Returns the true to let InputElement to render cursor, when Input is focused and current BlinkCursor is visible.
1861    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        // NOTE: Do not cancel select, when blur.
1880        // Because maybe user want to copy the selected text by AppMenuBar (will take focus handle).
1881
1882        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    /// Set the mask pattern for formatting the input text.
1954    ///
1955    /// The pattern can contain:
1956    /// - 9: Any digit or dot
1957    /// - A: Any letter
1958    /// - *: Any character
1959    /// - Other characters will be treated as literal mask characters
1960    ///
1961    /// Example: "(999)999-999" for phone numbers
1962    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        // Update text_wrapper wrap_width if changed.
1988        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 to disable wrapping (will use Pixels::MAX)
1992                    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    /// Replace text by [`lsp_types::Range`].
2036    ///
2037    /// See also: [`EntityInputHandler::replace_text_in_range`]
2038    #[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    /// Replace text in range in silent.
2057    ///
2058    /// This will not trigger any UI interaction, such as auto-completion.
2059    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    /// Replace text in range.
2111    ///
2112    /// - If the new text is invalid, it will not be replaced.
2113    /// - If `range_utf16` is not provided, the current selected range will be used.
2114    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            // Check if the new text is valid
2144            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    /// Mark text is the IME temporary insert on typing.
2181    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            // Cancel selection, when cancel IME input.
2225            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    /// Used to position IME candidates.
2243    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        // Ensure at same line.
2289        end_origin.y = start_origin.y;
2290
2291        Some(Bounds::from_corners(
2292            bounds.origin + line_number_origin + start_origin,
2293            // + line_height for show IME panel under the cursor line.
2294            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}