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, change::Change, element::TextElement, mask_pattern::MaskPattern,
23    mode::InputMode, number_input, text_wrapper::TextWrapper, TabSize,
24};
25use crate::actions::{SelectDown, SelectLeft, SelectRight, SelectUp};
26use crate::input::{
27    element::RIGHT_MARGIN,
28    popovers::{ContextMenu, DiagnosticPopover, HoverPopover, MouseContextMenu},
29    search::{self, SearchPanel},
30    text_wrapper::LineLayout,
31    HoverDefinition, Lsp, Position,
32};
33use crate::input::{RopeExt as _, Selection};
34use crate::{highlighter::DiagnosticSet, input::text_wrapper::LineItem};
35use crate::{history::History, scroll::ScrollbarState, Root};
36
37#[derive(Action, Clone, PartialEq, Eq, Deserialize)]
38#[action(namespace = input, no_json)]
39pub struct Enter {
40    /// Is confirm with secondary.
41    pub secondary: bool,
42}
43
44actions!(
45    input,
46    [
47        Backspace,
48        Delete,
49        DeleteToBeginningOfLine,
50        DeleteToEndOfLine,
51        DeleteToPreviousWordStart,
52        DeleteToNextWordEnd,
53        Indent,
54        Outdent,
55        IndentInline,
56        OutdentInline,
57        MoveUp,
58        MoveDown,
59        MoveLeft,
60        MoveRight,
61        MoveHome,
62        MoveEnd,
63        MovePageUp,
64        MovePageDown,
65        SelectAll,
66        SelectToStartOfLine,
67        SelectToEndOfLine,
68        SelectToStart,
69        SelectToEnd,
70        SelectToPreviousWordStart,
71        SelectToNextWordEnd,
72        ShowCharacterPalette,
73        Copy,
74        Cut,
75        Paste,
76        Undo,
77        Redo,
78        MoveToStartOfLine,
79        MoveToEndOfLine,
80        MoveToStart,
81        MoveToEnd,
82        MoveToPreviousWord,
83        MoveToNextWord,
84        Escape,
85        ToggleCodeActions,
86        Search,
87        GoToDefinition,
88    ]
89);
90
91#[derive(Clone)]
92pub enum InputEvent {
93    Change,
94    PressEnter { secondary: bool },
95    Focus,
96    Blur,
97}
98
99pub(super) const CONTEXT: &str = "Input";
100
101pub(crate) fn init(cx: &mut App) {
102    cx.bind_keys([
103        KeyBinding::new("backspace", Backspace, Some(CONTEXT)),
104        KeyBinding::new("delete", Delete, Some(CONTEXT)),
105        #[cfg(target_os = "macos")]
106        KeyBinding::new("cmd-backspace", DeleteToBeginningOfLine, Some(CONTEXT)),
107        #[cfg(target_os = "macos")]
108        KeyBinding::new("cmd-delete", DeleteToEndOfLine, Some(CONTEXT)),
109        #[cfg(target_os = "macos")]
110        KeyBinding::new("alt-backspace", DeleteToPreviousWordStart, Some(CONTEXT)),
111        #[cfg(not(target_os = "macos"))]
112        KeyBinding::new("ctrl-backspace", DeleteToPreviousWordStart, Some(CONTEXT)),
113        #[cfg(target_os = "macos")]
114        KeyBinding::new("alt-delete", DeleteToNextWordEnd, Some(CONTEXT)),
115        #[cfg(not(target_os = "macos"))]
116        KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)),
117        KeyBinding::new("enter", Enter { secondary: false }, Some(CONTEXT)),
118        KeyBinding::new("secondary-enter", Enter { secondary: true }, Some(CONTEXT)),
119        KeyBinding::new("escape", Escape, Some(CONTEXT)),
120        KeyBinding::new("up", MoveUp, Some(CONTEXT)),
121        KeyBinding::new("down", MoveDown, Some(CONTEXT)),
122        KeyBinding::new("left", MoveLeft, Some(CONTEXT)),
123        KeyBinding::new("right", MoveRight, Some(CONTEXT)),
124        KeyBinding::new("pageup", MovePageUp, Some(CONTEXT)),
125        KeyBinding::new("pagedown", MovePageDown, Some(CONTEXT)),
126        KeyBinding::new("tab", IndentInline, Some(CONTEXT)),
127        KeyBinding::new("shift-tab", OutdentInline, Some(CONTEXT)),
128        #[cfg(target_os = "macos")]
129        KeyBinding::new("cmd-]", Indent, Some(CONTEXT)),
130        #[cfg(not(target_os = "macos"))]
131        KeyBinding::new("ctrl-]", Indent, Some(CONTEXT)),
132        #[cfg(target_os = "macos")]
133        KeyBinding::new("cmd-[", Outdent, Some(CONTEXT)),
134        #[cfg(not(target_os = "macos"))]
135        KeyBinding::new("ctrl-[", Outdent, Some(CONTEXT)),
136        KeyBinding::new("shift-left", SelectLeft, Some(CONTEXT)),
137        KeyBinding::new("shift-right", SelectRight, Some(CONTEXT)),
138        KeyBinding::new("shift-up", SelectUp, Some(CONTEXT)),
139        KeyBinding::new("shift-down", SelectDown, Some(CONTEXT)),
140        KeyBinding::new("home", MoveHome, Some(CONTEXT)),
141        KeyBinding::new("end", MoveEnd, Some(CONTEXT)),
142        KeyBinding::new("shift-home", SelectToStartOfLine, Some(CONTEXT)),
143        KeyBinding::new("shift-end", SelectToEndOfLine, Some(CONTEXT)),
144        #[cfg(target_os = "macos")]
145        KeyBinding::new("ctrl-shift-a", SelectToStartOfLine, Some(CONTEXT)),
146        #[cfg(target_os = "macos")]
147        KeyBinding::new("ctrl-shift-e", SelectToEndOfLine, Some(CONTEXT)),
148        #[cfg(target_os = "macos")]
149        KeyBinding::new("shift-cmd-left", SelectToStartOfLine, Some(CONTEXT)),
150        #[cfg(target_os = "macos")]
151        KeyBinding::new("shift-cmd-right", SelectToEndOfLine, Some(CONTEXT)),
152        #[cfg(target_os = "macos")]
153        KeyBinding::new("alt-shift-left", SelectToPreviousWordStart, Some(CONTEXT)),
154        #[cfg(not(target_os = "macos"))]
155        KeyBinding::new("ctrl-shift-left", SelectToPreviousWordStart, Some(CONTEXT)),
156        #[cfg(target_os = "macos")]
157        KeyBinding::new("alt-shift-right", SelectToNextWordEnd, Some(CONTEXT)),
158        #[cfg(not(target_os = "macos"))]
159        KeyBinding::new("ctrl-shift-right", SelectToNextWordEnd, Some(CONTEXT)),
160        #[cfg(target_os = "macos")]
161        KeyBinding::new("ctrl-cmd-space", ShowCharacterPalette, Some(CONTEXT)),
162        #[cfg(target_os = "macos")]
163        KeyBinding::new("cmd-a", SelectAll, Some(CONTEXT)),
164        #[cfg(not(target_os = "macos"))]
165        KeyBinding::new("ctrl-a", SelectAll, Some(CONTEXT)),
166        #[cfg(target_os = "macos")]
167        KeyBinding::new("cmd-c", Copy, Some(CONTEXT)),
168        #[cfg(not(target_os = "macos"))]
169        KeyBinding::new("ctrl-c", Copy, Some(CONTEXT)),
170        #[cfg(target_os = "macos")]
171        KeyBinding::new("cmd-x", Cut, Some(CONTEXT)),
172        #[cfg(not(target_os = "macos"))]
173        KeyBinding::new("ctrl-x", Cut, Some(CONTEXT)),
174        #[cfg(target_os = "macos")]
175        KeyBinding::new("cmd-v", Paste, Some(CONTEXT)),
176        #[cfg(not(target_os = "macos"))]
177        KeyBinding::new("ctrl-v", Paste, Some(CONTEXT)),
178        #[cfg(target_os = "macos")]
179        KeyBinding::new("ctrl-a", MoveHome, Some(CONTEXT)),
180        #[cfg(target_os = "macos")]
181        KeyBinding::new("cmd-left", MoveHome, Some(CONTEXT)),
182        #[cfg(target_os = "macos")]
183        KeyBinding::new("ctrl-e", MoveEnd, Some(CONTEXT)),
184        #[cfg(target_os = "macos")]
185        KeyBinding::new("cmd-right", MoveEnd, Some(CONTEXT)),
186        #[cfg(target_os = "macos")]
187        KeyBinding::new("cmd-z", Undo, Some(CONTEXT)),
188        #[cfg(target_os = "macos")]
189        KeyBinding::new("cmd-shift-z", Redo, Some(CONTEXT)),
190        #[cfg(target_os = "macos")]
191        KeyBinding::new("cmd-up", MoveToStart, Some(CONTEXT)),
192        #[cfg(target_os = "macos")]
193        KeyBinding::new("cmd-down", MoveToEnd, Some(CONTEXT)),
194        #[cfg(target_os = "macos")]
195        KeyBinding::new("alt-left", MoveToPreviousWord, Some(CONTEXT)),
196        #[cfg(target_os = "macos")]
197        KeyBinding::new("alt-right", MoveToNextWord, Some(CONTEXT)),
198        #[cfg(not(target_os = "macos"))]
199        KeyBinding::new("ctrl-left", MoveToPreviousWord, Some(CONTEXT)),
200        #[cfg(not(target_os = "macos"))]
201        KeyBinding::new("ctrl-right", MoveToNextWord, Some(CONTEXT)),
202        #[cfg(target_os = "macos")]
203        KeyBinding::new("cmd-shift-up", SelectToStart, Some(CONTEXT)),
204        #[cfg(target_os = "macos")]
205        KeyBinding::new("cmd-shift-down", SelectToEnd, Some(CONTEXT)),
206        #[cfg(not(target_os = "macos"))]
207        KeyBinding::new("ctrl-z", Undo, Some(CONTEXT)),
208        #[cfg(not(target_os = "macos"))]
209        KeyBinding::new("ctrl-y", Redo, Some(CONTEXT)),
210        #[cfg(target_os = "macos")]
211        KeyBinding::new("cmd-.", ToggleCodeActions, Some(CONTEXT)),
212        #[cfg(not(target_os = "macos"))]
213        KeyBinding::new("ctrl-.", ToggleCodeActions, Some(CONTEXT)),
214        #[cfg(target_os = "macos")]
215        KeyBinding::new("cmd-f", Search, Some(CONTEXT)),
216        #[cfg(not(target_os = "macos"))]
217        KeyBinding::new("ctrl-f", Search, Some(CONTEXT)),
218    ]);
219
220    search::init(cx);
221    number_input::init(cx);
222}
223
224#[derive(Clone)]
225pub(super) struct LastLayout {
226    /// The visible range (no wrap) of lines in the viewport, the value is row (0-based) index.
227    pub(super) visible_range: Range<usize>,
228    /// The first visible line top position in scroll viewport.
229    pub(super) visible_top: Pixels,
230    /// The range of byte offset of the visible lines.
231    pub(super) visible_range_offset: Range<usize>,
232    /// The last layout lines (Only have visible lines).
233    pub(super) lines: Rc<Vec<LineLayout>>,
234    /// The line_height of text layout, this will change will InputElement painted.
235    pub(super) line_height: Pixels,
236    /// The wrap width of text layout, this will change will InputElement painted.
237    pub(super) wrap_width: Option<Pixels>,
238    /// The line number area width of text layout, if not line number, this will be 0px.
239    pub(super) line_number_width: Pixels,
240    /// The cursor position (top, left) in pixels.
241    pub(super) cursor_bounds: Option<Bounds<Pixels>>,
242}
243
244impl LastLayout {
245    /// Get the line layout for the given row (0-based).
246    ///
247    /// 0 is the viewport first visible line.
248    ///
249    /// Returns None if the row is out of range.
250    pub(crate) fn line(&self, row: usize) -> Option<&LineLayout> {
251        if row < self.visible_range.start || row >= self.visible_range.end {
252            return None;
253        }
254
255        self.lines.get(row.saturating_sub(self.visible_range.start))
256    }
257}
258
259/// InputState to keep editing state of the [`super::Input`].
260pub struct InputState {
261    pub(super) focus_handle: FocusHandle,
262    pub(super) mode: InputMode,
263    pub(super) text: Rope,
264    pub(super) text_wrapper: TextWrapper,
265    pub(super) history: History<Change>,
266    pub(super) blink_cursor: Entity<BlinkCursor>,
267    pub(super) loading: bool,
268    /// Range in UTF-8 length for the selected text.
269    ///
270    /// - "Hello δΈ–η•ŒπŸ’" = 16
271    /// - "πŸ’" = 4
272    pub(super) selected_range: Selection,
273    pub(super) search_panel: Option<Entity<SearchPanel>>,
274    pub(super) searchable: bool,
275    /// Range for save the selected word, use to keep word range when drag move.
276    pub(super) selected_word_range: Option<Selection>,
277    pub(super) selection_reversed: bool,
278    /// The marked range is the temporary insert text on IME typing.
279    pub(super) ime_marked_range: Option<Selection>,
280    pub(super) last_layout: Option<LastLayout>,
281    pub(super) last_cursor: Option<usize>,
282    /// The input container bounds
283    pub(super) input_bounds: Bounds<Pixels>,
284    /// The text bounds
285    pub(super) last_bounds: Option<Bounds<Pixels>>,
286    pub(super) last_selected_range: Option<Selection>,
287    pub(super) selecting: bool,
288    pub(super) disabled: bool,
289    pub(super) masked: bool,
290    pub(super) clean_on_escape: bool,
291    pub(super) soft_wrap: bool,
292    pub(super) pattern: Option<regex::Regex>,
293    pub(super) validate: Option<Box<dyn Fn(&str, &mut Context<Self>) -> bool + 'static>>,
294    pub(crate) scroll_handle: ScrollHandle,
295    /// The deferred scroll offset to apply on next layout.
296    pub(crate) deferred_scroll_offset: Option<Point<Pixels>>,
297    pub(super) scroll_state: ScrollbarState,
298    /// The size of the scrollable content.
299    pub(crate) scroll_size: gpui::Size<Pixels>,
300
301    /// The mask pattern for formatting the input text
302    pub(crate) mask_pattern: MaskPattern,
303    pub(super) placeholder: SharedString,
304
305    /// Popover
306    diagnostic_popover: Option<Entity<DiagnosticPopover>>,
307    /// Completion/CodeAction context menu
308    pub(super) context_menu: Option<ContextMenu>,
309    pub(super) mouse_context_menu: Entity<MouseContextMenu>,
310    /// A flag to indicate if we are currently inserting a completion item.
311    pub(super) completion_inserting: bool,
312    pub(super) hover_popover: Option<Entity<HoverPopover>>,
313    /// The LSP definitions locations for "Go to Definition" feature.
314    pub(super) hover_definition: HoverDefinition,
315
316    pub lsp: Lsp,
317
318    /// A flag to indicate if we have a pending update to the text.
319    ///
320    /// If true, will call some update (for example LSP, Syntax Highlight) before render.
321    _pending_update: bool,
322    /// A flag to indicate if we should ignore the next completion event.
323    pub(super) silent_replace_text: bool,
324
325    /// To remember the horizontal column (x-coordinate) of the cursor position for keep column for move up/down.
326    ///
327    /// The first element is the x-coordinate (Pixels), preferred to use this.
328    /// The second element is the column (usize), fallback to use this.
329    pub(super) preferred_column: Option<(Pixels, usize)>,
330    _subscriptions: Vec<Subscription>,
331
332    pub(super) _context_menu_task: Task<Result<()>>,
333}
334
335impl EventEmitter<InputEvent> for InputState {}
336
337impl InputState {
338    /// Create a Input state with default [`InputMode::SingleLine`] mode.
339    ///
340    /// See also: [`Self::multi_line`], [`Self::auto_grow`] to set other mode.
341    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
342        let focus_handle = cx.focus_handle().tab_stop(true);
343        let blink_cursor = cx.new(|_| BlinkCursor::new());
344        let history = History::new().group_interval(std::time::Duration::from_secs(1));
345
346        let _subscriptions = vec![
347            // Observe the blink cursor to repaint the view when it changes.
348            cx.observe(&blink_cursor, |_, _, cx| cx.notify()),
349            // Blink the cursor when the window is active, pause when it's not.
350            cx.observe_window_activation(window, |input, window, cx| {
351                if window.is_window_active() {
352                    let focus_handle = input.focus_handle.clone();
353                    if focus_handle.is_focused(window) {
354                        input.blink_cursor.update(cx, |blink_cursor, cx| {
355                            blink_cursor.start(cx);
356                        });
357                    }
358                }
359            }),
360            cx.on_focus(&focus_handle, window, Self::on_focus),
361            cx.on_blur(&focus_handle, window, Self::on_blur),
362        ];
363
364        let text_style = window.text_style();
365        let mouse_context_menu = MouseContextMenu::new(cx.entity(), window, cx);
366
367        Self {
368            focus_handle: focus_handle.clone(),
369            text: "".into(),
370            text_wrapper: TextWrapper::new(
371                text_style.font(),
372                text_style.font_size.to_pixels(window.rem_size()),
373                None,
374            ),
375            blink_cursor,
376            history,
377            selected_range: Selection::default(),
378            search_panel: None,
379            searchable: false,
380            selected_word_range: None,
381            selection_reversed: false,
382            ime_marked_range: None,
383            input_bounds: Bounds::default(),
384            selecting: false,
385            disabled: false,
386            masked: false,
387            clean_on_escape: false,
388            soft_wrap: true,
389            loading: false,
390            pattern: None,
391            validate: None,
392            mode: InputMode::SingleLine,
393            last_layout: None,
394            last_bounds: None,
395            last_selected_range: None,
396            last_cursor: None,
397            scroll_handle: ScrollHandle::new(),
398            scroll_state: ScrollbarState::default(),
399            scroll_size: gpui::size(px(0.), px(0.)),
400            deferred_scroll_offset: None,
401            preferred_column: None,
402            placeholder: SharedString::default(),
403            mask_pattern: MaskPattern::default(),
404            lsp: Lsp::default(),
405            diagnostic_popover: None,
406            context_menu: None,
407            mouse_context_menu,
408            completion_inserting: false,
409            hover_popover: None,
410            hover_definition: HoverDefinition::default(),
411            silent_replace_text: false,
412            _subscriptions,
413            _context_menu_task: Task::ready(Ok(())),
414            _pending_update: false,
415        }
416    }
417
418    /// Set Input to use [`InputMode::MultiLine`] mode.
419    ///
420    /// Default rows is 2.
421    pub fn multi_line(mut self) -> Self {
422        self.mode = InputMode::MultiLine {
423            rows: 2,
424            tab: TabSize::default(),
425        };
426        self
427    }
428
429    /// Set Input to use [`InputMode::AutoGrow`] mode with min, max rows limit.
430    pub fn auto_grow(mut self, min_rows: usize, max_rows: usize) -> Self {
431        self.mode = InputMode::AutoGrow {
432            rows: min_rows,
433            min_rows: min_rows,
434            max_rows: max_rows,
435        };
436        self
437    }
438
439    /// Set Input to use [`InputMode::CodeEditor`] mode.
440    ///
441    /// Default options:
442    ///
443    /// - line_number: true
444    /// - tab_size: 2
445    /// - hard_tabs: false
446    /// - height: full
447    ///
448    /// If `highlighter` is None, will use the default highlighter.
449    ///
450    /// Code Editor aim for help used to simple code editing or display, not a full-featured code editor.
451    ///
452    /// ## Features
453    ///
454    /// - Syntax Highlighting
455    /// - Auto Indent
456    /// - Line Number
457    /// - Large Text support, up to 50K lines.
458    pub fn code_editor(mut self, language: impl Into<SharedString>) -> Self {
459        let language: SharedString = language.into();
460        self.mode = InputMode::CodeEditor {
461            rows: 2,
462            tab: TabSize::default(),
463            language,
464            highlighter: Rc::new(RefCell::new(None)),
465            line_number: true,
466            indent_guides: true,
467            diagnostics: DiagnosticSet::new(&Rope::new()),
468        };
469        self.searchable = true;
470        self
471    }
472
473    /// Set this input is searchable, default is false (Default true for Code Editor).
474    pub fn searchable(mut self, searchable: bool) -> Self {
475        debug_assert!(self.mode.is_multi_line());
476        self.searchable = searchable;
477        self
478    }
479
480    /// Set placeholder
481    pub fn placeholder(mut self, placeholder: impl Into<SharedString>) -> Self {
482        self.placeholder = placeholder.into();
483        self
484    }
485
486    /// Set enable/disable line number, only for [`InputMode::CodeEditor`] mode.
487    pub fn line_number(mut self, line_number: bool) -> Self {
488        debug_assert!(self.mode.is_code_editor());
489        if let InputMode::CodeEditor { line_number: l, .. } = &mut self.mode {
490            *l = line_number;
491        }
492        self
493    }
494
495    /// Set line number, only for [`InputMode::CodeEditor`] mode.
496    pub fn set_line_number(&mut self, line_number: bool, _: &mut Window, cx: &mut Context<Self>) {
497        debug_assert!(self.mode.is_code_editor());
498        if let InputMode::CodeEditor { line_number: l, .. } = &mut self.mode {
499            *l = line_number;
500        }
501        cx.notify();
502    }
503
504    /// Set the number of rows for the multi-line Textarea.
505    ///
506    /// This is only used when `multi_line` is set to true.
507    ///
508    /// default: 2
509    pub fn rows(mut self, rows: usize) -> Self {
510        match &mut self.mode {
511            InputMode::MultiLine { rows: r, .. } => *r = rows,
512            InputMode::AutoGrow {
513                max_rows: max_r,
514                rows: r,
515                ..
516            } => {
517                *r = rows;
518                *max_r = rows;
519            }
520            _ => {}
521        }
522        self
523    }
524
525    /// Set highlighter language for for [`InputMode::CodeEditor`] mode.
526    pub fn set_highlighter(
527        &mut self,
528        new_language: impl Into<SharedString>,
529        cx: &mut Context<Self>,
530    ) {
531        match &mut self.mode {
532            InputMode::CodeEditor {
533                language,
534                highlighter,
535                ..
536            } => {
537                *language = new_language.into();
538                *highlighter.borrow_mut() = None;
539            }
540            _ => {}
541        }
542        cx.notify();
543    }
544
545    fn reset_highlighter(&mut self, cx: &mut Context<Self>) {
546        match &mut self.mode {
547            InputMode::CodeEditor { highlighter, .. } => {
548                *highlighter.borrow_mut() = None;
549            }
550            _ => {}
551        }
552        cx.notify();
553    }
554
555    #[inline]
556    pub fn diagnostics(&self) -> Option<&DiagnosticSet> {
557        self.mode.diagnostics()
558    }
559
560    #[inline]
561    pub fn diagnostics_mut(&mut self) -> Option<&mut DiagnosticSet> {
562        self.mode.diagnostics_mut()
563    }
564
565    /// Set placeholder
566    pub fn set_placeholder(
567        &mut self,
568        placeholder: impl Into<SharedString>,
569        _: &mut Window,
570        cx: &mut Context<Self>,
571    ) {
572        self.placeholder = placeholder.into();
573        cx.notify();
574    }
575
576    /// Find which line and sub-line the given offset belongs to, along with the position within that sub-line.
577    ///
578    /// Returns:
579    ///
580    /// - The index of the line (zero-based) containing the offset.
581    /// - The index of the sub-line (zero-based) within the line containing the offset.
582    /// - The position of the offset.
583    #[allow(unused)]
584    pub(super) fn line_and_position_for_offset(
585        &self,
586        offset: usize,
587    ) -> (usize, usize, Option<Point<Pixels>>) {
588        let Some(last_layout) = &self.last_layout else {
589            return (0, 0, None);
590        };
591        let line_height = last_layout.line_height;
592
593        let mut prev_lines_offset = last_layout.visible_range_offset.start;
594        let mut y_offset = last_layout.visible_top;
595        for (line_index, line) in last_layout.lines.iter().enumerate() {
596            let local_offset = offset.saturating_sub(prev_lines_offset);
597            if let Some(pos) = line.position_for_index(local_offset, line_height) {
598                let sub_line_index = (pos.y / line_height) as usize;
599                let adjusted_pos = point(pos.x + last_layout.line_number_width, pos.y + y_offset);
600                return (line_index, sub_line_index, Some(adjusted_pos));
601            }
602
603            y_offset += line.size(line_height).height;
604            prev_lines_offset += line.len() + 1;
605        }
606        (0, 0, None)
607    }
608
609    /// Set the text of the input field.
610    ///
611    /// And the selection_range will be reset to 0..0.
612    pub fn set_value(
613        &mut self,
614        value: impl Into<SharedString>,
615        window: &mut Window,
616        cx: &mut Context<Self>,
617    ) {
618        self.history.ignore = true;
619        let was_disabled = self.disabled;
620        self.disabled = false;
621        self.replace_text(value, window, cx);
622        self.disabled = was_disabled;
623        self.history.ignore = false;
624        // Ensure cursor to start when set text
625        if self.mode.is_single_line() {
626            self.selected_range = (self.text.len()..self.text.len()).into();
627        } else {
628            self.selected_range.clear();
629
630            self._pending_update = true;
631            self.lsp.reset();
632        }
633        // Move scroll to top
634        self.scroll_handle.set_offset(point(px(0.), px(0.)));
635
636        cx.notify();
637    }
638
639    /// Insert text at the current cursor position.
640    ///
641    /// And the cursor will be moved to the end of inserted text.
642    pub fn insert(
643        &mut self,
644        text: impl Into<SharedString>,
645        window: &mut Window,
646        cx: &mut Context<Self>,
647    ) {
648        let text: SharedString = text.into();
649        let range_utf16 = self.range_to_utf16(&(self.cursor()..self.cursor()));
650        self.replace_text_in_range_silent(Some(range_utf16), &text, window, cx);
651        self.selected_range = (self.selected_range.end..self.selected_range.end).into();
652    }
653
654    /// Replace text at the current cursor position.
655    ///
656    /// And the cursor will be moved to the end of replaced text.
657    pub fn replace(
658        &mut self,
659        text: impl Into<SharedString>,
660        window: &mut Window,
661        cx: &mut Context<Self>,
662    ) {
663        let text: SharedString = text.into();
664        self.replace_text_in_range_silent(None, &text, window, cx);
665        self.selected_range = (self.selected_range.end..self.selected_range.end).into();
666    }
667
668    fn replace_text(
669        &mut self,
670        text: impl Into<SharedString>,
671        window: &mut Window,
672        cx: &mut Context<Self>,
673    ) {
674        let text: SharedString = text.into();
675        let range = 0..self.text.chars().map(|c| c.len_utf16()).sum();
676        self.replace_text_in_range_silent(Some(range), &text, window, cx);
677        self.reset_highlighter(cx);
678    }
679
680    /// Set with disabled mode.
681    ///
682    /// See also: [`Self::set_disabled`], [`Self::is_disabled`].
683    #[allow(unused)]
684    pub(crate) fn disabled(mut self, disabled: bool) -> Self {
685        self.disabled = disabled;
686        self
687    }
688
689    /// Set with password masked state.
690    ///
691    /// Only for [`InputMode::SingleLine`] mode.
692    pub fn masked(mut self, masked: bool) -> Self {
693        debug_assert!(self.mode.is_single_line());
694        self.masked = masked;
695        self
696    }
697
698    /// Set the password masked state of the input field.
699    ///
700    /// Only for [`InputMode::SingleLine`] mode.
701    pub fn set_masked(&mut self, masked: bool, _: &mut Window, cx: &mut Context<Self>) {
702        debug_assert!(self.mode.is_single_line());
703        self.masked = masked;
704        cx.notify();
705    }
706
707    /// Set true to clear the input by pressing Escape key.
708    pub fn clean_on_escape(mut self) -> Self {
709        self.clean_on_escape = true;
710        self
711    }
712
713    /// Set the soft wrap mode for multi-line input, default is true.
714    pub fn soft_wrap(mut self, wrap: bool) -> Self {
715        debug_assert!(self.mode.is_multi_line());
716        self.soft_wrap = wrap;
717        self
718    }
719
720    /// Update the soft wrap mode for multi-line input, default is true.
721    pub fn set_soft_wrap(&mut self, wrap: bool, _: &mut Window, cx: &mut Context<Self>) {
722        debug_assert!(self.mode.is_multi_line());
723        self.soft_wrap = wrap;
724        if wrap {
725            let wrap_width = self
726                .last_layout
727                .as_ref()
728                .and_then(|b| b.wrap_width)
729                .unwrap_or(self.input_bounds.size.width);
730
731            self.text_wrapper.set_wrap_width(Some(wrap_width), cx);
732
733            // Reset scroll to left 0
734            let mut offset = self.scroll_handle.offset();
735            offset.x = px(0.);
736            self.scroll_handle.set_offset(offset);
737        } else {
738            self.text_wrapper.set_wrap_width(None, cx);
739        }
740        cx.notify();
741    }
742
743    /// Set the regular expression pattern of the input field.
744    ///
745    /// Only for [`InputMode::SingleLine`] mode.
746    pub fn pattern(mut self, pattern: regex::Regex) -> Self {
747        debug_assert!(self.mode.is_single_line());
748        self.pattern = Some(pattern);
749        self
750    }
751
752    /// Set the regular expression pattern of the input field with reference.
753    ///
754    /// Only for [`InputMode::SingleLine`] mode.
755    pub fn set_pattern(
756        &mut self,
757        pattern: regex::Regex,
758        _window: &mut Window,
759        _cx: &mut Context<Self>,
760    ) {
761        debug_assert!(self.mode.is_single_line());
762        self.pattern = Some(pattern);
763    }
764
765    /// Set the validation function of the input field.
766    ///
767    /// Only for [`InputMode::SingleLine`] mode.
768    pub fn validate(mut self, f: impl Fn(&str, &mut Context<Self>) -> bool + 'static) -> Self {
769        debug_assert!(self.mode.is_single_line());
770        self.validate = Some(Box::new(f));
771        self
772    }
773
774    /// Set true to show spinner at the input right.
775    ///
776    /// Only for [`InputMode::SingleLine`] mode.
777    pub fn set_loading(&mut self, loading: bool, _: &mut Window, cx: &mut Context<Self>) {
778        debug_assert!(self.mode.is_single_line());
779        self.loading = loading;
780        cx.notify();
781    }
782
783    /// Set the default value of the input field.
784    pub fn default_value(mut self, value: impl Into<SharedString>) -> Self {
785        let text: SharedString = value.into();
786        self.text = Rope::from(text.as_str());
787        if let Some(diagnostics) = self.mode.diagnostics_mut() {
788            diagnostics.reset(&self.text)
789        }
790        self.text_wrapper.set_default_text(&self.text);
791        self._pending_update = true;
792        self
793    }
794
795    /// Return the value of the input field.
796    pub fn value(&self) -> SharedString {
797        SharedString::new(self.text.to_string())
798    }
799
800    /// Return the value without mask.
801    pub fn unmask_value(&self) -> SharedString {
802        self.mask_pattern.unmask(&self.text.to_string()).into()
803    }
804
805    /// Return the text [`Rope`] of the input field.
806    pub fn text(&self) -> &Rope {
807        &self.text
808    }
809
810    /// Return the (0-based) [`Position`] of the cursor.
811    pub fn cursor_position(&self) -> Position {
812        let offset = self.cursor();
813        self.text.offset_to_position(offset)
814    }
815
816    /// Set (0-based) [`Position`] of the cursor.
817    ///
818    /// This will move the cursor to the specified line and column, and update the selection range.
819    pub fn set_cursor_position(
820        &mut self,
821        position: impl Into<Position>,
822        window: &mut Window,
823        cx: &mut Context<Self>,
824    ) {
825        let position: Position = position.into();
826        let offset = self.text.position_to_offset(&position);
827
828        self.move_to(offset, cx);
829        self.update_preferred_column();
830        self.focus(window, cx);
831    }
832
833    /// Focus the input field.
834    pub fn focus(&self, window: &mut Window, cx: &mut Context<Self>) {
835        self.focus_handle.focus(window);
836        self.blink_cursor.update(cx, |cursor, cx| {
837            cursor.start(cx);
838        });
839    }
840
841    pub(super) fn select_left(&mut self, _: &SelectLeft, _: &mut Window, cx: &mut Context<Self>) {
842        self.select_to(self.previous_boundary(self.cursor()), cx);
843    }
844
845    pub(super) fn select_right(&mut self, _: &SelectRight, _: &mut Window, cx: &mut Context<Self>) {
846        self.select_to(self.next_boundary(self.cursor()), cx);
847    }
848
849    pub(super) fn select_up(&mut self, _: &SelectUp, _: &mut Window, cx: &mut Context<Self>) {
850        if self.mode.is_single_line() {
851            return;
852        }
853        let offset = self.start_of_line().saturating_sub(1);
854        self.select_to(self.previous_boundary(offset), cx);
855    }
856
857    pub(super) fn select_down(&mut self, _: &SelectDown, _: &mut Window, cx: &mut Context<Self>) {
858        if self.mode.is_single_line() {
859            return;
860        }
861        let offset = (self.end_of_line() + 1).min(self.text.len());
862        self.select_to(self.next_boundary(offset), cx);
863    }
864
865    pub(super) fn select_all(&mut self, _: &SelectAll, _: &mut Window, cx: &mut Context<Self>) {
866        self.selected_range = (0..self.text.len()).into();
867        cx.notify();
868    }
869
870    pub(super) fn select_to_start(
871        &mut self,
872        _: &SelectToStart,
873        _: &mut Window,
874        cx: &mut Context<Self>,
875    ) {
876        self.select_to(0, cx);
877    }
878
879    pub(super) fn select_to_end(
880        &mut self,
881        _: &SelectToEnd,
882        _: &mut Window,
883        cx: &mut Context<Self>,
884    ) {
885        let end = self.text.len();
886        self.select_to(end, cx);
887    }
888
889    pub(super) fn select_to_start_of_line(
890        &mut self,
891        _: &SelectToStartOfLine,
892        _: &mut Window,
893        cx: &mut Context<Self>,
894    ) {
895        let offset = self.start_of_line();
896        self.select_to(offset, cx);
897    }
898
899    pub(super) fn select_to_end_of_line(
900        &mut self,
901        _: &SelectToEndOfLine,
902        _: &mut Window,
903        cx: &mut Context<Self>,
904    ) {
905        let offset = self.end_of_line();
906        self.select_to(offset, cx);
907    }
908
909    pub(super) fn select_to_previous_word(
910        &mut self,
911        _: &SelectToPreviousWordStart,
912        _: &mut Window,
913        cx: &mut Context<Self>,
914    ) {
915        let offset = self.previous_start_of_word();
916        self.select_to(offset, cx);
917    }
918
919    pub(super) fn select_to_next_word(
920        &mut self,
921        _: &SelectToNextWordEnd,
922        _: &mut Window,
923        cx: &mut Context<Self>,
924    ) {
925        let offset = self.next_end_of_word();
926        self.select_to(offset, cx);
927    }
928
929    /// Return the start offset of the previous word.
930    pub(super) fn previous_start_of_word(&mut self) -> usize {
931        let offset = self.selected_range.start;
932        let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
933        // FIXME: Avoid to_string
934        let left_part = self.text.slice(0..offset).to_string();
935
936        UnicodeSegmentation::split_word_bound_indices(left_part.as_str())
937            .filter(|(_, s)| !s.trim_start().is_empty())
938            .next_back()
939            .map(|(i, _)| i)
940            .unwrap_or(0)
941    }
942
943    /// Return the next end offset of the next word.
944    pub(super) fn next_end_of_word(&mut self) -> usize {
945        let offset = self.cursor();
946        let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
947        let right_part = self.text.slice(offset..self.text.len()).to_string();
948
949        UnicodeSegmentation::split_word_bound_indices(right_part.as_str())
950            .find(|(_, s)| !s.trim_start().is_empty())
951            .map(|(i, s)| offset + i + s.len())
952            .unwrap_or(self.text.len())
953    }
954
955    /// Get start of line byte offset of cursor
956    pub(super) fn start_of_line(&self) -> usize {
957        if self.mode.is_single_line() {
958            return 0;
959        }
960
961        let row = self.text.offset_to_point(self.cursor()).row;
962        self.text.line_start_offset(row)
963    }
964
965    /// Get end of line byte offset of cursor
966    pub(super) fn end_of_line(&self) -> usize {
967        if self.mode.is_single_line() {
968            return self.text.len();
969        }
970
971        let row = self.text.offset_to_point(self.cursor()).row;
972        self.text.line_end_offset(row)
973    }
974
975    /// Get start line of selection start or end (The min value).
976    ///
977    /// This is means is always get the first line of selection.
978    pub(super) fn start_of_line_of_selection(
979        &mut self,
980        window: &mut Window,
981        cx: &mut Context<Self>,
982    ) -> usize {
983        if self.mode.is_single_line() {
984            return 0;
985        }
986
987        let mut offset =
988            self.previous_boundary(self.selected_range.start.min(self.selected_range.end));
989        if self.text.char_at(offset) == Some('\r') {
990            offset += 1;
991        }
992
993        let line = self
994            .text_for_range(self.range_to_utf16(&(0..offset + 1)), &mut None, window, cx)
995            .unwrap_or_default()
996            .rfind('\n')
997            .map(|i| i + 1)
998            .unwrap_or(0);
999        line
1000    }
1001
1002    /// Get indent string of next line.
1003    ///
1004    /// To get current and next line indent, to return more depth one.
1005    pub(super) fn indent_of_next_line(&mut self) -> String {
1006        if self.mode.is_single_line() {
1007            return "".into();
1008        }
1009
1010        let mut current_indent = String::new();
1011        let mut next_indent = String::new();
1012        let current_line_start_pos = self.start_of_line();
1013        let next_line_start_pos = self.end_of_line();
1014        for c in self.text.slice(current_line_start_pos..).chars() {
1015            if !c.is_whitespace() {
1016                break;
1017            }
1018            if c == '\n' || c == '\r' {
1019                break;
1020            }
1021            current_indent.push(c);
1022        }
1023
1024        for c in self.text.slice(next_line_start_pos..).chars() {
1025            if !c.is_whitespace() {
1026                break;
1027            }
1028            if c == '\n' || c == '\r' {
1029                break;
1030            }
1031            next_indent.push(c);
1032        }
1033
1034        if next_indent.len() > current_indent.len() {
1035            return next_indent;
1036        } else {
1037            return current_indent;
1038        }
1039    }
1040
1041    pub(super) fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
1042        if self.selected_range.is_empty() {
1043            self.select_to(self.previous_boundary(self.cursor()), cx)
1044        }
1045        self.replace_text_in_range(None, "", window, cx);
1046        self.pause_blink_cursor(cx);
1047    }
1048
1049    pub(super) fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
1050        if self.selected_range.is_empty() {
1051            self.select_to(self.next_boundary(self.cursor()), cx)
1052        }
1053        self.replace_text_in_range(None, "", window, cx);
1054        self.pause_blink_cursor(cx);
1055    }
1056
1057    pub(super) fn delete_to_beginning_of_line(
1058        &mut self,
1059        _: &DeleteToBeginningOfLine,
1060        window: &mut Window,
1061        cx: &mut Context<Self>,
1062    ) {
1063        if !self.selected_range.is_empty() {
1064            self.replace_text_in_range(None, "", window, cx);
1065            self.pause_blink_cursor(cx);
1066            return;
1067        }
1068
1069        let mut offset = self.start_of_line();
1070        if offset == self.cursor() {
1071            offset = offset.saturating_sub(1);
1072        }
1073        self.replace_text_in_range_silent(
1074            Some(self.range_to_utf16(&(offset..self.cursor()))),
1075            "",
1076            window,
1077            cx,
1078        );
1079        self.pause_blink_cursor(cx);
1080    }
1081
1082    pub(super) fn delete_to_end_of_line(
1083        &mut self,
1084        _: &DeleteToEndOfLine,
1085        window: &mut Window,
1086        cx: &mut Context<Self>,
1087    ) {
1088        if !self.selected_range.is_empty() {
1089            self.replace_text_in_range(None, "", window, cx);
1090            self.pause_blink_cursor(cx);
1091            return;
1092        }
1093
1094        let mut offset = self.end_of_line();
1095        if offset == self.cursor() {
1096            offset = (offset + 1).clamp(0, self.text.len());
1097        }
1098        self.replace_text_in_range_silent(
1099            Some(self.range_to_utf16(&(self.cursor()..offset))),
1100            "",
1101            window,
1102            cx,
1103        );
1104        self.pause_blink_cursor(cx);
1105    }
1106
1107    pub(super) fn delete_previous_word(
1108        &mut self,
1109        _: &DeleteToPreviousWordStart,
1110        window: &mut Window,
1111        cx: &mut Context<Self>,
1112    ) {
1113        if !self.selected_range.is_empty() {
1114            self.replace_text_in_range(None, "", window, cx);
1115            self.pause_blink_cursor(cx);
1116            return;
1117        }
1118
1119        let offset = self.previous_start_of_word();
1120        self.replace_text_in_range_silent(
1121            Some(self.range_to_utf16(&(offset..self.cursor()))),
1122            "",
1123            window,
1124            cx,
1125        );
1126        self.pause_blink_cursor(cx);
1127    }
1128
1129    pub(super) fn delete_next_word(
1130        &mut self,
1131        _: &DeleteToNextWordEnd,
1132        window: &mut Window,
1133        cx: &mut Context<Self>,
1134    ) {
1135        if !self.selected_range.is_empty() {
1136            self.replace_text_in_range(None, "", window, cx);
1137            self.pause_blink_cursor(cx);
1138            return;
1139        }
1140
1141        let offset = self.next_end_of_word();
1142        self.replace_text_in_range_silent(
1143            Some(self.range_to_utf16(&(self.cursor()..offset))),
1144            "",
1145            window,
1146            cx,
1147        );
1148        self.pause_blink_cursor(cx);
1149    }
1150
1151    pub(super) fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) {
1152        if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1153            return;
1154        }
1155
1156        if self.mode.is_multi_line() {
1157            // Get current line indent
1158            let indent = if self.mode.is_code_editor() {
1159                self.indent_of_next_line()
1160            } else {
1161                "".to_string()
1162            };
1163
1164            // Add newline and indent
1165            let new_line_text = format!("\n{}", indent);
1166            self.replace_text_in_range_silent(None, &new_line_text, window, cx);
1167            self.pause_blink_cursor(cx);
1168        } else {
1169            // Single line input, just emit the event (e.g.: In a dialog to confirm).
1170            cx.propagate();
1171        }
1172
1173        cx.emit(InputEvent::PressEnter {
1174            secondary: action.secondary,
1175        });
1176    }
1177
1178    pub(super) fn clean(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1179        self.replace_text("", window, cx);
1180        self.selected_range = (0..0).into();
1181        self.scroll_to(0, cx);
1182    }
1183
1184    pub(super) fn escape(&mut self, action: &Escape, window: &mut Window, cx: &mut Context<Self>) {
1185        if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1186            return;
1187        }
1188
1189        if self.ime_marked_range.is_some() {
1190            self.unmark_text(window, cx);
1191        }
1192
1193        if self.clean_on_escape {
1194            return self.clean(window, cx);
1195        }
1196
1197        cx.propagate();
1198    }
1199
1200    pub(super) fn on_mouse_down(
1201        &mut self,
1202        event: &MouseDownEvent,
1203        window: &mut Window,
1204        cx: &mut Context<Self>,
1205    ) {
1206        // If there have IME marked range and is empty (Means pressed Esc to abort IME typing)
1207        // Clear the marked range.
1208        if let Some(ime_marked_range) = &self.ime_marked_range {
1209            if ime_marked_range.len() == 0 {
1210                self.ime_marked_range = None;
1211            }
1212        }
1213
1214        self.selecting = true;
1215        let offset = self.index_for_mouse_position(event.position);
1216
1217        if self.handle_click_hover_definition(event, offset, window, cx) {
1218            return;
1219        }
1220
1221        // Double click to select word
1222        if event.button == MouseButton::Left && event.click_count == 2 {
1223            self.select_word(offset, window, cx);
1224            return;
1225        }
1226
1227        // Show Mouse context menu
1228        if event.button == MouseButton::Right {
1229            self.handle_right_click_menu(event, offset, window, cx);
1230            return;
1231        }
1232
1233        if event.modifiers.shift {
1234            self.select_to(offset, cx);
1235        } else {
1236            self.move_to(offset, cx)
1237        }
1238    }
1239
1240    pub(super) fn on_mouse_up(
1241        &mut self,
1242        _: &MouseUpEvent,
1243        _window: &mut Window,
1244        _cx: &mut Context<Self>,
1245    ) {
1246        self.selecting = false;
1247        self.selected_word_range = None;
1248    }
1249
1250    pub(super) fn on_mouse_move(
1251        &mut self,
1252        event: &MouseMoveEvent,
1253        window: &mut Window,
1254        cx: &mut Context<Self>,
1255    ) {
1256        // Show diagnostic popover on mouse move
1257        let offset = self.index_for_mouse_position(event.position);
1258        self.handle_mouse_move(offset, event, window, cx);
1259
1260        if self.mode.is_code_editor() {
1261            if let Some(diagnostic) = self
1262                .mode
1263                .diagnostics()
1264                .and_then(|set| set.for_offset(offset))
1265            {
1266                if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
1267                    if diagnostic_popover.read(cx).diagnostic.range == diagnostic.range {
1268                        diagnostic_popover.update(cx, |this, cx| {
1269                            this.show(cx);
1270                        });
1271
1272                        return;
1273                    }
1274                }
1275
1276                self.diagnostic_popover = Some(DiagnosticPopover::new(diagnostic, cx.entity(), cx));
1277                cx.notify();
1278            } else {
1279                if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
1280                    diagnostic_popover.update(cx, |this, cx| {
1281                        this.check_to_hide(event.position, cx);
1282                    })
1283                }
1284            }
1285        }
1286    }
1287
1288    pub(super) fn on_scroll_wheel(
1289        &mut self,
1290        event: &ScrollWheelEvent,
1291        window: &mut Window,
1292        cx: &mut Context<Self>,
1293    ) {
1294        let line_height = self
1295            .last_layout
1296            .as_ref()
1297            .map(|layout| layout.line_height)
1298            .unwrap_or(window.line_height());
1299        let delta = event.delta.pixel_delta(line_height);
1300
1301        let old_offset = self.scroll_handle.offset();
1302        self.update_scroll_offset(Some(old_offset + delta), cx);
1303
1304        // Only stop propagation if the offset actually changed
1305        if self.scroll_handle.offset() != old_offset {
1306            cx.stop_propagation();
1307        }
1308
1309        self.diagnostic_popover = None;
1310    }
1311
1312    pub(super) fn update_scroll_offset(
1313        &mut self,
1314        offset: Option<Point<Pixels>>,
1315        cx: &mut Context<Self>,
1316    ) {
1317        let mut offset = offset.unwrap_or(self.scroll_handle.offset());
1318
1319        let safe_y_range =
1320            (-self.scroll_size.height + self.input_bounds.size.height).min(px(0.0))..px(0.);
1321        let safe_x_range =
1322            (-self.scroll_size.width + self.input_bounds.size.width).min(px(0.0))..px(0.);
1323
1324        offset.y = if self.mode.is_single_line() {
1325            px(0.)
1326        } else {
1327            offset.y.clamp(safe_y_range.start, safe_y_range.end)
1328        };
1329        offset.x = offset.x.clamp(safe_x_range.start, safe_x_range.end);
1330        self.scroll_handle.set_offset(offset);
1331        cx.notify();
1332    }
1333
1334    pub(crate) fn scroll_to(&mut self, offset: usize, cx: &mut Context<Self>) {
1335        let Some(last_layout) = self.last_layout.as_ref() else {
1336            return;
1337        };
1338        let Some(bounds) = self.last_bounds.as_ref() else {
1339            return;
1340        };
1341
1342        let mut scroll_offset = self.scroll_handle.offset();
1343        let line_height = last_layout.line_height;
1344
1345        let point = self.text.offset_to_point(offset);
1346        let row = point.row;
1347
1348        let mut row_offset_y = px(0.);
1349        for (ix, wrap_line) in self.text_wrapper.lines.iter().enumerate() {
1350            if ix == row {
1351                break;
1352            }
1353
1354            row_offset_y += wrap_line.height(line_height);
1355        }
1356
1357        if let Some(line) = last_layout
1358            .lines
1359            .get(row.saturating_sub(last_layout.visible_range.start))
1360        {
1361            // Check to scroll horizontally
1362            if let Some(pos) = line.position_for_index(point.column, line_height) {
1363                let bounds_width = bounds.size.width - last_layout.line_number_width;
1364                let col_offset_x = pos.x;
1365                if col_offset_x - RIGHT_MARGIN < -scroll_offset.x {
1366                    // If the position is out of the visible area, scroll to make it visible
1367                    scroll_offset.x = -col_offset_x + RIGHT_MARGIN;
1368                } else if col_offset_x + RIGHT_MARGIN > -scroll_offset.x + bounds_width {
1369                    scroll_offset.x = -(col_offset_x - bounds_width + RIGHT_MARGIN);
1370                }
1371            }
1372        }
1373
1374        // Check if row_offset_y is out of the viewport
1375        // If row offset is not in the viewport, scroll to make it visible
1376        let edge_height = if self.mode.is_code_editor() {
1377            3 * line_height
1378        } else {
1379            line_height
1380        };
1381        if row_offset_y - edge_height < -scroll_offset.y {
1382            // Scroll up
1383            scroll_offset.y = -row_offset_y + edge_height;
1384        } else if row_offset_y + edge_height > -scroll_offset.y + bounds.size.height {
1385            // Scroll down
1386            scroll_offset.y = -(row_offset_y - bounds.size.height + edge_height);
1387        }
1388
1389        scroll_offset.x = scroll_offset.x.min(px(0.));
1390        scroll_offset.y = scroll_offset.y.min(px(0.));
1391        self.deferred_scroll_offset = Some(scroll_offset);
1392        cx.notify();
1393    }
1394
1395    pub(super) fn show_character_palette(
1396        &mut self,
1397        _: &ShowCharacterPalette,
1398        window: &mut Window,
1399        _: &mut Context<Self>,
1400    ) {
1401        window.show_character_palette();
1402    }
1403
1404    pub(super) fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
1405        if self.selected_range.is_empty() {
1406            return;
1407        }
1408
1409        let selected_text = self.text.slice(self.selected_range).to_string();
1410        cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1411    }
1412
1413    pub(super) fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
1414        if self.selected_range.is_empty() {
1415            return;
1416        }
1417
1418        let selected_text = self.text.slice(self.selected_range).to_string();
1419        cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1420
1421        self.replace_text_in_range_silent(None, "", window, cx);
1422    }
1423
1424    pub(super) fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
1425        if let Some(clipboard) = cx.read_from_clipboard() {
1426            let mut new_text = clipboard.text().unwrap_or_default();
1427            if !self.mode.is_multi_line() {
1428                new_text = new_text.replace('\n', "");
1429            }
1430
1431            self.replace_text_in_range_silent(None, &new_text, window, cx);
1432            self.scroll_to(self.cursor(), cx);
1433        }
1434    }
1435
1436    fn push_history(&mut self, text: &Rope, range: &Range<usize>, new_text: &str) {
1437        if self.history.ignore {
1438            return;
1439        }
1440
1441        let old_text = text.slice(range.clone()).to_string();
1442        let new_range = range.start..range.start + new_text.len();
1443
1444        self.history
1445            .push(Change::new(range.clone(), &old_text, new_range, new_text));
1446    }
1447
1448    pub(super) fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
1449        self.history.ignore = true;
1450        if let Some(changes) = self.history.undo() {
1451            for change in changes {
1452                let range_utf16 = self.range_to_utf16(&change.new_range.into());
1453                self.replace_text_in_range_silent(Some(range_utf16), &change.old_text, window, cx);
1454            }
1455        }
1456        self.history.ignore = false;
1457    }
1458
1459    pub(super) fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
1460        self.history.ignore = true;
1461        if let Some(changes) = self.history.redo() {
1462            for change in changes {
1463                let range_utf16 = self.range_to_utf16(&change.old_range.into());
1464                self.replace_text_in_range_silent(Some(range_utf16), &change.new_text, window, cx);
1465            }
1466        }
1467        self.history.ignore = false;
1468    }
1469
1470    /// Get byte offset of the cursor.
1471    ///
1472    /// The offset is the UTF-8 offset.
1473    pub fn cursor(&self) -> usize {
1474        if let Some(ime_marked_range) = &self.ime_marked_range {
1475            return ime_marked_range.end;
1476        }
1477
1478        if self.selection_reversed {
1479            self.selected_range.start
1480        } else {
1481            self.selected_range.end
1482        }
1483    }
1484
1485    pub(crate) fn index_for_mouse_position(&self, position: Point<Pixels>) -> usize {
1486        // If the text is empty, always return 0
1487        if self.text.len() == 0 {
1488            return 0;
1489        }
1490
1491        let (Some(bounds), Some(last_layout)) =
1492            (self.last_bounds.as_ref(), self.last_layout.as_ref())
1493        else {
1494            return 0;
1495        };
1496
1497        let line_height = last_layout.line_height;
1498        let line_number_width = last_layout.line_number_width;
1499
1500        // TIP: About the IBeam cursor
1501        //
1502        // If cursor style is IBeam, the mouse mouse position is in the middle of the cursor (This is special in OS)
1503
1504        // The position is relative to the bounds of the text input
1505        //
1506        // bounds.origin:
1507        //
1508        // - included the input padding.
1509        // - included the scroll offset.
1510        let inner_position = position - bounds.origin - point(line_number_width, px(0.));
1511
1512        let mut index = last_layout.visible_range_offset.start;
1513        let mut y_offset = last_layout.visible_top;
1514        for (ix, line) in self
1515            .text_wrapper
1516            .lines
1517            .iter()
1518            .skip(last_layout.visible_range.start)
1519            .enumerate()
1520        {
1521            let line_origin = self.line_origin_with_y_offset(&mut y_offset, line, line_height);
1522            let pos = inner_position - line_origin;
1523
1524            let Some(line_layout) = last_layout.lines.get(ix) else {
1525                if pos.y < line_origin.y + line_height {
1526                    break;
1527                }
1528
1529                continue;
1530            };
1531
1532            // Return offset by use closest_index_for_x if is single line mode.
1533            if self.mode.is_single_line() {
1534                index = line_layout.closest_index_for_x(pos.x);
1535                break;
1536            }
1537
1538            if let Some(v) = line_layout.closest_index_for_position(pos, line_height) {
1539                index += v;
1540                break;
1541            } else if pos.y < px(0.) {
1542                break;
1543            }
1544
1545            // +1 for `\n`
1546            index += line_layout.len() + 1;
1547        }
1548
1549        let index = if index > self.text.len() {
1550            self.text.len()
1551        } else {
1552            index
1553        };
1554
1555        if self.masked {
1556            // When is masked, the index is char index, need convert to byte index.
1557            self.text.char_index_to_offset(index)
1558        } else {
1559            index
1560        }
1561    }
1562
1563    /// Returns a y offsetted point for the line origin.
1564    fn line_origin_with_y_offset(
1565        &self,
1566        y_offset: &mut Pixels,
1567        line: &LineItem,
1568        line_height: Pixels,
1569    ) -> Point<Pixels> {
1570        // NOTE: About line.wrap_boundaries.len()
1571        //
1572        // If only 1 line, the value is 0
1573        // If have 2 line, the value is 1
1574        if self.mode.is_multi_line() {
1575            let p = point(px(0.), *y_offset);
1576            *y_offset += line.height(line_height);
1577            p
1578        } else {
1579            point(px(0.), px(0.))
1580        }
1581    }
1582
1583    /// Select the text from the current cursor position to the given offset.
1584    ///
1585    /// The offset is the UTF-8 offset.
1586    ///
1587    /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset.
1588    pub(crate) fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
1589        let offset = offset.clamp(0, self.text.len());
1590        if self.selection_reversed {
1591            self.selected_range.start = offset
1592        } else {
1593            self.selected_range.end = offset
1594        };
1595
1596        if self.selected_range.end < self.selected_range.start {
1597            self.selection_reversed = !self.selection_reversed;
1598            self.selected_range = (self.selected_range.end..self.selected_range.start).into();
1599        }
1600
1601        // Ensure keep word selected range
1602        if let Some(word_range) = self.selected_word_range.as_ref() {
1603            if self.selected_range.start > word_range.start {
1604                self.selected_range.start = word_range.start;
1605            }
1606            if self.selected_range.end < word_range.end {
1607                self.selected_range.end = word_range.end;
1608            }
1609        }
1610        if self.selected_range.is_empty() {
1611            self.update_preferred_column();
1612        }
1613        cx.notify()
1614    }
1615
1616    /// Unselects the currently selected text.
1617    pub fn unselect(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1618        let offset = self.cursor();
1619        self.selected_range = (offset..offset).into();
1620        cx.notify()
1621    }
1622
1623    #[inline]
1624    pub(super) fn offset_from_utf16(&self, offset: usize) -> usize {
1625        self.text.offset_utf16_to_offset(offset)
1626    }
1627
1628    #[inline]
1629    pub(super) fn offset_to_utf16(&self, offset: usize) -> usize {
1630        self.text.offset_to_offset_utf16(offset)
1631    }
1632
1633    #[inline]
1634    pub(super) fn range_to_utf16(&self, range: &Range<usize>) -> Range<usize> {
1635        self.offset_to_utf16(range.start)..self.offset_to_utf16(range.end)
1636    }
1637
1638    #[inline]
1639    pub(super) fn range_from_utf16(&self, range_utf16: &Range<usize>) -> Range<usize> {
1640        self.offset_from_utf16(range_utf16.start)..self.offset_from_utf16(range_utf16.end)
1641    }
1642
1643    pub(super) fn previous_boundary(&self, offset: usize) -> usize {
1644        let mut offset = self.text.clip_offset(offset.saturating_sub(1), Bias::Left);
1645        if let Some(ch) = self.text.char_at(offset) {
1646            if ch == '\r' {
1647                offset -= 1;
1648            }
1649        }
1650
1651        offset
1652    }
1653
1654    pub(super) fn next_boundary(&self, offset: usize) -> usize {
1655        let mut offset = self.text.clip_offset(offset + 1, Bias::Right);
1656        if let Some(ch) = self.text.char_at(offset) {
1657            if ch == '\r' {
1658                offset += 1;
1659            }
1660        }
1661
1662        offset
1663    }
1664
1665    /// Returns the true to let InputElement to render cursor, when Input is focused and current BlinkCursor is visible.
1666    pub(crate) fn show_cursor(&self, window: &Window, cx: &App) -> bool {
1667        (self.focus_handle.is_focused(window) || self.is_context_menu_open(cx))
1668            && self.blink_cursor.read(cx).visible()
1669            && window.is_window_active()
1670    }
1671
1672    fn on_focus(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1673        self.blink_cursor.update(cx, |cursor, cx| {
1674            cursor.start(cx);
1675        });
1676        cx.emit(InputEvent::Focus);
1677    }
1678
1679    fn on_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1680        if self.is_context_menu_open(cx) {
1681            return;
1682        }
1683
1684        // NOTE: Do not cancel select, when blur.
1685        // Because maybe user want to copy the selected text by AppMenuBar (will take focus handle).
1686
1687        self.hover_popover = None;
1688        self.diagnostic_popover = None;
1689        self.context_menu = None;
1690        self.blink_cursor.update(cx, |cursor, cx| {
1691            cursor.stop(cx);
1692        });
1693        Root::update(window, cx, |root, _, _| {
1694            root.focused_input = None;
1695        });
1696        cx.emit(InputEvent::Blur);
1697        cx.notify();
1698    }
1699
1700    pub(super) fn pause_blink_cursor(&mut self, cx: &mut Context<Self>) {
1701        self.blink_cursor.update(cx, |cursor, cx| {
1702            cursor.pause(cx);
1703        });
1704    }
1705
1706    pub(super) fn on_key_down(&mut self, _: &KeyDownEvent, _: &mut Window, cx: &mut Context<Self>) {
1707        self.pause_blink_cursor(cx);
1708    }
1709
1710    pub(super) fn on_drag_move(
1711        &mut self,
1712        event: &MouseMoveEvent,
1713        window: &mut Window,
1714        cx: &mut Context<Self>,
1715    ) {
1716        if self.text.len() == 0 {
1717            return;
1718        }
1719
1720        if self.last_layout.is_none() {
1721            return;
1722        }
1723
1724        if !self.focus_handle.is_focused(window) {
1725            return;
1726        }
1727
1728        if !self.selecting {
1729            return;
1730        }
1731
1732        let offset = self.index_for_mouse_position(event.position);
1733        self.select_to(offset, cx);
1734    }
1735
1736    fn is_valid_input(&self, new_text: &str, cx: &mut Context<Self>) -> bool {
1737        if new_text.is_empty() {
1738            return true;
1739        }
1740
1741        if let Some(validate) = &self.validate {
1742            if !validate(new_text, cx) {
1743                return false;
1744            }
1745        }
1746
1747        if !self.mask_pattern.is_valid(new_text) {
1748            return false;
1749        }
1750
1751        let Some(pattern) = &self.pattern else {
1752            return true;
1753        };
1754
1755        pattern.is_match(new_text)
1756    }
1757
1758    /// Set the mask pattern for formatting the input text.
1759    ///
1760    /// The pattern can contain:
1761    /// - 9: Any digit or dot
1762    /// - A: Any letter
1763    /// - *: Any character
1764    /// - Other characters will be treated as literal mask characters
1765    ///
1766    /// Example: "(999)999-999" for phone numbers
1767    pub fn mask_pattern(mut self, pattern: impl Into<MaskPattern>) -> Self {
1768        self.mask_pattern = pattern.into();
1769        if let Some(placeholder) = self.mask_pattern.placeholder() {
1770            self.placeholder = placeholder.into();
1771        }
1772        self
1773    }
1774
1775    pub fn set_mask_pattern(
1776        &mut self,
1777        pattern: impl Into<MaskPattern>,
1778        _: &mut Window,
1779        cx: &mut Context<Self>,
1780    ) {
1781        self.mask_pattern = pattern.into();
1782        if let Some(placeholder) = self.mask_pattern.placeholder() {
1783            self.placeholder = placeholder.into();
1784        }
1785        cx.notify();
1786    }
1787
1788    pub(super) fn set_input_bounds(&mut self, new_bounds: Bounds<Pixels>, cx: &mut Context<Self>) {
1789        let wrap_width_changed = self.input_bounds.size.width != new_bounds.size.width;
1790        self.input_bounds = new_bounds;
1791
1792        // Update text_wrapper wrap_width if changed.
1793        if let Some(last_layout) = self.last_layout.as_ref() {
1794            if wrap_width_changed {
1795                let wrap_width = if !self.soft_wrap {
1796                    // None to disable wrapping (will use Pixels::MAX)
1797                    None
1798                } else {
1799                    last_layout.wrap_width
1800                };
1801
1802                self.text_wrapper.set_wrap_width(wrap_width, cx);
1803                self.mode.update_auto_grow(&self.text_wrapper);
1804                cx.notify();
1805            }
1806        }
1807    }
1808
1809    pub(super) fn selected_text(&self) -> RopeSlice<'_> {
1810        let range_utf16 = self.range_to_utf16(&self.selected_range.into());
1811        let range = self.range_from_utf16(&range_utf16);
1812        self.text.slice(range)
1813    }
1814
1815    pub(crate) fn range_to_bounds(&self, range: &Range<usize>) -> Option<Bounds<Pixels>> {
1816        let Some(last_layout) = self.last_layout.as_ref() else {
1817            return None;
1818        };
1819
1820        let Some(last_bounds) = self.last_bounds else {
1821            return None;
1822        };
1823
1824        let (_, _, start_pos) = self.line_and_position_for_offset(range.start);
1825        let (_, _, end_pos) = self.line_and_position_for_offset(range.end);
1826
1827        let Some(start_pos) = start_pos else {
1828            return None;
1829        };
1830        let Some(end_pos) = end_pos else {
1831            return None;
1832        };
1833
1834        Some(Bounds::from_corners(
1835            last_bounds.origin + start_pos,
1836            last_bounds.origin + end_pos + point(px(0.), last_layout.line_height),
1837        ))
1838    }
1839
1840    /// Replace text by [`lsp_types::Range`].
1841    ///
1842    /// See also: [`EntityInputHandler::replace_text_in_range`]
1843    #[allow(unused)]
1844    pub(crate) fn replace_text_in_lsp_range(
1845        &mut self,
1846        lsp_range: &lsp_types::Range,
1847        new_text: &str,
1848        window: &mut Window,
1849        cx: &mut Context<Self>,
1850    ) {
1851        let start = self.text.position_to_offset(&lsp_range.start);
1852        let end = self.text.position_to_offset(&lsp_range.end);
1853        self.replace_text_in_range_silent(
1854            Some(self.range_to_utf16(&(start..end))),
1855            new_text,
1856            window,
1857            cx,
1858        );
1859    }
1860
1861    /// Replace text in range in silent.
1862    ///
1863    /// This will not trigger any UI interaction, such as auto-completion.
1864    pub(crate) fn replace_text_in_range_silent(
1865        &mut self,
1866        range_utf16: Option<Range<usize>>,
1867        new_text: &str,
1868        window: &mut Window,
1869        cx: &mut Context<Self>,
1870    ) {
1871        self.silent_replace_text = true;
1872        self.replace_text_in_range(range_utf16, new_text, window, cx);
1873        self.silent_replace_text = false;
1874    }
1875}
1876
1877impl EntityInputHandler for InputState {
1878    fn text_for_range(
1879        &mut self,
1880        range_utf16: Range<usize>,
1881        adjusted_range: &mut Option<Range<usize>>,
1882        _window: &mut Window,
1883        _cx: &mut Context<Self>,
1884    ) -> Option<String> {
1885        let range = self.range_from_utf16(&range_utf16);
1886        adjusted_range.replace(self.range_to_utf16(&range));
1887        Some(self.text.slice(range).to_string())
1888    }
1889
1890    fn selected_text_range(
1891        &mut self,
1892        _ignore_disabled_input: bool,
1893        _window: &mut Window,
1894        _cx: &mut Context<Self>,
1895    ) -> Option<UTF16Selection> {
1896        Some(UTF16Selection {
1897            range: self.range_to_utf16(&self.selected_range.into()),
1898            reversed: false,
1899        })
1900    }
1901
1902    fn marked_text_range(
1903        &self,
1904        _window: &mut Window,
1905        _cx: &mut Context<Self>,
1906    ) -> Option<Range<usize>> {
1907        self.ime_marked_range
1908            .map(|range| self.range_to_utf16(&range.into()))
1909    }
1910
1911    fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
1912        self.ime_marked_range = None;
1913    }
1914
1915    /// Replace text in range.
1916    ///
1917    /// - If the new text is invalid, it will not be replaced.
1918    /// - If `range_utf16` is not provided, the current selected range will be used.
1919    fn replace_text_in_range(
1920        &mut self,
1921        range_utf16: Option<Range<usize>>,
1922        new_text: &str,
1923        window: &mut Window,
1924        cx: &mut Context<Self>,
1925    ) {
1926        if self.disabled {
1927            return;
1928        }
1929
1930        self.pause_blink_cursor(cx);
1931
1932        let range = range_utf16
1933            .as_ref()
1934            .map(|range_utf16| self.range_from_utf16(range_utf16))
1935            .or(self.ime_marked_range.map(|range| {
1936                let range = self.range_to_utf16(&(range.start..range.end));
1937                self.range_from_utf16(&range)
1938            }))
1939            .unwrap_or(self.selected_range.into());
1940
1941        let old_text = self.text.clone();
1942        self.text.replace(range.clone(), new_text);
1943
1944        let mut new_offset = (range.start + new_text.len()).min(self.text.len());
1945
1946        if self.mode.is_single_line() {
1947            let pending_text = self.text.to_string();
1948            // Check if the new text is valid
1949            if !self.is_valid_input(&pending_text, cx) {
1950                self.text = old_text;
1951                return;
1952            }
1953
1954            if !self.mask_pattern.is_none() {
1955                let mask_text = self.mask_pattern.mask(&pending_text);
1956                self.text = Rope::from(mask_text.as_str());
1957                let new_text_len =
1958                    (new_text.len() + mask_text.len()).saturating_sub(pending_text.len());
1959                new_offset = (range.start + new_text_len).min(mask_text.len());
1960            }
1961        }
1962
1963        self.push_history(&old_text, &range, &new_text);
1964        self.history.end_grouping();
1965        if let Some(diagnostics) = self.mode.diagnostics_mut() {
1966            diagnostics.reset(&self.text)
1967        }
1968        self.text_wrapper
1969            .update(&self.text, &range, &Rope::from(new_text), cx);
1970        self.mode
1971            .update_highlighter(&range, &self.text, &new_text, true, cx);
1972        self.lsp.update(&self.text, window, cx);
1973        self.selected_range = (new_offset..new_offset).into();
1974        self.ime_marked_range.take();
1975        self.update_preferred_column();
1976        self.update_search(cx);
1977        self.mode.update_auto_grow(&self.text_wrapper);
1978        if !self.silent_replace_text {
1979            self.handle_completion_trigger(&range, &new_text, window, cx);
1980        }
1981        cx.emit(InputEvent::Change);
1982        cx.notify();
1983    }
1984
1985    /// Mark text is the IME temporary insert on typing.
1986    fn replace_and_mark_text_in_range(
1987        &mut self,
1988        range_utf16: Option<Range<usize>>,
1989        new_text: &str,
1990        new_selected_range_utf16: Option<Range<usize>>,
1991        window: &mut Window,
1992        cx: &mut Context<Self>,
1993    ) {
1994        if self.disabled {
1995            return;
1996        }
1997
1998        self.lsp.reset();
1999
2000        let range = range_utf16
2001            .as_ref()
2002            .map(|range_utf16| self.range_from_utf16(range_utf16))
2003            .or(self.ime_marked_range.map(|range| {
2004                let range = self.range_to_utf16(&(range.start..range.end));
2005                self.range_from_utf16(&range)
2006            }))
2007            .unwrap_or(self.selected_range.into());
2008
2009        let old_text = self.text.clone();
2010        self.text.replace(range.clone(), new_text);
2011
2012        if self.mode.is_single_line() {
2013            let pending_text = self.text.to_string();
2014            if !self.is_valid_input(&pending_text, cx) {
2015                self.text = old_text;
2016                return;
2017            }
2018        }
2019
2020        if let Some(diagnostics) = self.mode.diagnostics_mut() {
2021            diagnostics.reset(&self.text)
2022        }
2023        self.text_wrapper
2024            .update(&self.text, &range, &Rope::from(new_text), cx);
2025        self.mode
2026            .update_highlighter(&range, &self.text, &new_text, true, cx);
2027        self.lsp.update(&self.text, window, cx);
2028        if new_text.is_empty() {
2029            // Cancel selection, when cancel IME input.
2030            self.selected_range = (range.start..range.start).into();
2031            self.ime_marked_range = None;
2032        } else {
2033            self.ime_marked_range = Some((range.start..range.start + new_text.len()).into());
2034            self.selected_range = new_selected_range_utf16
2035                .as_ref()
2036                .map(|range_utf16| self.range_from_utf16(range_utf16))
2037                .map(|new_range| new_range.start + range.start..new_range.end + range.end)
2038                .unwrap_or_else(|| range.start + new_text.len()..range.start + new_text.len())
2039                .into();
2040        }
2041        self.mode.update_auto_grow(&self.text_wrapper);
2042        self.history.start_grouping();
2043        self.push_history(&old_text, &range, new_text);
2044        cx.notify();
2045    }
2046
2047    /// Used to position IME candidates.
2048    fn bounds_for_range(
2049        &mut self,
2050        range_utf16: Range<usize>,
2051        bounds: Bounds<Pixels>,
2052        _window: &mut Window,
2053        _cx: &mut Context<Self>,
2054    ) -> Option<Bounds<Pixels>> {
2055        let last_layout = self.last_layout.as_ref()?;
2056        let line_height = last_layout.line_height;
2057        let line_number_width = last_layout.line_number_width;
2058        let range = self.range_from_utf16(&range_utf16);
2059
2060        let mut start_origin = None;
2061        let mut end_origin = None;
2062        let line_number_origin = point(line_number_width, px(0.));
2063        let mut y_offset = last_layout.visible_top;
2064        let mut index_offset = last_layout.visible_range_offset.start;
2065
2066        for line in last_layout.lines.iter() {
2067            if start_origin.is_some() && end_origin.is_some() {
2068                break;
2069            }
2070
2071            if start_origin.is_none() {
2072                if let Some(p) =
2073                    line.position_for_index(range.start.saturating_sub(index_offset), line_height)
2074                {
2075                    start_origin = Some(p + point(px(0.), y_offset));
2076                }
2077            }
2078
2079            if end_origin.is_none() {
2080                if let Some(p) =
2081                    line.position_for_index(range.end.saturating_sub(index_offset), line_height)
2082                {
2083                    end_origin = Some(p + point(px(0.), y_offset));
2084                }
2085            }
2086
2087            index_offset += line.len() + 1;
2088            y_offset += line.size(line_height).height;
2089        }
2090
2091        let start_origin = start_origin.unwrap_or_default();
2092        let mut end_origin = end_origin.unwrap_or_default();
2093        // Ensure at same line.
2094        end_origin.y = start_origin.y;
2095
2096        Some(Bounds::from_corners(
2097            bounds.origin + line_number_origin + start_origin,
2098            // + line_height for show IME panel under the cursor line.
2099            bounds.origin + line_number_origin + point(end_origin.x, end_origin.y + line_height),
2100        ))
2101    }
2102
2103    fn character_index_for_point(
2104        &mut self,
2105        point: gpui::Point<Pixels>,
2106        _window: &mut Window,
2107        _cx: &mut Context<Self>,
2108    ) -> Option<usize> {
2109        let last_layout = self.last_layout.as_ref()?;
2110        let line_height = last_layout.line_height;
2111        let line_point = self.last_bounds?.localize(&point)?;
2112        let offset = last_layout.visible_range_offset.start;
2113
2114        for line in last_layout.lines.iter() {
2115            if let Some(utf8_index) = line.index_for_position(line_point, line_height) {
2116                return Some(self.offset_to_utf16(offset + utf8_index));
2117            }
2118        }
2119
2120        None
2121    }
2122}
2123
2124impl Focusable for InputState {
2125    fn focus_handle(&self, _cx: &App) -> FocusHandle {
2126        self.focus_handle.clone()
2127    }
2128}
2129
2130impl Render for InputState {
2131    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
2132        if self._pending_update {
2133            self.mode
2134                .update_highlighter(&(0..0), &self.text, "", false, cx);
2135            self.lsp.update(&self.text, window, cx);
2136            self._pending_update = false;
2137        }
2138
2139        div()
2140            .id("input-state")
2141            .flex_1()
2142            .when(self.mode.is_multi_line(), |this| this.h_full())
2143            .flex_grow()
2144            .overflow_x_hidden()
2145            .child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone()))
2146            .children(self.diagnostic_popover.clone())
2147            .children(self.context_menu.as_ref().map(|menu| menu.render()))
2148            .children(self.hover_popover.clone())
2149    }
2150}