1use std::{ops::Range, time::Duration};
21
22use gpui::{
23 App, Bounds, ClipboardItem, Context, CursorStyle, DispatchPhase, ElementId,
24 ElementInputHandler, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable, Global,
25 GlobalElementId, KeyBinding, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
26 MouseUpEvent, PaintQuad, Pixels, Point, SharedString, Style, Task, TextRun, UTF16Selection,
27 UnderlineStyle, Window, WrappedLine, actions, div, fill, prelude::*, px, relative,
28};
29use unicode_segmentation::UnicodeSegmentation as _;
30
31use theme::{HighlightKind, Metrics, SyntaxPalette, TextStyle, Theme};
32
33actions!(
34 bezel_text_field,
35 [
36 Backspace,
37 Delete,
38 Left,
39 Right,
40 SelectLeft,
41 SelectRight,
42 SelectAll,
43 Home,
44 End,
45 SelectHome,
46 SelectEnd,
47 WordLeft,
48 WordRight,
49 SelectWordLeft,
50 SelectWordRight,
51 DeleteWordLeft,
52 DeleteWordRight,
53 DeleteToLineStart,
54 DeleteToLineEnd,
55 ShowCharacterPalette,
56 Paste,
57 Cut,
58 Copy,
59 Up,
60 Down,
61 SelectUp,
62 SelectDown,
63 InsertNewline,
64 Undo,
65 Redo,
66 ]
67);
68
69pub const DEFAULT_UNDO_LIMIT: usize = 10;
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub enum FieldEvent {
87 Changed,
89 Moved,
91}
92
93const BLINK: Duration = Duration::from_millis(500);
95
96struct CaretBlink(bool);
99
100impl Global for CaretBlink {}
101
102pub fn caret_blink(cx: &App) -> bool {
105 cx.try_global::<CaretBlink>().is_none_or(|blink| blink.0)
106}
107
108pub fn set_caret_blink(blink: bool, cx: &mut App) {
111 cx.set_global(CaretBlink(blink));
112 cx.refresh_windows();
113}
114
115const CARET_WIDTH: Pixels = px(2.);
118
119pub const KEY_CONTEXT: &str = "TextField";
121
122pub const MULTILINE_KEY_CONTEXT: &str = "TextArea";
131
132pub fn init(cx: &mut App) {
134 cx.bind_keys(bindings());
135}
136
137pub fn bindings() -> Vec<KeyBinding> {
144 let mut bindings = Vec::new();
145 let ctx = Some(KEY_CONTEXT);
146 bindings.extend([
147 KeyBinding::new("backspace", Backspace, ctx),
149 KeyBinding::new("delete", Delete, ctx),
150 KeyBinding::new("left", Left, ctx),
151 KeyBinding::new("right", Right, ctx),
152 KeyBinding::new("shift-left", SelectLeft, ctx),
153 KeyBinding::new("shift-right", SelectRight, ctx),
154 KeyBinding::new("home", Home, ctx),
155 KeyBinding::new("end", End, ctx),
156 KeyBinding::new("shift-home", SelectHome, ctx),
157 KeyBinding::new("shift-end", SelectEnd, ctx),
158 ]);
159
160 let area = Some(MULTILINE_KEY_CONTEXT);
163 bindings.extend([
164 KeyBinding::new("enter", InsertNewline, area),
165 KeyBinding::new("up", Up, area),
166 KeyBinding::new("down", Down, area),
167 KeyBinding::new("shift-up", SelectUp, area),
168 KeyBinding::new("shift-down", SelectDown, area),
169 ]);
170
171 #[cfg(target_os = "macos")]
172 bindings.extend([
173 KeyBinding::new("cmd-a", SelectAll, ctx),
174 KeyBinding::new("cmd-c", Copy, ctx),
175 KeyBinding::new("cmd-x", Cut, ctx),
176 KeyBinding::new("cmd-v", Paste, ctx),
177 KeyBinding::new("cmd-z", Undo, ctx),
178 KeyBinding::new("cmd-shift-z", Redo, ctx),
179 KeyBinding::new("ctrl-cmd-space", ShowCharacterPalette, ctx),
180 KeyBinding::new("cmd-left", Home, ctx),
182 KeyBinding::new("cmd-right", End, ctx),
183 KeyBinding::new("cmd-shift-left", SelectHome, ctx),
184 KeyBinding::new("cmd-shift-right", SelectEnd, ctx),
185 KeyBinding::new("alt-left", WordLeft, ctx),
186 KeyBinding::new("alt-right", WordRight, ctx),
187 KeyBinding::new("alt-shift-left", SelectWordLeft, ctx),
188 KeyBinding::new("alt-shift-right", SelectWordRight, ctx),
189 KeyBinding::new("cmd-backspace", DeleteToLineStart, ctx),
190 KeyBinding::new("alt-backspace", DeleteWordLeft, ctx),
191 KeyBinding::new("alt-delete", DeleteWordRight, ctx),
192 KeyBinding::new("ctrl-a", Home, ctx),
194 KeyBinding::new("ctrl-e", End, ctx),
195 KeyBinding::new("ctrl-b", Left, ctx),
196 KeyBinding::new("ctrl-f", Right, ctx),
197 KeyBinding::new("ctrl-h", Backspace, ctx),
198 KeyBinding::new("ctrl-d", Delete, ctx),
199 KeyBinding::new("ctrl-k", DeleteToLineEnd, ctx),
200 ]);
201
202 #[cfg(target_os = "macos")]
205 bindings.extend([
206 KeyBinding::new("ctrl-n", Down, area),
207 KeyBinding::new("ctrl-p", Up, area),
208 ]);
209
210 #[cfg(not(target_os = "macos"))]
211 bindings.extend([
212 KeyBinding::new("ctrl-a", SelectAll, ctx),
213 KeyBinding::new("ctrl-c", Copy, ctx),
214 KeyBinding::new("ctrl-x", Cut, ctx),
215 KeyBinding::new("ctrl-v", Paste, ctx),
216 KeyBinding::new("ctrl-left", WordLeft, ctx),
218 KeyBinding::new("ctrl-right", WordRight, ctx),
219 KeyBinding::new("ctrl-shift-left", SelectWordLeft, ctx),
220 KeyBinding::new("ctrl-shift-right", SelectWordRight, ctx),
221 KeyBinding::new("ctrl-backspace", DeleteWordLeft, ctx),
222 KeyBinding::new("ctrl-delete", DeleteWordRight, ctx),
223 KeyBinding::new("ctrl-z", Undo, ctx),
224 KeyBinding::new("ctrl-shift-z", Redo, ctx),
225 ]);
226
227 bindings
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
237pub enum Shape {
238 #[default]
241 Line,
242 Rows(usize),
244 Grow { min: usize, max: usize },
247}
248
249impl Shape {
250 fn is_multiline(self) -> bool {
253 !matches!(self, Self::Line)
254 }
255}
256
257#[derive(Clone)]
263struct Snapshot {
264 content: SharedString,
265 selection: Range<usize>,
266 reversed: bool,
267}
268
269#[derive(Clone, Copy, PartialEq, Eq)]
272pub enum EditKind {
273 Insert,
274 Delete,
275}
276
277pub struct TextField {
280 focus_handle: FocusHandle,
281 content: SharedString,
282 placeholder: SharedString,
283 shape: Shape,
284 selected_range: Range<usize>,
285 selection_reversed: bool,
286 marked_range: Option<Range<usize>>,
288 last_layout: Vec<WrappedLine>,
291 last_bounds: Option<Bounds<Pixels>>,
292 is_selecting: bool,
293 goal_x: Option<Pixels>,
300 scroll: Point<Pixels>,
308 history: crate::history::SnapshotHistory<Snapshot>,
309 last_edit: Option<(EditKind, usize)>,
313 key_context: Option<SharedString>,
316 frame: bool,
320 metrics: Metrics,
323 caret_on: bool,
325 blink: Option<Task<()>>,
327 follow_caret: bool,
334 spans: Vec<(Range<usize>, HighlightKind)>,
337}
338
339impl EventEmitter<FieldEvent> for TextField {}
340
341impl TextField {
342 pub fn new(cx: &mut Context<Self>) -> Self {
343 Self {
344 focus_handle: cx.focus_handle().tab_stop(true),
347 frame: true,
348 content: "".into(),
349 placeholder: "".into(),
350 shape: Shape::Line,
351 selected_range: 0..0,
352 selection_reversed: false,
353 marked_range: None,
354 last_layout: Vec::new(),
355 last_bounds: None,
356 is_selecting: false,
357 goal_x: None,
358 scroll: Point::default(),
359 history: crate::history::SnapshotHistory::new(DEFAULT_UNDO_LIMIT),
360 last_edit: None,
361 key_context: None,
362 metrics: TextStyle::Body.into(),
363 caret_on: true,
364 blink: None,
365 follow_caret: false,
366 spans: Vec::new(),
367 }
368 }
369
370 pub fn with_undo_limit(mut self, limit: usize) -> Self {
375 self.history.set_limit(limit);
376 self
377 }
378
379 pub fn with_placeholder(mut self, placeholder: impl Into<SharedString>) -> Self {
380 self.placeholder = placeholder.into();
381 self
382 }
383
384 pub fn with_key_context(mut self, context: impl Into<SharedString>) -> Self {
410 self.key_context = Some(context.into());
411 self
412 }
413
414 pub fn with_frame(mut self, frame: bool) -> Self {
417 self.frame = frame;
418 self
419 }
420
421 pub fn with_metrics(mut self, metrics: Metrics) -> Self {
425 self.metrics = metrics;
426 self
427 }
428
429 pub fn set_metrics(&mut self, metrics: Metrics, cx: &mut Context<Self>) {
431 if self.metrics != metrics {
432 self.metrics = metrics;
433 cx.notify();
434 }
435 }
436
437 pub fn with_shape(mut self, shape: Shape) -> Self {
438 self.shape = shape;
439 self
440 }
441
442 pub fn shape(&self) -> Shape {
443 self.shape
444 }
445
446 pub fn content(&self) -> &SharedString {
447 &self.content
448 }
449
450 pub fn spans(&self) -> &[(Range<usize>, HighlightKind)] {
452 &self.spans
453 }
454
455 pub fn set_content(&mut self, content: impl Into<SharedString>, cx: &mut Context<Self>) {
457 self.content = normalize(&content.into(), self.shape).into();
458 self.spans.clear();
460 self.history.clear();
463 self.last_edit = None;
464 let end = self.content.len();
465 self.selected_range = end..end;
466 self.marked_range = None;
467 cx.emit(FieldEvent::Changed);
468 cx.notify();
469 }
470
471 pub fn clear(&mut self, cx: &mut Context<Self>) {
472 self.set_content("", cx);
473 }
474
475 pub fn set_spans(&mut self, spans: Vec<(Range<usize>, HighlightKind)>, cx: &mut Context<Self>) {
489 self.spans = spans;
490 cx.notify();
491 }
492
493 pub fn set_placeholder(
497 &mut self,
498 placeholder: impl Into<SharedString>,
499 cx: &mut Context<Self>,
500 ) {
501 self.placeholder = placeholder.into();
502 cx.notify();
503 }
504
505 fn caret_moved(&mut self) {
509 self.follow_caret = true;
510 self.blink = None;
511 }
512
513 fn start_blink(&mut self, cx: &mut Context<Self>) {
515 self.caret_on = true;
516 self.blink = Some(cx.spawn(async move |field, cx| {
517 loop {
518 cx.background_executor().timer(BLINK).await;
519 let flipped = field.update(cx, |field, cx| {
520 field.caret_on = !field.caret_on;
521 cx.notify();
522 });
523 if flipped.is_err() {
524 break;
525 }
526 }
527 }));
528 }
529
530 pub fn cursor(&self) -> usize {
536 self.cursor_offset()
537 }
538
539 pub fn offset_bounds(&self, offset: usize) -> Option<Bounds<Pixels>> {
550 self.row_bounds(self.text_origin()?, offset..offset, self.line_height())
551 }
552
553 fn row_bounds(
560 &self,
561 origin: Point<Pixels>,
562 range: Range<usize>,
563 line_height: Pixels,
564 ) -> Option<Bounds<Pixels>> {
565 let start = position_for_offset(&self.last_layout, range.start, line_height)?;
566 let end = position_for_offset(&self.last_layout, range.end, line_height)?;
567 Some(Bounds::from_corners(
568 origin + start,
569 origin + gpui::point(end.x, end.y + line_height),
570 ))
571 }
572
573 fn left(&mut self, _: &Left, _: &mut Window, cx: &mut Context<Self>) {
574 if self.selected_range.is_empty() {
575 self.move_to(self.previous_boundary(self.cursor_offset()), cx);
576 } else {
577 self.move_to(self.selected_range.start, cx)
578 }
579 }
580
581 fn right(&mut self, _: &Right, _: &mut Window, cx: &mut Context<Self>) {
582 if self.selected_range.is_empty() {
583 self.move_to(self.next_boundary(self.selected_range.end), cx);
584 } else {
585 self.move_to(self.selected_range.end, cx)
586 }
587 }
588
589 fn select_left(&mut self, _: &SelectLeft, _: &mut Window, cx: &mut Context<Self>) {
590 self.select_to(self.previous_boundary(self.cursor_offset()), cx);
591 }
592
593 fn select_right(&mut self, _: &SelectRight, _: &mut Window, cx: &mut Context<Self>) {
594 self.select_to(self.next_boundary(self.cursor_offset()), cx);
595 }
596
597 fn select_all(&mut self, _: &SelectAll, _: &mut Window, cx: &mut Context<Self>) {
598 self.move_to(0, cx);
599 self.select_to(self.content.len(), cx)
600 }
601
602 fn home(&mut self, _: &Home, _: &mut Window, cx: &mut Context<Self>) {
603 self.move_to(line_start(&self.content, self.cursor_offset()), cx);
604 }
605
606 fn end(&mut self, _: &End, _: &mut Window, cx: &mut Context<Self>) {
607 self.move_to(line_end(&self.content, self.cursor_offset()), cx);
608 }
609
610 fn select_home(&mut self, _: &SelectHome, _: &mut Window, cx: &mut Context<Self>) {
611 self.select_to(line_start(&self.content, self.cursor_offset()), cx);
612 }
613
614 fn select_end(&mut self, _: &SelectEnd, _: &mut Window, cx: &mut Context<Self>) {
615 self.select_to(line_end(&self.content, self.cursor_offset()), cx);
616 }
617
618 fn up(&mut self, _: &Up, _: &mut Window, cx: &mut Context<Self>) {
619 self.vertical(-1, false, cx);
620 }
621
622 fn down(&mut self, _: &Down, _: &mut Window, cx: &mut Context<Self>) {
623 self.vertical(1, false, cx);
624 }
625
626 fn select_up(&mut self, _: &SelectUp, _: &mut Window, cx: &mut Context<Self>) {
627 self.vertical(-1, true, cx);
628 }
629
630 fn select_down(&mut self, _: &SelectDown, _: &mut Window, cx: &mut Context<Self>) {
631 self.vertical(1, true, cx);
632 }
633
634 fn vertical(&mut self, rows: i32, extend: bool, cx: &mut Context<Self>) {
643 if self.last_layout.is_empty() {
644 return;
645 }
646 let line_height = self.line_height();
647 let Some(at) = position_for_offset(&self.last_layout, self.cursor_offset(), line_height)
648 else {
649 return;
650 };
651 let goal = self.goal_x.unwrap_or(at.x);
652 let target = at.y + line_height * rows as f32;
653 let offset = if target < px(0.) {
656 0
657 } else {
658 offset_for_position(&self.last_layout, gpui::point(goal, target), line_height)
659 };
660
661 if extend {
662 self.select_to(offset, cx);
663 } else {
664 self.move_to(offset, cx);
665 }
666 self.goal_x = Some(goal);
668 }
669
670 fn insert_newline(&mut self, _: &InsertNewline, window: &mut Window, cx: &mut Context<Self>) {
673 if self.shape.is_multiline() {
674 self.replace_text_in_range(None, "\n", window, cx);
675 }
676 }
677
678 fn word_left(&mut self, _: &WordLeft, _: &mut Window, cx: &mut Context<Self>) {
679 self.move_to(
680 previous_word_boundary(&self.content, self.cursor_offset()),
681 cx,
682 );
683 }
684
685 fn word_right(&mut self, _: &WordRight, _: &mut Window, cx: &mut Context<Self>) {
686 self.move_to(next_word_boundary(&self.content, self.cursor_offset()), cx);
687 }
688
689 fn select_word_left(&mut self, _: &SelectWordLeft, _: &mut Window, cx: &mut Context<Self>) {
690 self.select_to(
691 previous_word_boundary(&self.content, self.cursor_offset()),
692 cx,
693 );
694 }
695
696 fn select_word_right(&mut self, _: &SelectWordRight, _: &mut Window, cx: &mut Context<Self>) {
697 self.select_to(next_word_boundary(&self.content, self.cursor_offset()), cx);
698 }
699
700 fn delete_word_left(
704 &mut self,
705 _: &DeleteWordLeft,
706 window: &mut Window,
707 cx: &mut Context<Self>,
708 ) {
709 if self.selected_range.is_empty() {
710 self.select_to(
711 previous_word_boundary(&self.content, self.cursor_offset()),
712 cx,
713 );
714 }
715 self.replace_text_in_range(None, "", window, cx)
716 }
717
718 fn delete_word_right(
719 &mut self,
720 _: &DeleteWordRight,
721 window: &mut Window,
722 cx: &mut Context<Self>,
723 ) {
724 if self.selected_range.is_empty() {
725 self.select_to(next_word_boundary(&self.content, self.cursor_offset()), cx);
726 }
727 self.replace_text_in_range(None, "", window, cx)
728 }
729
730 fn delete_to_line_start(
731 &mut self,
732 _: &DeleteToLineStart,
733 window: &mut Window,
734 cx: &mut Context<Self>,
735 ) {
736 if self.selected_range.is_empty() {
737 self.select_to(line_start(&self.content, self.cursor_offset()), cx);
738 }
739 self.replace_text_in_range(None, "", window, cx)
740 }
741
742 fn delete_to_line_end(
743 &mut self,
744 _: &DeleteToLineEnd,
745 window: &mut Window,
746 cx: &mut Context<Self>,
747 ) {
748 if self.selected_range.is_empty() {
749 self.select_to(line_end(&self.content, self.cursor_offset()), cx);
750 }
751 self.replace_text_in_range(None, "", window, cx)
752 }
753
754 fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
755 if self.selected_range.is_empty() {
756 let prev = self.previous_boundary(self.cursor_offset());
757 if self.cursor_offset() == prev {
758 return;
759 }
760 self.select_to(prev, cx)
761 }
762 self.replace_text_in_range(None, "", window, cx)
763 }
764
765 fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
766 if self.selected_range.is_empty() {
767 let next = self.next_boundary(self.cursor_offset());
768 if self.cursor_offset() == next {
769 return;
770 }
771 self.select_to(next, cx)
772 }
773 self.replace_text_in_range(None, "", window, cx)
774 }
775
776 fn on_mouse_down(
777 &mut self,
778 event: &MouseDownEvent,
779 _window: &mut Window,
780 cx: &mut Context<Self>,
781 ) {
782 self.is_selecting = true;
783 let offset = self.index_for_mouse_position(event.position, self.line_height());
784 if event.modifiers.shift {
785 self.select_to(offset, cx);
786 } else {
787 self.move_to(offset, cx)
788 }
789 }
790
791 fn on_mouse_up(&mut self, _: &MouseUpEvent, _: &mut Window, _: &mut Context<Self>) {
792 self.is_selecting = false;
793 }
794
795 fn on_scroll_wheel(
799 &mut self,
800 event: &gpui::ScrollWheelEvent,
801 _window: &mut Window,
802 cx: &mut Context<Self>,
803 ) {
804 let delta = event.delta.pixel_delta(self.line_height());
805 self.scroll.x = (self.scroll.x - delta.x).max(px(0.));
806 self.scroll.y = (self.scroll.y - delta.y).max(px(0.));
807 cx.notify();
808 }
809
810 fn drag_to(&mut self, position: Point<Pixels>, line_height: Pixels, cx: &mut Context<Self>) {
814 if !self.is_selecting {
815 return;
816 }
817 let offset = self.index_for_mouse_position(position, line_height);
818 if offset != self.cursor_offset() {
821 self.select_to(offset, cx);
822 }
823 }
824
825 fn show_character_palette(
826 &mut self,
827 _: &ShowCharacterPalette,
828 window: &mut Window,
829 _: &mut Context<Self>,
830 ) {
831 window.show_character_palette();
832 }
833
834 fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
835 if let Some(text) = cx.read_from_clipboard().and_then(|item| item.text()) {
836 self.replace_text_in_range(None, &normalize(&text, self.shape), window, cx);
837 }
838 }
839
840 fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
841 if !self.selected_range.is_empty() {
842 cx.write_to_clipboard(ClipboardItem::new_string(
843 self.content[self.selected_range.clone()].to_string(),
844 ));
845 }
846 }
847
848 fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
849 if !self.selected_range.is_empty() {
850 cx.write_to_clipboard(ClipboardItem::new_string(
851 self.content[self.selected_range.clone()].to_string(),
852 ));
853 self.replace_text_in_range(None, "", window, cx)
854 }
855 }
856
857 fn snapshot(&self) -> Snapshot {
858 Snapshot {
859 content: self.content.clone(),
860 selection: self.selected_range.clone(),
861 reversed: self.selection_reversed,
862 }
863 }
864
865 fn restore(&mut self, point: Snapshot, cx: &mut Context<Self>) {
866 self.content = point.content;
867 self.selected_range = point.selection;
868 self.selection_reversed = point.reversed;
869 self.marked_range = None;
870 self.last_edit = None;
872 self.caret_moved();
873 cx.emit(FieldEvent::Changed);
874 cx.notify();
875 }
876
877 fn push_undo(&mut self, kind: EditKind, at: usize) {
883 let before = (!joins_group(self.last_edit, kind, at)).then(|| self.snapshot());
884 self.history.record(before);
885 }
886
887 fn undo(&mut self, _: &Undo, _: &mut Window, cx: &mut Context<Self>) {
888 let current = self.snapshot();
889 if let Some(point) = self.history.undo(|| current) {
890 self.restore(point, cx);
891 }
892 }
893
894 fn redo(&mut self, _: &Redo, _: &mut Window, cx: &mut Context<Self>) {
895 let current = self.snapshot();
896 if let Some(point) = self.history.redo(|| current) {
897 self.restore(point, cx);
898 }
899 }
900
901 fn move_to(&mut self, offset: usize, cx: &mut Context<Self>) {
902 self.selected_range = offset..offset;
903 self.goal_x = None;
904 self.caret_moved();
905 cx.emit(FieldEvent::Moved);
906 cx.notify()
907 }
908
909 fn cursor_offset(&self) -> usize {
910 if self.selection_reversed {
911 self.selected_range.start
912 } else {
913 self.selected_range.end
914 }
915 }
916
917 fn line_height(&self) -> Pixels {
928 px(self.metrics.line_height())
929 }
930
931 fn text_origin(&self) -> Option<Point<Pixels>> {
934 Some(self.last_bounds?.origin - self.scroll)
935 }
936
937 fn index_for_mouse_position(&self, position: Point<Pixels>, line_height: Pixels) -> usize {
938 if self.content.is_empty() || self.last_layout.is_empty() {
939 return 0;
940 }
941 let Some(origin) = self.text_origin() else {
942 return 0;
943 };
944 offset_for_position(&self.last_layout, position - origin, line_height)
945 }
946
947 fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
948 self.goal_x = None;
949 self.caret_moved();
950 if self.selection_reversed {
951 self.selected_range.start = offset
952 } else {
953 self.selected_range.end = offset
954 };
955 if self.selected_range.end < self.selected_range.start {
956 self.selection_reversed = !self.selection_reversed;
957 self.selected_range = self.selected_range.end..self.selected_range.start;
958 }
959 cx.emit(FieldEvent::Moved);
960 cx.notify()
961 }
962
963 fn offset_to_utf16(&self, offset: usize) -> usize {
964 offset_to_utf16(&self.content, offset)
965 }
966
967 fn range_to_utf16(&self, range: &Range<usize>) -> Range<usize> {
968 range_to_utf16(&self.content, range.clone())
969 }
970
971 fn range_from_utf16(&self, range_utf16: &Range<usize>) -> Range<usize> {
972 range_from_utf16(&self.content, range_utf16.clone())
973 }
974
975 fn previous_boundary(&self, offset: usize) -> usize {
976 previous_boundary(&self.content, offset)
977 }
978
979 fn next_boundary(&self, offset: usize) -> usize {
980 next_boundary(&self.content, offset)
981 }
982}
983
984pub fn offset_from_utf16(text: &str, offset: usize) -> usize {
991 let mut utf8_offset = 0;
992 let mut utf16_count = 0;
993 for ch in text.chars() {
994 if utf16_count >= offset {
995 break;
996 }
997 utf16_count += ch.len_utf16();
998 utf8_offset += ch.len_utf8();
999 }
1000 utf8_offset
1001}
1002
1003pub fn offset_to_utf16(text: &str, offset: usize) -> usize {
1005 let mut utf16_offset = 0;
1006 let mut utf8_count = 0;
1007 for ch in text.chars() {
1008 if utf8_count >= offset {
1009 break;
1010 }
1011 utf8_count += ch.len_utf8();
1012 utf16_offset += ch.len_utf16();
1013 }
1014 utf16_offset
1015}
1016
1017pub fn range_from_utf16(text: &str, range: Range<usize>) -> Range<usize> {
1019 offset_from_utf16(text, range.start)..offset_from_utf16(text, range.end)
1020}
1021
1022pub fn range_to_utf16(text: &str, range: Range<usize>) -> Range<usize> {
1024 offset_to_utf16(text, range.start)..offset_to_utf16(text, range.end)
1025}
1026
1027pub fn composition_selection(
1029 text: &str,
1030 start: usize,
1031 selection: Option<Range<usize>>,
1032) -> Range<usize> {
1033 let range = selection
1034 .map(|range| range_from_utf16(text, range))
1035 .unwrap_or(text.len()..text.len());
1036 start + range.start..start + range.end
1037}
1038
1039pub fn previous_boundary(text: &str, offset: usize) -> usize {
1043 text.grapheme_indices(true)
1044 .rev()
1045 .find_map(|(idx, _)| (idx < offset).then_some(idx))
1046 .unwrap_or(0)
1047}
1048
1049pub fn next_boundary(text: &str, offset: usize) -> usize {
1051 text.grapheme_indices(true)
1052 .find_map(|(idx, _)| (idx > offset).then_some(idx))
1053 .unwrap_or(text.len())
1054}
1055
1056pub fn joins_group(last: Option<(EditKind, usize)>, kind: EditKind, at: usize) -> bool {
1064 last.is_some_and(|(last_kind, offset)| last_kind == kind && at == offset)
1065}
1066
1067pub fn normalize(text: &str, shape: Shape) -> String {
1077 let text = text.replace("\r\n", "\n").replace('\r', "\n");
1078 if shape.is_multiline() {
1079 text
1080 } else {
1081 text.replace('\n', " ")
1082 }
1083}
1084
1085pub fn line_start(text: &str, offset: usize) -> usize {
1094 text[..offset].rfind('\n').map_or(0, |at| at + 1)
1095}
1096
1097pub fn line_end(text: &str, offset: usize) -> usize {
1099 text[offset..]
1100 .find('\n')
1101 .map_or(text.len(), |at| offset + at)
1102}
1103
1104fn is_word(segment: &str) -> bool {
1107 segment.chars().any(char::is_alphanumeric)
1108}
1109
1110pub fn previous_word_boundary(text: &str, offset: usize) -> usize {
1118 text.split_word_bound_indices()
1119 .filter(|(start, _)| *start < offset)
1120 .rfind(|(_, segment)| is_word(segment))
1121 .map(|(start, _)| start)
1122 .unwrap_or(0)
1123}
1124
1125pub fn next_word_boundary(text: &str, offset: usize) -> usize {
1127 text.split_word_bound_indices()
1128 .filter(|(start, segment)| start + segment.len() > offset)
1129 .find(|(_, segment)| is_word(segment))
1130 .map(|(start, segment)| start + segment.len())
1131 .unwrap_or(text.len())
1132}
1133
1134fn display_text(field: &TextField) -> (SharedString, bool) {
1137 if field.content.is_empty() {
1138 (field.placeholder.clone(), true)
1139 } else {
1140 (field.content.clone(), false)
1141 }
1142}
1143
1144pub fn coloured(
1159 text: &str,
1160 spans: &[(Range<usize>, HighlightKind)],
1161 base: &TextRun,
1162 palette: &SyntaxPalette,
1163) -> Vec<TextRun> {
1164 if spans.is_empty() {
1165 return vec![TextRun {
1166 len: text.len(),
1167 ..base.clone()
1168 }];
1169 }
1170 let mut runs = Vec::with_capacity(spans.len() * 2 + 1);
1171 let mut at = 0;
1172 for (range, kind) in spans {
1173 if range.start < at
1174 || range.end <= range.start
1175 || range.end > text.len()
1176 || !text.is_char_boundary(range.start)
1177 || !text.is_char_boundary(range.end)
1178 {
1179 continue;
1180 }
1181 if range.start > at {
1182 runs.push(TextRun {
1183 len: range.start - at,
1184 ..base.clone()
1185 });
1186 }
1187 runs.push(TextRun {
1188 len: range.end - range.start,
1189 color: palette.color(*kind),
1190 ..base.clone()
1191 });
1192 at = range.end;
1193 }
1194 if at < text.len() {
1195 runs.push(TextRun {
1196 len: text.len() - at,
1197 ..base.clone()
1198 });
1199 }
1200 runs
1201}
1202
1203pub fn underlined(runs: Vec<TextRun>, marked: &Range<usize>) -> Vec<TextRun> {
1207 let mut out = Vec::with_capacity(runs.len() + 2);
1208 let mut at = 0;
1209 for run in runs {
1210 let end = at + run.len;
1211 for (start, stop, mark) in [
1212 (at, end.min(marked.start), false),
1213 (at.max(marked.start), end.min(marked.end), true),
1214 (at.max(marked.end), end, false),
1215 ] {
1216 if stop <= start {
1217 continue;
1218 }
1219 out.push(TextRun {
1220 len: stop - start,
1221 underline: mark.then(|| UnderlineStyle {
1222 color: Some(run.color),
1223 thickness: px(1.0),
1224 wavy: false,
1225 }),
1226 ..run.clone()
1227 });
1228 }
1229 at = end;
1230 }
1231 out
1232}
1233
1234fn lines_from(lines: &[WrappedLine]) -> impl Iterator<Item = (usize, &WrappedLine)> {
1243 lines.iter().scan(0usize, |start, line| {
1244 let at = *start;
1245 *start = at + line.len() + 1;
1246 Some((at, line))
1247 })
1248}
1249
1250fn rows(lines: &[WrappedLine], line_height: Pixels) -> Vec<(Range<usize>, Pixels)> {
1255 let mut out = Vec::new();
1256 let mut top = px(0.);
1257 for (start, line) in lines_from(lines) {
1258 let mut row_start = start;
1259 for boundary in line.wrap_boundaries() {
1260 let at = start + line.runs()[boundary.run_ix].glyphs[boundary.glyph_ix].index;
1261 out.push((row_start..at, top));
1262 row_start = at;
1263 top += line_height;
1264 }
1265 out.push((row_start..start + line.len(), top));
1266 top += line_height;
1267 }
1268 out
1269}
1270
1271fn position_for_offset(
1273 lines: &[WrappedLine],
1274 offset: usize,
1275 line_height: Pixels,
1276) -> Option<Point<Pixels>> {
1277 let mut top = px(0.);
1278 for (start, line) in lines_from(lines) {
1279 if offset <= start + line.len() {
1280 let local = line.position_for_index(offset.saturating_sub(start), line_height)?;
1281 return Some(gpui::point(local.x, local.y + top));
1282 }
1283 top += line.size(line_height).height;
1284 }
1285 None
1286}
1287
1288fn offset_for_position(
1290 lines: &[WrappedLine],
1291 position: Point<Pixels>,
1292 line_height: Pixels,
1293) -> usize {
1294 let mut top = px(0.);
1295 let mut last = 0;
1296 for (start, line) in lines_from(lines) {
1297 let height = line.size(line_height).height;
1298 last = start + line.len();
1299 if position.y < top + height {
1300 let local = gpui::point(position.x, position.y - top);
1301 let (Ok(index) | Err(index)) = line.closest_index_for_position(local, line_height);
1302 return start + index;
1303 }
1304 top += height;
1305 }
1306 last
1307}
1308
1309fn selection_rows(
1315 lines: &[WrappedLine],
1316 range: &Range<usize>,
1317 line_height: Pixels,
1318) -> Vec<Bounds<Pixels>> {
1319 rows(lines, line_height)
1320 .into_iter()
1321 .filter(|(row, _)| range.start <= row.end && range.end >= row.start)
1322 .filter_map(|(row, top)| {
1323 let left = if range.start <= row.start {
1324 px(0.)
1325 } else {
1326 position_for_offset(lines, range.start, line_height)?.x
1327 };
1328 let right = position_for_offset(lines, range.end.min(row.end), line_height)?.x;
1329 (right > left).then(|| {
1330 Bounds::from_corners(
1331 gpui::point(left, top),
1332 gpui::point(right, top + line_height),
1333 )
1334 })
1335 })
1336 .collect()
1337}
1338
1339impl EntityInputHandler for TextField {
1340 fn text_for_range(
1341 &mut self,
1342 range_utf16: Range<usize>,
1343 actual_range: &mut Option<Range<usize>>,
1344 _window: &mut Window,
1345 _cx: &mut Context<Self>,
1346 ) -> Option<String> {
1347 let range = self.range_from_utf16(&range_utf16);
1348 actual_range.replace(self.range_to_utf16(&range));
1349 Some(self.content[range].to_string())
1350 }
1351
1352 fn selected_text_range(
1353 &mut self,
1354 _ignore_disabled_input: bool,
1355 _window: &mut Window,
1356 _cx: &mut Context<Self>,
1357 ) -> Option<UTF16Selection> {
1358 Some(UTF16Selection {
1359 range: self.range_to_utf16(&self.selected_range),
1360 reversed: self.selection_reversed,
1361 })
1362 }
1363
1364 fn marked_text_range(
1365 &self,
1366 _window: &mut Window,
1367 _cx: &mut Context<Self>,
1368 ) -> Option<Range<usize>> {
1369 self.marked_range
1370 .as_ref()
1371 .map(|range| self.range_to_utf16(range))
1372 }
1373
1374 fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
1375 self.marked_range = None;
1376 }
1377
1378 fn replace_text_in_range(
1379 &mut self,
1380 range_utf16: Option<Range<usize>>,
1381 new_text: &str,
1382 _: &mut Window,
1383 cx: &mut Context<Self>,
1384 ) {
1385 let range = range_utf16
1386 .as_ref()
1387 .map(|range_utf16| self.range_from_utf16(range_utf16))
1388 .or(self.marked_range.clone())
1389 .unwrap_or(self.selected_range.clone());
1390
1391 let kind = if new_text.is_empty() {
1396 EditKind::Delete
1397 } else {
1398 EditKind::Insert
1399 };
1400 self.push_undo(
1403 kind,
1404 if new_text.is_empty() {
1405 range.end
1406 } else {
1407 range.start
1408 },
1409 );
1410
1411 self.content =
1412 (self.content[0..range.start].to_owned() + new_text + &self.content[range.end..])
1413 .into();
1414 self.selected_range = range.start + new_text.len()..range.start + new_text.len();
1415 self.marked_range.take();
1416 self.last_edit = Some((kind, self.selected_range.end));
1417 self.caret_moved();
1418 cx.emit(FieldEvent::Changed);
1419 cx.notify();
1420 }
1421
1422 fn replace_and_mark_text_in_range(
1423 &mut self,
1424 range_utf16: Option<Range<usize>>,
1425 new_text: &str,
1426 new_selected_range_utf16: Option<Range<usize>>,
1427 _window: &mut Window,
1428 cx: &mut Context<Self>,
1429 ) {
1430 let range = range_utf16
1431 .as_ref()
1432 .map(|range_utf16| self.range_from_utf16(range_utf16))
1433 .or(self.marked_range.clone())
1434 .unwrap_or(self.selected_range.clone());
1435
1436 self.content =
1437 (self.content[0..range.start].to_owned() + new_text + &self.content[range.end..])
1438 .into();
1439 self.marked_range =
1440 (!new_text.is_empty()).then(|| range.start..range.start + new_text.len());
1441 self.selected_range =
1442 composition_selection(new_text, range.start, new_selected_range_utf16);
1443 self.selection_reversed = false;
1444
1445 self.caret_moved();
1446 cx.emit(FieldEvent::Changed);
1447 cx.notify();
1448 }
1449
1450 fn bounds_for_range(
1451 &mut self,
1452 range_utf16: Range<usize>,
1453 bounds: Bounds<Pixels>,
1454 _window: &mut Window,
1455 _cx: &mut Context<Self>,
1456 ) -> Option<Bounds<Pixels>> {
1457 let range = self.range_from_utf16(&range_utf16);
1458 self.row_bounds(bounds.origin - self.scroll, range, self.line_height())
1463 }
1464
1465 fn character_index_for_point(
1466 &mut self,
1467 point: Point<Pixels>,
1468 _window: &mut Window,
1469 _cx: &mut Context<Self>,
1470 ) -> Option<usize> {
1471 self.last_bounds?.localize(&point)?;
1472 let origin = self.text_origin()?;
1473 let offset = offset_for_position(&self.last_layout, point - origin, self.line_height());
1474 Some(self.offset_to_utf16(offset))
1475 }
1476}
1477
1478impl Focusable for TextField {
1479 fn focus_handle(&self, _: &App) -> FocusHandle {
1480 self.focus_handle.clone()
1481 }
1482}
1483
1484impl Render for TextField {
1485 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
1486 if self.focus_handle.is_focused(_window) && caret_blink(cx) {
1489 if self.blink.is_none() {
1490 self.start_blink(cx);
1491 }
1492 } else {
1493 self.blink = None;
1494 self.caret_on = true;
1495 }
1496 let theme = Theme::of(cx);
1497 let mut key_context = gpui::KeyContext::default();
1498 key_context.add(KEY_CONTEXT);
1499 if self.shape.is_multiline() {
1500 key_context.add(MULTILINE_KEY_CONTEXT);
1501 }
1502 if let Some(extra) = self.key_context.clone() {
1503 key_context.add(extra);
1504 }
1505 div()
1506 .key_context(key_context)
1507 .track_focus(&self.focus_handle(cx))
1508 .cursor(CursorStyle::IBeam)
1509 .on_action(cx.listener(Self::backspace))
1510 .on_action(cx.listener(Self::delete))
1511 .on_action(cx.listener(Self::left))
1512 .on_action(cx.listener(Self::right))
1513 .on_action(cx.listener(Self::select_left))
1514 .on_action(cx.listener(Self::select_right))
1515 .on_action(cx.listener(Self::select_all))
1516 .on_action(cx.listener(Self::home))
1517 .on_action(cx.listener(Self::end))
1518 .on_action(cx.listener(Self::select_home))
1519 .on_action(cx.listener(Self::select_end))
1520 .on_action(cx.listener(Self::word_left))
1521 .on_action(cx.listener(Self::word_right))
1522 .on_action(cx.listener(Self::select_word_left))
1523 .on_action(cx.listener(Self::select_word_right))
1524 .on_action(cx.listener(Self::up))
1525 .on_action(cx.listener(Self::down))
1526 .on_action(cx.listener(Self::select_up))
1527 .on_action(cx.listener(Self::select_down))
1528 .on_action(cx.listener(Self::insert_newline))
1529 .on_action(cx.listener(Self::undo))
1530 .on_action(cx.listener(Self::redo))
1531 .on_action(cx.listener(Self::delete_word_left))
1532 .on_action(cx.listener(Self::delete_word_right))
1533 .on_action(cx.listener(Self::delete_to_line_start))
1534 .on_action(cx.listener(Self::delete_to_line_end))
1535 .on_action(cx.listener(Self::show_character_palette))
1536 .on_action(cx.listener(Self::paste))
1537 .on_action(cx.listener(Self::cut))
1538 .on_action(cx.listener(Self::copy))
1539 .on_mouse_down(MouseButton::Left, cx.listener(Self::on_mouse_down))
1540 .on_mouse_up(MouseButton::Left, cx.listener(Self::on_mouse_up))
1541 .on_mouse_up_out(MouseButton::Left, cx.listener(Self::on_mouse_up))
1542 .on_scroll_wheel(cx.listener(Self::on_scroll_wheel))
1543 .w_full()
1544 .when(self.frame, |field| {
1545 field
1546 .px(px(10.0))
1547 .py(px(7.0))
1548 .rounded(px(Theme::button_radius()))
1549 .bg(theme.input_bg)
1550 .border_1()
1551 .border_color(if self.focus_handle.is_focused(_window) {
1552 theme.ring
1553 } else {
1554 theme.border
1555 })
1556 })
1557 .text_size(px(self.metrics.size()))
1558 .font_weight(self.metrics.weight)
1559 .line_height(px(self.metrics.line_height()))
1560 .text_color(theme.text)
1561 .child(TextFieldElement { field: cx.entity() })
1562 }
1563}
1564
1565struct TextFieldElement {
1569 field: Entity<TextField>,
1570}
1571
1572struct FieldPrepaint {
1573 lines: Vec<WrappedLine>,
1574 origin: Point<Pixels>,
1576 cursor: Option<PaintQuad>,
1577 selection: Vec<PaintQuad>,
1579}
1580
1581impl IntoElement for TextFieldElement {
1582 type Element = Self;
1583
1584 fn into_element(self) -> Self::Element {
1585 self
1586 }
1587}
1588
1589impl Element for TextFieldElement {
1590 type RequestLayoutState = ();
1591 type PrepaintState = FieldPrepaint;
1592
1593 fn id(&self) -> Option<ElementId> {
1594 None
1595 }
1596
1597 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
1598 None
1599 }
1600
1601 fn request_layout(
1602 &mut self,
1603 _id: Option<&GlobalElementId>,
1604 _inspector_id: Option<&gpui::InspectorElementId>,
1605 window: &mut Window,
1606 cx: &mut App,
1607 ) -> (LayoutId, ()) {
1608 let mut style = Style::default();
1609 style.size.width = relative(1.).into();
1610 let field = self.field.read(cx);
1611 let line_height = field.line_height();
1614 let shape = field.shape;
1615
1616 let (min, max) = match shape {
1617 Shape::Line => {
1618 style.size.height = line_height.into();
1619 return (window.request_layout(style, [], cx), ());
1620 }
1621 Shape::Rows(rows) => {
1622 style.size.height = (line_height * rows.max(1) as f32).into();
1623 return (window.request_layout(style, [], cx), ());
1624 }
1625 Shape::Grow { min, max } => (min.max(1), max.max(min.max(1))),
1629 };
1630
1631 let text = display_text(field).0;
1632 let id = window.request_measured_layout(style, move |known, available, window, _cx| {
1633 let text_style = window.text_style();
1634 let font_size = text_style.font_size.to_pixels(window.rem_size());
1635 let wrap_width = known.width.or(match available.width {
1640 gpui::AvailableSpace::Definite(width) => Some(width),
1641 _ => None,
1642 });
1643 let run = TextRun {
1644 len: text.len(),
1645 font: text_style.font(),
1646 color: text_style.color,
1647 background_color: None,
1648 underline: None,
1649 strikethrough: None,
1650 };
1651 let count = window
1652 .text_system()
1653 .shape_text(text.clone(), font_size, &[run], wrap_width, None)
1654 .map(|lines| {
1655 lines
1656 .iter()
1657 .map(|line| line.wrap_boundaries().len() + 1)
1658 .sum::<usize>()
1659 })
1660 .unwrap_or(1);
1661 gpui::size(
1662 wrap_width.unwrap_or(px(0.)),
1663 line_height * count.clamp(min, max) as f32,
1664 )
1665 });
1666 (id, ())
1667 }
1668
1669 fn prepaint(
1670 &mut self,
1671 _id: Option<&GlobalElementId>,
1672 _inspector_id: Option<&gpui::InspectorElementId>,
1673 bounds: Bounds<Pixels>,
1674 _request_layout: &mut Self::RequestLayoutState,
1675 window: &mut Window,
1676 cx: &mut App,
1677 ) -> FieldPrepaint {
1678 let theme = Theme::of(cx).clone();
1679 let field = self.field.read(cx);
1680 let selected_range = field.selected_range.clone();
1681 let cursor = field.cursor_offset();
1682 let shape = field.shape;
1683 let marked_range = field.marked_range.clone();
1684 let scrolled = field.scroll;
1685 let follow_caret = field.follow_caret;
1686 let style = window.text_style();
1687
1688 let (text, is_placeholder) = display_text(field);
1689 let text_color = if is_placeholder {
1690 theme.text_faint
1691 } else {
1692 style.color
1693 };
1694
1695 let run = TextRun {
1696 len: text.len(),
1697 font: style.font(),
1698 color: text_color,
1699 background_color: None,
1700 underline: None,
1701 strikethrough: None,
1702 };
1703 let runs = if is_placeholder {
1707 vec![run]
1708 } else {
1709 coloured(&text, &field.spans, &run, &theme.syntax)
1710 };
1711 let runs = match marked_range.as_ref() {
1712 Some(marked) => underlined(runs, marked),
1713 None => runs,
1714 };
1715
1716 let font_size = style.font_size.to_pixels(window.rem_size());
1717 let line_height = field.line_height();
1718 let wrap_width = shape.is_multiline().then_some(bounds.size.width);
1721 let lines = window
1722 .text_system()
1723 .shape_text(text, font_size, &runs, wrap_width, None)
1724 .map(|lines| lines.into_vec())
1725 .unwrap_or_default();
1726
1727 let content_height: Pixels = lines.iter().map(|l| l.size(line_height).height).sum();
1736 let content_width = lines.iter().map(|l| l.width()).fold(px(0.), Pixels::max);
1737 let max = gpui::point(
1738 (content_width - bounds.size.width).max(px(0.)),
1739 (content_height - bounds.size.height).max(px(0.)),
1740 );
1741 let mut scroll = gpui::point(
1742 scrolled.x.clamp(px(0.), max.x),
1743 scrolled.y.clamp(px(0.), max.y),
1744 );
1745 if follow_caret && let Some(at) = position_for_offset(&lines, cursor, line_height) {
1746 if at.y < scroll.y {
1747 scroll.y = at.y;
1748 } else if at.y + line_height > scroll.y + bounds.size.height {
1749 scroll.y = at.y + line_height - bounds.size.height;
1750 }
1751 if at.x < scroll.x {
1754 scroll.x = at.x;
1755 } else if at.x + CARET_WIDTH > scroll.x + bounds.size.width {
1756 scroll.x = at.x + CARET_WIDTH - bounds.size.width;
1757 }
1758 scroll.x = scroll.x.clamp(px(0.), max.x);
1759 scroll.y = scroll.y.clamp(px(0.), max.y);
1760 }
1761 self.field.update(cx, |field, _| {
1762 field.scroll = scroll;
1763 field.follow_caret = false;
1764 });
1765 let origin = bounds.origin - scroll;
1766
1767 let (selection, cursor) = if selected_range.is_empty() {
1768 let at = position_for_offset(&lines, cursor, line_height).unwrap_or_default();
1769 (
1770 Vec::new(),
1771 Some(fill(
1772 Bounds::new(
1775 origin + at + gpui::point(px(0.), (line_height - font_size) / 2.),
1776 gpui::size(CARET_WIDTH, font_size),
1777 ),
1778 theme.caret,
1779 )),
1780 )
1781 } else {
1782 (
1783 selection_rows(&lines, &selected_range, line_height)
1784 .into_iter()
1785 .map(|rect| {
1786 fill(
1787 Bounds::new(origin + rect.origin, rect.size),
1788 theme.selection,
1789 )
1790 })
1791 .collect(),
1792 None,
1793 )
1794 };
1795
1796 FieldPrepaint {
1797 lines,
1798 origin,
1799 cursor,
1800 selection,
1801 }
1802 }
1803
1804 fn paint(
1805 &mut self,
1806 _id: Option<&GlobalElementId>,
1807 _inspector_id: Option<&gpui::InspectorElementId>,
1808 bounds: Bounds<Pixels>,
1809 _request_layout: &mut Self::RequestLayoutState,
1810 prepaint: &mut Self::PrepaintState,
1811 window: &mut Window,
1812 cx: &mut App,
1813 ) {
1814 let focus_handle = self.field.read(cx).focus_handle.clone();
1815 let caret_on = self.field.read(cx).caret_on;
1816 window.handle_input(
1817 &focus_handle,
1818 ElementInputHandler::new(bounds, self.field.clone()),
1819 cx,
1820 );
1821 let line_height = self.field.read(cx).line_height();
1822 let dragged = self.field.clone();
1832 window.on_mouse_event(move |event: &MouseMoveEvent, phase, _window, cx| {
1833 if phase != DispatchPhase::Bubble || !event.dragging() {
1838 return;
1839 }
1840 dragged.update(cx, |field, cx| {
1841 field.drag_to(event.position, line_height, cx);
1842 });
1843 });
1844 let lines = std::mem::take(&mut prepaint.lines);
1845 let selection = std::mem::take(&mut prepaint.selection);
1846 let cursor = prepaint.cursor.take();
1847 let origin = prepaint.origin;
1848
1849 window.with_content_mask(Some(gpui::ContentMask::new(bounds)), |window| {
1852 for selection in selection {
1853 window.paint_quad(selection);
1854 }
1855
1856 let mut top = origin;
1857 for line in &lines {
1858 line.paint(top, line_height, gpui::TextAlign::Left, None, window, cx)
1859 .ok();
1860 top.y += line.size(line_height).height;
1861 }
1862
1863 if focus_handle.is_focused(window)
1866 && caret_on
1867 && let Some(cursor) = cursor
1868 {
1869 window.paint_quad(cursor);
1870 }
1871 });
1872
1873 self.field.update(cx, |field, _| {
1874 field.last_layout = lines;
1875 field.last_bounds = Some(bounds);
1876 });
1877 }
1878}