Skip to main content

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