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            .filter(|(_, s)| !s.trim_start().is_empty())
929            .next_back()
930            .map(|(i, _)| i)
931            .unwrap_or(0)
932    }
933
934    /// Return the next end offset of the next word.
935    pub(super) fn next_end_of_word(&mut self) -> usize {
936        let offset = self.cursor();
937        let offset = self.offset_from_utf16(self.offset_to_utf16(offset));
938        let right_part = self.text.slice(offset..self.text.len()).to_string();
939
940        UnicodeSegmentation::split_word_bound_indices(right_part.as_str())
941            .find(|(_, s)| !s.trim_start().is_empty())
942            .map(|(i, s)| offset + i + s.len())
943            .unwrap_or(self.text.len())
944    }
945
946    /// Get start of line byte offset of cursor
947    pub(super) fn start_of_line(&self) -> usize {
948        if self.mode.is_single_line() {
949            return 0;
950        }
951
952        let row = self.text.offset_to_point(self.cursor()).row;
953        self.text.line_start_offset(row)
954    }
955
956    /// Get end of line byte offset of cursor
957    pub(super) fn end_of_line(&self) -> usize {
958        if self.mode.is_single_line() {
959            return self.text.len();
960        }
961
962        let row = self.text.offset_to_point(self.cursor()).row;
963        self.text.line_end_offset(row)
964    }
965
966    /// Get start line of selection start or end (The min value).
967    ///
968    /// This is means is always get the first line of selection.
969    pub(super) fn start_of_line_of_selection(
970        &mut self,
971        window: &mut Window,
972        cx: &mut Context<Self>,
973    ) -> usize {
974        if self.mode.is_single_line() {
975            return 0;
976        }
977
978        let mut offset =
979            self.previous_boundary(self.selected_range.start.min(self.selected_range.end));
980        if self.text.char_at(offset) == Some('\r') {
981            offset += 1;
982        }
983
984        let line = self
985            .text_for_range(self.range_to_utf16(&(0..offset + 1)), &mut None, window, cx)
986            .unwrap_or_default()
987            .rfind('\n')
988            .map(|i| i + 1)
989            .unwrap_or(0);
990        line
991    }
992
993    /// Get indent string of next line.
994    ///
995    /// To get current and next line indent, to return more depth one.
996    pub(super) fn indent_of_next_line(&mut self) -> String {
997        if self.mode.is_single_line() {
998            return "".into();
999        }
1000
1001        let mut current_indent = String::new();
1002        let mut next_indent = String::new();
1003        let current_line_start_pos = self.start_of_line();
1004        let next_line_start_pos = self.end_of_line();
1005        for c in self.text.slice(current_line_start_pos..).chars() {
1006            if !c.is_whitespace() {
1007                break;
1008            }
1009            if c == '\n' || c == '\r' {
1010                break;
1011            }
1012            current_indent.push(c);
1013        }
1014
1015        for c in self.text.slice(next_line_start_pos..).chars() {
1016            if !c.is_whitespace() {
1017                break;
1018            }
1019            if c == '\n' || c == '\r' {
1020                break;
1021            }
1022            next_indent.push(c);
1023        }
1024
1025        if next_indent.len() > current_indent.len() {
1026            return next_indent;
1027        } else {
1028            return current_indent;
1029        }
1030    }
1031
1032    pub(super) fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
1033        if self.selected_range.is_empty() {
1034            self.select_to(self.previous_boundary(self.cursor()), cx)
1035        }
1036        self.replace_text_in_range(None, "", window, cx);
1037        self.pause_blink_cursor(cx);
1038    }
1039
1040    pub(super) fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
1041        if self.selected_range.is_empty() {
1042            self.select_to(self.next_boundary(self.cursor()), cx)
1043        }
1044        self.replace_text_in_range(None, "", window, cx);
1045        self.pause_blink_cursor(cx);
1046    }
1047
1048    pub(super) fn delete_to_beginning_of_line(
1049        &mut self,
1050        _: &DeleteToBeginningOfLine,
1051        window: &mut Window,
1052        cx: &mut Context<Self>,
1053    ) {
1054        if !self.selected_range.is_empty() {
1055            self.replace_text_in_range(None, "", window, cx);
1056            self.pause_blink_cursor(cx);
1057            return;
1058        }
1059
1060        let mut offset = self.start_of_line();
1061        if offset == self.cursor() {
1062            offset = offset.saturating_sub(1);
1063        }
1064        self.replace_text_in_range_silent(
1065            Some(self.range_to_utf16(&(offset..self.cursor()))),
1066            "",
1067            window,
1068            cx,
1069        );
1070        self.pause_blink_cursor(cx);
1071    }
1072
1073    pub(super) fn delete_to_end_of_line(
1074        &mut self,
1075        _: &DeleteToEndOfLine,
1076        window: &mut Window,
1077        cx: &mut Context<Self>,
1078    ) {
1079        if !self.selected_range.is_empty() {
1080            self.replace_text_in_range(None, "", window, cx);
1081            self.pause_blink_cursor(cx);
1082            return;
1083        }
1084
1085        let mut offset = self.end_of_line();
1086        if offset == self.cursor() {
1087            offset = (offset + 1).clamp(0, self.text.len());
1088        }
1089        self.replace_text_in_range_silent(
1090            Some(self.range_to_utf16(&(self.cursor()..offset))),
1091            "",
1092            window,
1093            cx,
1094        );
1095        self.pause_blink_cursor(cx);
1096    }
1097
1098    pub(super) fn delete_previous_word(
1099        &mut self,
1100        _: &DeleteToPreviousWordStart,
1101        window: &mut Window,
1102        cx: &mut Context<Self>,
1103    ) {
1104        if !self.selected_range.is_empty() {
1105            self.replace_text_in_range(None, "", window, cx);
1106            self.pause_blink_cursor(cx);
1107            return;
1108        }
1109
1110        let offset = self.previous_start_of_word();
1111        self.replace_text_in_range_silent(
1112            Some(self.range_to_utf16(&(offset..self.cursor()))),
1113            "",
1114            window,
1115            cx,
1116        );
1117        self.pause_blink_cursor(cx);
1118    }
1119
1120    pub(super) fn delete_next_word(
1121        &mut self,
1122        _: &DeleteToNextWordEnd,
1123        window: &mut Window,
1124        cx: &mut Context<Self>,
1125    ) {
1126        if !self.selected_range.is_empty() {
1127            self.replace_text_in_range(None, "", window, cx);
1128            self.pause_blink_cursor(cx);
1129            return;
1130        }
1131
1132        let offset = self.next_end_of_word();
1133        self.replace_text_in_range_silent(
1134            Some(self.range_to_utf16(&(self.cursor()..offset))),
1135            "",
1136            window,
1137            cx,
1138        );
1139        self.pause_blink_cursor(cx);
1140    }
1141
1142    pub(super) fn enter(&mut self, action: &Enter, window: &mut Window, cx: &mut Context<Self>) {
1143        if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1144            return;
1145        }
1146
1147        // Clear inline completion on enter (user chose not to accept it)
1148        if self.has_inline_completion() {
1149            self.clear_inline_completion(cx);
1150        }
1151
1152        if self.mode.is_multi_line() {
1153            // Get current line indent
1154            let indent = if self.mode.is_code_editor() {
1155                self.indent_of_next_line()
1156            } else {
1157                "".to_string()
1158            };
1159
1160            // Add newline and indent
1161            let new_line_text = format!("\n{}", indent);
1162            self.replace_text_in_range_silent(None, &new_line_text, window, cx);
1163            self.pause_blink_cursor(cx);
1164        } else {
1165            // Single line input, just emit the event (e.g.: In a dialog to confirm).
1166            cx.propagate();
1167        }
1168
1169        cx.emit(InputEvent::PressEnter {
1170            secondary: action.secondary,
1171        });
1172    }
1173
1174    pub(super) fn clean(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1175        self.replace_text("", window, cx);
1176        self.selected_range = (0..0).into();
1177        self.scroll_to(0, None, cx);
1178    }
1179
1180    pub(super) fn escape(&mut self, action: &Escape, window: &mut Window, cx: &mut Context<Self>) {
1181        if self.handle_action_for_context_menu(Box::new(action.clone()), window, cx) {
1182            return;
1183        }
1184
1185        // Clear inline completion on escape
1186        if self.has_inline_completion() {
1187            self.clear_inline_completion(cx);
1188            return; // Consume the escape, don't propagate
1189        }
1190
1191        if self.ime_marked_range.is_some() {
1192            self.unmark_text(window, cx);
1193        }
1194
1195        if self.clean_on_escape {
1196            return self.clean(window, cx);
1197        }
1198
1199        cx.propagate();
1200    }
1201
1202    pub(super) fn on_mouse_down(
1203        &mut self,
1204        event: &MouseDownEvent,
1205        window: &mut Window,
1206        cx: &mut Context<Self>,
1207    ) {
1208        // Clear inline completion on any mouse interaction
1209        self.clear_inline_completion(cx);
1210
1211        // If there have IME marked range and is empty (Means pressed Esc to abort IME typing)
1212        // Clear the marked range.
1213        if let Some(ime_marked_range) = &self.ime_marked_range {
1214            if ime_marked_range.len() == 0 {
1215                self.ime_marked_range = None;
1216            }
1217        }
1218
1219        self.selecting = true;
1220        let offset = self.index_for_mouse_position(event.position);
1221
1222        if self.handle_click_hover_definition(event, offset, window, cx) {
1223            return;
1224        }
1225
1226        // Double click to select word
1227        if event.button == MouseButton::Left && event.click_count == 2 {
1228            self.select_word(offset, window, cx);
1229            return;
1230        }
1231
1232        // Show Mouse context menu
1233        if event.button == MouseButton::Right {
1234            self.handle_right_click_menu(event, offset, window, cx);
1235            return;
1236        }
1237
1238        if event.modifiers.shift {
1239            self.select_to(offset, cx);
1240        } else {
1241            self.move_to(offset, None, cx)
1242        }
1243    }
1244
1245    pub(super) fn on_mouse_up(
1246        &mut self,
1247        _: &MouseUpEvent,
1248        _window: &mut Window,
1249        _cx: &mut Context<Self>,
1250    ) {
1251        if self.selected_range.is_empty() {
1252            self.selection_reversed = false;
1253        }
1254        self.selecting = false;
1255        self.selected_word_range = None;
1256    }
1257
1258    pub(super) fn on_mouse_move(
1259        &mut self,
1260        event: &MouseMoveEvent,
1261        window: &mut Window,
1262        cx: &mut Context<Self>,
1263    ) {
1264        // Show diagnostic popover on mouse move
1265        let offset = self.index_for_mouse_position(event.position);
1266        self.handle_mouse_move(offset, event, window, cx);
1267
1268        if self.mode.is_code_editor() {
1269            if let Some(diagnostic) = self
1270                .mode
1271                .diagnostics()
1272                .and_then(|set| set.for_offset(offset))
1273            {
1274                if let Some(diagnostic_popover) = self.diagnostic_popover.as_ref() {
1275                    if diagnostic_popover.read(cx).diagnostic.range == diagnostic.range {
1276                        diagnostic_popover.update(cx, |this, cx| {
1277                            this.show(cx);
1278                        });
1279
1280                        return;
1281                    }
1282                }
1283
1284                self.diagnostic_popover = Some(DiagnosticPopover::new(diagnostic, cx.entity(), cx));
1285                cx.notify();
1286            } else {
1287                if let Some(diagnostic_popover) = self.diagnostic_popover.as_mut() {
1288                    diagnostic_popover.update(cx, |this, cx| {
1289                        this.check_to_hide(event.position, cx);
1290                    })
1291                }
1292            }
1293        }
1294    }
1295
1296    pub(super) fn on_scroll_wheel(
1297        &mut self,
1298        event: &ScrollWheelEvent,
1299        window: &mut Window,
1300        cx: &mut Context<Self>,
1301    ) {
1302        let line_height = self
1303            .last_layout
1304            .as_ref()
1305            .map(|layout| layout.line_height)
1306            .unwrap_or(window.line_height());
1307        let delta = event.delta.pixel_delta(line_height);
1308
1309        let old_offset = self.scroll_handle.offset();
1310        self.update_scroll_offset(Some(old_offset + delta), cx);
1311
1312        // Only stop propagation if the offset actually changed
1313        if self.scroll_handle.offset() != old_offset {
1314            cx.stop_propagation();
1315        }
1316
1317        self.diagnostic_popover = None;
1318    }
1319
1320    pub(super) fn update_scroll_offset(
1321        &mut self,
1322        offset: Option<Point<Pixels>>,
1323        cx: &mut Context<Self>,
1324    ) {
1325        let mut offset = offset.unwrap_or(self.scroll_handle.offset());
1326
1327        let safe_y_range =
1328            (-self.scroll_size.height + self.input_bounds.size.height).min(px(0.0))..px(0.);
1329        let safe_x_range =
1330            (-self.scroll_size.width + self.input_bounds.size.width).min(px(0.0))..px(0.);
1331
1332        offset.y = if self.mode.is_single_line() {
1333            px(0.)
1334        } else {
1335            offset.y.clamp(safe_y_range.start, safe_y_range.end)
1336        };
1337        offset.x = offset.x.clamp(safe_x_range.start, safe_x_range.end);
1338        self.scroll_handle.set_offset(offset);
1339        cx.notify();
1340    }
1341
1342    /// Scroll to make the given offset visible.
1343    ///
1344    /// If `direction` is Some, will keep edges at the same side.
1345    pub(crate) fn scroll_to(
1346        &mut self,
1347        offset: usize,
1348        direction: Option<MoveDirection>,
1349        cx: &mut Context<Self>,
1350    ) {
1351        let Some(last_layout) = self.last_layout.as_ref() else {
1352            return;
1353        };
1354        let Some(bounds) = self.last_bounds.as_ref() else {
1355            return;
1356        };
1357
1358        let mut scroll_offset = self.scroll_handle.offset();
1359        let was_offset = scroll_offset;
1360        let line_height = last_layout.line_height;
1361
1362        let point = self.text.offset_to_point(offset);
1363
1364        let row = point.row;
1365
1366        let mut row_offset_y = px(0.);
1367        for (ix, wrap_line) in self.text_wrapper.lines.iter().enumerate() {
1368            if ix == row {
1369                break;
1370            }
1371
1372            row_offset_y += wrap_line.height(line_height);
1373        }
1374
1375        if let Some(line) = last_layout
1376            .lines
1377            .get(row.saturating_sub(last_layout.visible_range.start))
1378        {
1379            // Check to scroll horizontally and soft wrap lines
1380            if let Some(pos) = line.position_for_index(point.column, line_height) {
1381                let bounds_width = bounds.size.width - last_layout.line_number_width;
1382                let col_offset_x = pos.x;
1383                row_offset_y += pos.y;
1384                if col_offset_x - RIGHT_MARGIN < -scroll_offset.x {
1385                    // If the position is out of the visible area, scroll to make it visible
1386                    scroll_offset.x = -col_offset_x + RIGHT_MARGIN;
1387                } else if col_offset_x + RIGHT_MARGIN > -scroll_offset.x + bounds_width {
1388                    scroll_offset.x = -(col_offset_x - bounds_width + RIGHT_MARGIN);
1389                }
1390            }
1391        }
1392
1393        // Check if row_offset_y is out of the viewport
1394        // If row offset is not in the viewport, scroll to make it visible
1395        let edge_height = if direction.is_some() && self.mode.is_code_editor() {
1396            3 * line_height
1397        } else {
1398            line_height
1399        };
1400        if row_offset_y - edge_height + line_height < -scroll_offset.y {
1401            // Scroll up
1402            scroll_offset.y = -row_offset_y + edge_height - line_height;
1403        } else if row_offset_y + edge_height > -scroll_offset.y + bounds.size.height {
1404            // Scroll down
1405            scroll_offset.y = -(row_offset_y - bounds.size.height + edge_height);
1406        }
1407
1408        // Avoid necessary scroll, when it was already in the correct position.
1409        if direction == Some(MoveDirection::Up) {
1410            scroll_offset.y = scroll_offset.y.max(was_offset.y);
1411        } else if direction == Some(MoveDirection::Down) {
1412            scroll_offset.y = scroll_offset.y.min(was_offset.y);
1413        }
1414
1415        scroll_offset.x = scroll_offset.x.min(px(0.));
1416        scroll_offset.y = scroll_offset.y.min(px(0.));
1417        self.deferred_scroll_offset = Some(scroll_offset);
1418        cx.notify();
1419    }
1420
1421    pub(super) fn show_character_palette(
1422        &mut self,
1423        _: &ShowCharacterPalette,
1424        window: &mut Window,
1425        _: &mut Context<Self>,
1426    ) {
1427        window.show_character_palette();
1428    }
1429
1430    pub(super) fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
1431        if self.selected_range.is_empty() {
1432            return;
1433        }
1434
1435        let selected_text = self.text.slice(self.selected_range).to_string();
1436        cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1437    }
1438
1439    pub(super) fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
1440        if self.selected_range.is_empty() {
1441            return;
1442        }
1443
1444        let selected_text = self.text.slice(self.selected_range).to_string();
1445        cx.write_to_clipboard(ClipboardItem::new_string(selected_text));
1446
1447        self.replace_text_in_range_silent(None, "", window, cx);
1448    }
1449
1450    pub(super) fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
1451        if let Some(clipboard) = cx.read_from_clipboard() {
1452            let mut new_text = clipboard.text().unwrap_or_default();
1453            if !self.mode.is_multi_line() {
1454                new_text = new_text.replace('\n', "");
1455            }
1456
1457            self.replace_text_in_range_silent(None, &new_text, window, cx);
1458            self.scroll_to(self.cursor(), None, cx);
1459        }
1460    }
1461
1462    fn push_history(&mut self, text: &Rope, range: &Range<usize>, new_text: &str) {
1463        if self.history.ignore {
1464            return;
1465        }
1466
1467        let old_text = text.slice(range.clone()).to_string();
1468        let new_range = range.start..range.start + new_text.len();
1469
1470        self.history
1471            .push(Change::new(range.clone(), &old_text, new_range, new_text));
1472    }
1473
1474    pub(super) fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
1475        self.history.ignore = true;
1476        if let Some(changes) = self.history.undo() {
1477            for change in changes {
1478                let range_utf16 = self.range_to_utf16(&change.new_range.into());
1479                self.replace_text_in_range_silent(Some(range_utf16), &change.old_text, window, cx);
1480            }
1481        }
1482        self.history.ignore = false;
1483    }
1484
1485    pub(super) fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
1486        self.history.ignore = true;
1487        if let Some(changes) = self.history.redo() {
1488            for change in changes {
1489                let range_utf16 = self.range_to_utf16(&change.old_range.into());
1490                self.replace_text_in_range_silent(Some(range_utf16), &change.new_text, window, cx);
1491            }
1492        }
1493        self.history.ignore = false;
1494    }
1495
1496    /// Get byte offset of the cursor.
1497    ///
1498    /// The offset is the UTF-8 offset.
1499    pub fn cursor(&self) -> usize {
1500        if let Some(ime_marked_range) = &self.ime_marked_range {
1501            return ime_marked_range.end;
1502        }
1503
1504        if self.selection_reversed {
1505            self.selected_range.start
1506        } else {
1507            self.selected_range.end
1508        }
1509    }
1510
1511    pub(crate) fn index_for_mouse_position(&self, position: Point<Pixels>) -> usize {
1512        // If the text is empty, always return 0
1513        if self.text.len() == 0 {
1514            return 0;
1515        }
1516
1517        let (Some(bounds), Some(last_layout)) =
1518            (self.last_bounds.as_ref(), self.last_layout.as_ref())
1519        else {
1520            return 0;
1521        };
1522
1523        let line_height = last_layout.line_height;
1524        let line_number_width = last_layout.line_number_width;
1525
1526        // TIP: About the IBeam cursor
1527        //
1528        // If cursor style is IBeam, the mouse mouse position is in the middle of the cursor (This is special in OS)
1529
1530        // The position is relative to the bounds of the text input
1531        //
1532        // bounds.origin:
1533        //
1534        // - included the input padding.
1535        // - included the scroll offset.
1536        let inner_position = position - bounds.origin - point(line_number_width, px(0.));
1537
1538        let mut index = last_layout.visible_range_offset.start;
1539        let mut y_offset = last_layout.visible_top;
1540        for (ix, line) in self
1541            .text_wrapper
1542            .lines
1543            .iter()
1544            .skip(last_layout.visible_range.start)
1545            .enumerate()
1546        {
1547            let line_origin = self.line_origin_with_y_offset(&mut y_offset, line, line_height);
1548            let pos = inner_position - line_origin;
1549
1550            let Some(line_layout) = last_layout.lines.get(ix) else {
1551                if pos.y < line_origin.y + line_height {
1552                    break;
1553                }
1554
1555                continue;
1556            };
1557
1558            // Return offset by use closest_index_for_x if is single line mode.
1559            if self.mode.is_single_line() {
1560                index = line_layout.closest_index_for_x(pos.x);
1561                break;
1562            }
1563
1564            if let Some(v) = line_layout.closest_index_for_position(pos, line_height) {
1565                index += v;
1566                break;
1567            } else if pos.y < px(0.) {
1568                break;
1569            }
1570
1571            // +1 for `\n`
1572            index += line_layout.len() + 1;
1573        }
1574
1575        let index = if index > self.text.len() {
1576            self.text.len()
1577        } else {
1578            index
1579        };
1580
1581        if self.masked {
1582            // When is masked, the index is char index, need convert to byte index.
1583            self.text.char_index_to_offset(index)
1584        } else {
1585            index
1586        }
1587    }
1588
1589    /// Returns a y offsetted point for the line origin.
1590    fn line_origin_with_y_offset(
1591        &self,
1592        y_offset: &mut Pixels,
1593        line: &LineItem,
1594        line_height: Pixels,
1595    ) -> Point<Pixels> {
1596        // NOTE: About line.wrap_boundaries.len()
1597        //
1598        // If only 1 line, the value is 0
1599        // If have 2 line, the value is 1
1600        if self.mode.is_multi_line() {
1601            let p = point(px(0.), *y_offset);
1602            *y_offset += line.height(line_height);
1603            p
1604        } else {
1605            point(px(0.), px(0.))
1606        }
1607    }
1608
1609    /// Select the text from the current cursor position to the given offset.
1610    ///
1611    /// The offset is the UTF-8 offset.
1612    ///
1613    /// Ensure the offset use self.next_boundary or self.previous_boundary to get the correct offset.
1614    pub(crate) fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
1615        self.clear_inline_completion(cx);
1616
1617        let offset = offset.clamp(0, self.text.len());
1618        if self.selection_reversed {
1619            self.selected_range.start = offset
1620        } else {
1621            self.selected_range.end = offset
1622        };
1623
1624        if self.selected_range.end < self.selected_range.start {
1625            self.selection_reversed = !self.selection_reversed;
1626            self.selected_range = (self.selected_range.end..self.selected_range.start).into();
1627        }
1628
1629        // Ensure keep word selected range
1630        if let Some(word_range) = self.selected_word_range.as_ref() {
1631            if self.selected_range.start > word_range.start {
1632                self.selected_range.start = word_range.start;
1633            }
1634            if self.selected_range.end < word_range.end {
1635                self.selected_range.end = word_range.end;
1636            }
1637        }
1638        if self.selected_range.is_empty() {
1639            self.update_preferred_column();
1640        }
1641        cx.notify()
1642    }
1643
1644    /// Unselects the currently selected text.
1645    pub fn unselect(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1646        let offset = self.cursor();
1647        self.selected_range = (offset..offset).into();
1648        cx.notify()
1649    }
1650
1651    #[inline]
1652    pub(super) fn offset_from_utf16(&self, offset: usize) -> usize {
1653        self.text.offset_utf16_to_offset(offset)
1654    }
1655
1656    #[inline]
1657    pub(super) fn offset_to_utf16(&self, offset: usize) -> usize {
1658        self.text.offset_to_offset_utf16(offset)
1659    }
1660
1661    #[inline]
1662    pub(super) fn range_to_utf16(&self, range: &Range<usize>) -> Range<usize> {
1663        self.offset_to_utf16(range.start)..self.offset_to_utf16(range.end)
1664    }
1665
1666    #[inline]
1667    pub(super) fn range_from_utf16(&self, range_utf16: &Range<usize>) -> Range<usize> {
1668        self.offset_from_utf16(range_utf16.start)..self.offset_from_utf16(range_utf16.end)
1669    }
1670
1671    pub(super) fn previous_boundary(&self, offset: usize) -> usize {
1672        let mut offset = self.text.clip_offset(offset.saturating_sub(1), Bias::Left);
1673        if let Some(ch) = self.text.char_at(offset) {
1674            if ch == '\r' {
1675                offset -= 1;
1676            }
1677        }
1678
1679        offset
1680    }
1681
1682    pub(super) fn next_boundary(&self, offset: usize) -> usize {
1683        let mut offset = self.text.clip_offset(offset + 1, Bias::Right);
1684        if let Some(ch) = self.text.char_at(offset) {
1685            if ch == '\r' {
1686                offset += 1;
1687            }
1688        }
1689
1690        offset
1691    }
1692
1693    /// Returns the true to let InputElement to render cursor, when Input is focused and current BlinkCursor is visible.
1694    pub(crate) fn show_cursor(&self, window: &Window, cx: &App) -> bool {
1695        (self.focus_handle.is_focused(window) || self.is_context_menu_open(cx))
1696            && self.blink_cursor.read(cx).visible()
1697            && window.is_window_active()
1698    }
1699
1700    fn on_focus(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1701        self.blink_cursor.update(cx, |cursor, cx| {
1702            cursor.start(cx);
1703        });
1704        cx.emit(InputEvent::Focus);
1705    }
1706
1707    fn on_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1708        if self.is_context_menu_open(cx) {
1709            return;
1710        }
1711
1712        // NOTE: Do not cancel select, when blur.
1713        // Because maybe user want to copy the selected text by AppMenuBar (will take focus handle).
1714
1715        self.hover_popover = None;
1716        self.diagnostic_popover = None;
1717        self.context_menu = None;
1718        self.clear_inline_completion(cx);
1719        self.blink_cursor.update(cx, |cursor, cx| {
1720            cursor.stop(cx);
1721        });
1722        Root::update(window, cx, |root, _, _| {
1723            root.focused_input = None;
1724        });
1725        cx.emit(InputEvent::Blur);
1726        cx.notify();
1727    }
1728
1729    pub(super) fn pause_blink_cursor(&mut self, cx: &mut Context<Self>) {
1730        self.blink_cursor.update(cx, |cursor, cx| {
1731            cursor.pause(cx);
1732        });
1733    }
1734
1735    pub(super) fn on_key_down(&mut self, _: &KeyDownEvent, _: &mut Window, cx: &mut Context<Self>) {
1736        self.pause_blink_cursor(cx);
1737    }
1738
1739    pub(super) fn on_drag_move(
1740        &mut self,
1741        event: &MouseMoveEvent,
1742        window: &mut Window,
1743        cx: &mut Context<Self>,
1744    ) {
1745        if self.text.len() == 0 {
1746            return;
1747        }
1748
1749        if self.last_layout.is_none() {
1750            return;
1751        }
1752
1753        if !self.focus_handle.is_focused(window) {
1754            return;
1755        }
1756
1757        if !self.selecting {
1758            return;
1759        }
1760
1761        let offset = self.index_for_mouse_position(event.position);
1762        self.select_to(offset, cx);
1763    }
1764
1765    fn is_valid_input(&self, new_text: &str, cx: &mut Context<Self>) -> bool {
1766        if new_text.is_empty() {
1767            return true;
1768        }
1769
1770        if let Some(validate) = &self.validate {
1771            if !validate(new_text, cx) {
1772                return false;
1773            }
1774        }
1775
1776        if !self.mask_pattern.is_valid(new_text) {
1777            return false;
1778        }
1779
1780        let Some(pattern) = &self.pattern else {
1781            return true;
1782        };
1783
1784        pattern.is_match(new_text)
1785    }
1786
1787    /// Set the mask pattern for formatting the input text.
1788    ///
1789    /// The pattern can contain:
1790    /// - 9: Any digit or dot
1791    /// - A: Any letter
1792    /// - *: Any character
1793    /// - Other characters will be treated as literal mask characters
1794    ///
1795    /// Example: "(999)999-999" for phone numbers
1796    pub fn mask_pattern(mut self, pattern: impl Into<MaskPattern>) -> Self {
1797        self.mask_pattern = pattern.into();
1798        if let Some(placeholder) = self.mask_pattern.placeholder() {
1799            self.placeholder = placeholder.into();
1800        }
1801        self
1802    }
1803
1804    pub fn set_mask_pattern(
1805        &mut self,
1806        pattern: impl Into<MaskPattern>,
1807        _: &mut Window,
1808        cx: &mut Context<Self>,
1809    ) {
1810        self.mask_pattern = pattern.into();
1811        if let Some(placeholder) = self.mask_pattern.placeholder() {
1812            self.placeholder = placeholder.into();
1813        }
1814        cx.notify();
1815    }
1816
1817    pub(super) fn set_input_bounds(&mut self, new_bounds: Bounds<Pixels>, cx: &mut Context<Self>) {
1818        let wrap_width_changed = self.input_bounds.size.width != new_bounds.size.width;
1819        self.input_bounds = new_bounds;
1820
1821        // Update text_wrapper wrap_width if changed.
1822        if let Some(last_layout) = self.last_layout.as_ref() {
1823            if wrap_width_changed {
1824                let wrap_width = if !self.soft_wrap {
1825                    // None to disable wrapping (will use Pixels::MAX)
1826                    None
1827                } else {
1828                    last_layout.wrap_width
1829                };
1830
1831                self.text_wrapper.set_wrap_width(wrap_width, cx);
1832                self.mode.update_auto_grow(&self.text_wrapper);
1833                cx.notify();
1834            }
1835        }
1836    }
1837
1838    pub(super) fn selected_text(&self) -> RopeSlice<'_> {
1839        let range_utf16 = self.range_to_utf16(&self.selected_range.into());
1840        let range = self.range_from_utf16(&range_utf16);
1841        self.text.slice(range)
1842    }
1843
1844    pub(crate) fn range_to_bounds(&self, range: &Range<usize>) -> Option<Bounds<Pixels>> {
1845        let Some(last_layout) = self.last_layout.as_ref() else {
1846            return None;
1847        };
1848
1849        let Some(last_bounds) = self.last_bounds else {
1850            return None;
1851        };
1852
1853        let (_, _, start_pos) = self.line_and_position_for_offset(range.start);
1854        let (_, _, end_pos) = self.line_and_position_for_offset(range.end);
1855
1856        let Some(start_pos) = start_pos else {
1857            return None;
1858        };
1859        let Some(end_pos) = end_pos else {
1860            return None;
1861        };
1862
1863        Some(Bounds::from_corners(
1864            last_bounds.origin + start_pos,
1865            last_bounds.origin + end_pos + point(px(0.), last_layout.line_height),
1866        ))
1867    }
1868
1869    /// Replace text by [`lsp_types::Range`].
1870    ///
1871    /// See also: [`EntityInputHandler::replace_text_in_range`]
1872    #[allow(unused)]
1873    pub(crate) fn replace_text_in_lsp_range(
1874        &mut self,
1875        lsp_range: &lsp_types::Range,
1876        new_text: &str,
1877        window: &mut Window,
1878        cx: &mut Context<Self>,
1879    ) {
1880        let start = self.text.position_to_offset(&lsp_range.start);
1881        let end = self.text.position_to_offset(&lsp_range.end);
1882        self.replace_text_in_range_silent(
1883            Some(self.range_to_utf16(&(start..end))),
1884            new_text,
1885            window,
1886            cx,
1887        );
1888    }
1889
1890    /// Replace text in range in silent.
1891    ///
1892    /// This will not trigger any UI interaction, such as auto-completion.
1893    pub(crate) fn replace_text_in_range_silent(
1894        &mut self,
1895        range_utf16: Option<Range<usize>>,
1896        new_text: &str,
1897        window: &mut Window,
1898        cx: &mut Context<Self>,
1899    ) {
1900        self.silent_replace_text = true;
1901        self.replace_text_in_range(range_utf16, new_text, window, cx);
1902        self.silent_replace_text = false;
1903    }
1904}
1905
1906impl EntityInputHandler for InputState {
1907    fn text_for_range(
1908        &mut self,
1909        range_utf16: Range<usize>,
1910        adjusted_range: &mut Option<Range<usize>>,
1911        _window: &mut Window,
1912        _cx: &mut Context<Self>,
1913    ) -> Option<String> {
1914        let range = self.range_from_utf16(&range_utf16);
1915        adjusted_range.replace(self.range_to_utf16(&range));
1916        Some(self.text.slice(range).to_string())
1917    }
1918
1919    fn selected_text_range(
1920        &mut self,
1921        _ignore_disabled_input: bool,
1922        _window: &mut Window,
1923        _cx: &mut Context<Self>,
1924    ) -> Option<UTF16Selection> {
1925        Some(UTF16Selection {
1926            range: self.range_to_utf16(&self.selected_range.into()),
1927            reversed: false,
1928        })
1929    }
1930
1931    fn marked_text_range(
1932        &self,
1933        _window: &mut Window,
1934        _cx: &mut Context<Self>,
1935    ) -> Option<Range<usize>> {
1936        self.ime_marked_range
1937            .map(|range| self.range_to_utf16(&range.into()))
1938    }
1939
1940    fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
1941        self.ime_marked_range = None;
1942    }
1943
1944    /// Replace text in range.
1945    ///
1946    /// - If the new text is invalid, it will not be replaced.
1947    /// - If `range_utf16` is not provided, the current selected range will be used.
1948    fn replace_text_in_range(
1949        &mut self,
1950        range_utf16: Option<Range<usize>>,
1951        new_text: &str,
1952        window: &mut Window,
1953        cx: &mut Context<Self>,
1954    ) {
1955        if self.disabled {
1956            return;
1957        }
1958
1959        self.pause_blink_cursor(cx);
1960
1961        let range = range_utf16
1962            .as_ref()
1963            .map(|range_utf16| self.range_from_utf16(range_utf16))
1964            .or(self.ime_marked_range.map(|range| {
1965                let range = self.range_to_utf16(&(range.start..range.end));
1966                self.range_from_utf16(&range)
1967            }))
1968            .unwrap_or(self.selected_range.into());
1969
1970        let old_text = self.text.clone();
1971        self.text.replace(range.clone(), new_text);
1972
1973        let mut new_offset = (range.start + new_text.len()).min(self.text.len());
1974
1975        if self.mode.is_single_line() {
1976            let pending_text = self.text.to_string();
1977            // Check if the new text is valid
1978            if !self.is_valid_input(&pending_text, cx) {
1979                self.text = old_text;
1980                return;
1981            }
1982
1983            if !self.mask_pattern.is_none() {
1984                let mask_text = self.mask_pattern.mask(&pending_text);
1985                self.text = Rope::from(mask_text.as_str());
1986                let new_text_len =
1987                    (new_text.len() + mask_text.len()).saturating_sub(pending_text.len());
1988                new_offset = (range.start + new_text_len).min(mask_text.len());
1989            }
1990        }
1991
1992        self.push_history(&old_text, &range, &new_text);
1993        self.history.end_grouping();
1994        if let Some(diagnostics) = self.mode.diagnostics_mut() {
1995            diagnostics.reset(&self.text)
1996        }
1997        self.text_wrapper
1998            .update(&self.text, &range, &Rope::from(new_text), cx);
1999        self.mode
2000            .update_highlighter(&range, &self.text, &new_text, true, cx);
2001        self.lsp.update(&self.text, window, cx);
2002        self.selected_range = (new_offset..new_offset).into();
2003        self.ime_marked_range.take();
2004        self.update_preferred_column();
2005        self.update_search(cx);
2006        self.mode.update_auto_grow(&self.text_wrapper);
2007        if !self.silent_replace_text {
2008            self.handle_completion_trigger(&range, &new_text, window, cx);
2009        }
2010        cx.emit(InputEvent::Change);
2011        cx.notify();
2012    }
2013
2014    /// Mark text is the IME temporary insert on typing.
2015    fn replace_and_mark_text_in_range(
2016        &mut self,
2017        range_utf16: Option<Range<usize>>,
2018        new_text: &str,
2019        new_selected_range_utf16: Option<Range<usize>>,
2020        window: &mut Window,
2021        cx: &mut Context<Self>,
2022    ) {
2023        if self.disabled {
2024            return;
2025        }
2026
2027        self.lsp.reset();
2028
2029        let range = range_utf16
2030            .as_ref()
2031            .map(|range_utf16| self.range_from_utf16(range_utf16))
2032            .or(self.ime_marked_range.map(|range| {
2033                let range = self.range_to_utf16(&(range.start..range.end));
2034                self.range_from_utf16(&range)
2035            }))
2036            .unwrap_or(self.selected_range.into());
2037
2038        let old_text = self.text.clone();
2039        self.text.replace(range.clone(), new_text);
2040
2041        if self.mode.is_single_line() {
2042            let pending_text = self.text.to_string();
2043            if !self.is_valid_input(&pending_text, cx) {
2044                self.text = old_text;
2045                return;
2046            }
2047        }
2048
2049        if let Some(diagnostics) = self.mode.diagnostics_mut() {
2050            diagnostics.reset(&self.text)
2051        }
2052        self.text_wrapper
2053            .update(&self.text, &range, &Rope::from(new_text), cx);
2054        self.mode
2055            .update_highlighter(&range, &self.text, &new_text, true, cx);
2056        self.lsp.update(&self.text, window, cx);
2057        if new_text.is_empty() {
2058            // Cancel selection, when cancel IME input.
2059            self.selected_range = (range.start..range.start).into();
2060            self.ime_marked_range = None;
2061        } else {
2062            self.ime_marked_range = Some((range.start..range.start + new_text.len()).into());
2063            self.selected_range = new_selected_range_utf16
2064                .as_ref()
2065                .map(|range_utf16| self.range_from_utf16(range_utf16))
2066                .map(|new_range| new_range.start + range.start..new_range.end + range.end)
2067                .unwrap_or_else(|| range.start + new_text.len()..range.start + new_text.len())
2068                .into();
2069        }
2070        self.mode.update_auto_grow(&self.text_wrapper);
2071        self.history.start_grouping();
2072        self.push_history(&old_text, &range, new_text);
2073        cx.notify();
2074    }
2075
2076    /// Used to position IME candidates.
2077    fn bounds_for_range(
2078        &mut self,
2079        range_utf16: Range<usize>,
2080        bounds: Bounds<Pixels>,
2081        _window: &mut Window,
2082        _cx: &mut Context<Self>,
2083    ) -> Option<Bounds<Pixels>> {
2084        let last_layout = self.last_layout.as_ref()?;
2085        let line_height = last_layout.line_height;
2086        let line_number_width = last_layout.line_number_width;
2087        let range = self.range_from_utf16(&range_utf16);
2088
2089        let mut start_origin = None;
2090        let mut end_origin = None;
2091        let line_number_origin = point(line_number_width, px(0.));
2092        let mut y_offset = last_layout.visible_top;
2093        let mut index_offset = last_layout.visible_range_offset.start;
2094
2095        for line in last_layout.lines.iter() {
2096            if start_origin.is_some() && end_origin.is_some() {
2097                break;
2098            }
2099
2100            if start_origin.is_none() {
2101                if let Some(p) =
2102                    line.position_for_index(range.start.saturating_sub(index_offset), line_height)
2103                {
2104                    start_origin = Some(p + point(px(0.), y_offset));
2105                }
2106            }
2107
2108            if end_origin.is_none() {
2109                if let Some(p) =
2110                    line.position_for_index(range.end.saturating_sub(index_offset), line_height)
2111                {
2112                    end_origin = Some(p + point(px(0.), y_offset));
2113                }
2114            }
2115
2116            index_offset += line.len() + 1;
2117            y_offset += line.size(line_height).height;
2118        }
2119
2120        let start_origin = start_origin.unwrap_or_default();
2121        let mut end_origin = end_origin.unwrap_or_default();
2122        // Ensure at same line.
2123        end_origin.y = start_origin.y;
2124
2125        Some(Bounds::from_corners(
2126            bounds.origin + line_number_origin + start_origin,
2127            // + line_height for show IME panel under the cursor line.
2128            bounds.origin + line_number_origin + point(end_origin.x, end_origin.y + line_height),
2129        ))
2130    }
2131
2132    fn character_index_for_point(
2133        &mut self,
2134        point: gpui::Point<Pixels>,
2135        _window: &mut Window,
2136        _cx: &mut Context<Self>,
2137    ) -> Option<usize> {
2138        let last_layout = self.last_layout.as_ref()?;
2139        let line_height = last_layout.line_height;
2140        let line_point = self.last_bounds?.localize(&point)?;
2141        let offset = last_layout.visible_range_offset.start;
2142
2143        for line in last_layout.lines.iter() {
2144            if let Some(utf8_index) = line.index_for_position(line_point, line_height) {
2145                return Some(self.offset_to_utf16(offset + utf8_index));
2146            }
2147        }
2148
2149        None
2150    }
2151}
2152
2153impl Focusable for InputState {
2154    fn focus_handle(&self, _cx: &App) -> FocusHandle {
2155        self.focus_handle.clone()
2156    }
2157}
2158
2159impl Render for InputState {
2160    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
2161        if self._pending_update {
2162            self.mode
2163                .update_highlighter(&(0..0), &self.text, "", false, cx);
2164            self.lsp.update(&self.text, window, cx);
2165            self._pending_update = false;
2166        }
2167
2168        div()
2169            .id("input-state")
2170            .flex_1()
2171            .when(self.mode.is_multi_line(), |this| this.h_full())
2172            .flex_grow()
2173            .overflow_x_hidden()
2174            .child(TextElement::new(cx.entity().clone()).placeholder(self.placeholder.clone()))
2175            .children(self.diagnostic_popover.clone())
2176            .children(self.context_menu.as_ref().map(|menu| menu.render()))
2177            .children(self.hover_popover.clone())
2178    }
2179}