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