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