1use crate::clipboard;
3use crate::input_method;
4use crate::keyboard;
5use crate::keyboard::key;
6use crate::mouse;
7use crate::renderer;
8use crate::text::highlighter;
9use crate::text::{self, Alignment, LineHeight, Position, Wrapping};
10use crate::time::{Duration, Instant};
11use crate::touch;
12use crate::widget::operation::{Focusable, TextInput};
13use crate::window;
14use crate::{
15 Color, Event, Font, InputMethod, Padding, Pixels, Point, Rectangle, Size, SmolStr, Vector,
16};
17
18use std::borrow::Cow;
19use std::sync::Arc;
20
21pub trait Editor: Sized + Default {
23 fn with_text(text: &str) -> Self;
25
26 fn is_empty(&self) -> bool;
28
29 fn cursor(&self) -> Cursor;
31
32 fn selection(&self) -> Selection;
34
35 fn copy(&self) -> Option<String>;
37
38 fn line(&self, index: usize) -> Option<Line<'_>>;
40
41 fn line_count(&self) -> usize;
43
44 fn perform(&mut self, action: Action);
46
47 fn move_to(&mut self, cursor: Cursor);
49
50 fn bounds(&self) -> Size;
52
53 fn min_bounds(&self) -> Size;
56
57 fn hint_factor(&self) -> Option<f32>;
59
60 fn update(
62 &mut self,
63 new_bounds: Size,
64 new_font: Font,
65 new_size: Pixels,
66 new_line_height: LineHeight,
67 new_wrapping: Wrapping,
68 new_alignment: Alignment,
69 new_hint_factor: Option<f32>,
70 new_parser: &mut impl text::Parser,
71 );
72
73 fn overwrite(&mut self, new_text: &str);
75
76 fn highlight<P: text::Parser>(
78 &mut self,
79 font: Font,
80 parser: &mut P,
81 highlight: impl Fn(P::Output) -> highlighter::Style,
82 );
83
84 fn lines(&self) -> impl Iterator<Item = Line<'_>> {
86 (0..)
87 .map(|i| self.line(i))
88 .take_while(Option::is_some)
89 .flatten()
90 }
91
92 fn text(&self) -> String {
94 let mut contents = String::new();
95 let mut lines = self.lines().peekable();
96
97 while let Some(line) = lines.next() {
98 contents.push_str(&line.text);
99
100 if lines.peek().is_some() {
101 contents.push_str(if line.ending == LineEnding::None {
102 LineEnding::default().as_str()
103 } else {
104 line.ending.as_str()
105 });
106 }
107 }
108
109 contents
110 }
111
112 fn font(&self) -> Font;
114
115 fn text_size(&self) -> Pixels;
117
118 fn line_height(&self) -> LineHeight;
120}
121
122#[derive(Debug, Clone, PartialEq)]
124pub enum Action {
125 Move(Motion),
127 Select(Motion),
129 SelectWord,
131 SelectLine,
133 SelectAll,
135 Edit(Edit),
137 Click(Point, mouse::click::Kind),
139 Drag(Point),
141 Scroll {
143 lines: i32,
145 },
146}
147
148impl Action {
149 pub fn is_edit(&self) -> bool {
151 matches!(self, Self::Edit(_))
152 }
153}
154
155#[derive(Debug, Clone, PartialEq)]
157pub enum Edit {
158 Insert(char),
160 Paste(Arc<String>),
162 Enter,
164 Indent,
166 Unindent,
168 Backspace,
170 BackspaceWord,
172 BackspaceLine,
174 Delete,
176 DeleteWord,
178 DeleteLine,
180 Undo,
182 Redo,
184}
185
186#[derive(Debug, Clone, Copy, PartialEq)]
188pub enum Motion {
189 Left,
191 Right,
193 Up,
195 Down,
197 WordLeft,
199 WordRight,
201 Home,
203 End,
205 PageUp,
207 PageDown,
209 DocumentStart,
211 DocumentEnd,
213}
214
215impl Motion {
216 pub fn widen(self) -> Self {
218 match self {
219 Self::Left => Self::WordLeft,
220 Self::Right => Self::WordRight,
221 Self::Home => Self::DocumentStart,
222 Self::End => Self::DocumentEnd,
223 _ => self,
224 }
225 }
226
227 pub fn direction(&self) -> Direction {
229 match self {
230 Self::Left
231 | Self::Up
232 | Self::WordLeft
233 | Self::Home
234 | Self::PageUp
235 | Self::DocumentStart => Direction::Left,
236 Self::Right
237 | Self::Down
238 | Self::WordRight
239 | Self::End
240 | Self::PageDown
241 | Self::DocumentEnd => Direction::Right,
242 }
243 }
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub enum Direction {
249 Left,
251 Right,
253}
254
255#[derive(Debug, Clone)]
257pub enum Selection {
258 Caret(Point),
260
261 Range(Vec<Rectangle>),
263}
264
265#[derive(Debug, Clone, Copy, PartialEq)]
267pub struct Cursor {
268 pub position: Position,
270
271 pub selection: Option<Position>,
273}
274
275#[derive(Clone, Debug, Default, Eq, PartialEq)]
277pub struct Line<'a> {
278 pub text: Cow<'a, str>,
280 pub ending: LineEnding,
282}
283
284#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
286pub enum LineEnding {
287 #[default]
289 Lf,
290 CrLf,
292 Cr,
294 LfCr,
296 None,
298}
299
300impl LineEnding {
301 pub fn as_str(self) -> &'static str {
303 match self {
304 Self::Lf => "\n",
305 Self::CrLf => "\r\n",
306 Self::Cr => "\r",
307 Self::LfCr => "\n\r",
308 Self::None => "",
309 }
310 }
311}
312
313#[derive(Debug, Clone, Default)]
315pub struct State {
316 focus: Option<Focus>,
317 preedit: Option<input_method::Preedit>,
318 last_click: Option<mouse::Click>,
319 is_dragging: bool,
320 partial_scroll: f32,
321}
322
323impl State {
324 pub fn new() -> Self {
326 Self::default()
327 }
328
329 pub fn update<Message>(
331 &mut self,
332 editor: &impl Editor,
333 event: &Event,
334 bounds: Rectangle,
335 padding: Padding,
336 cursor: mouse::Cursor,
337 key_binding: impl Fn(KeyPress) -> Option<Binding<Message>>,
338 ) -> Option<Update<Message>> {
339 match event {
340 Event::Window(window::Event::Unfocused) => {
341 if let Some(focus) = &mut self.focus {
342 focus.is_window_focused = false;
343 }
344
345 None
346 }
347 Event::Window(window::Event::Focused) => {
348 if let Some(focus) = &mut self.focus {
349 focus.is_window_focused = true;
350 focus.updated_at = Instant::now();
351 }
352
353 Some(Update::Focus)
354 }
355 Event::Window(window::Event::RedrawRequested(now)) => {
356 let focus = self.focus.as_mut()?;
357
358 if !focus.is_window_focused {
359 return None;
360 }
361
362 focus.now = *now;
363
364 let millis_until_redraw = Focus::CURSOR_BLINK_INTERVAL_MILLIS
365 - (focus.now - focus.updated_at).as_millis()
366 % Focus::CURSOR_BLINK_INTERVAL_MILLIS;
367
368 Some(Update::RedrawAt(
369 focus.now + Duration::from_millis(millis_until_redraw as u64),
370 ))
371 }
372 Event::Clipboard(clipboard::Event::Read(Ok(content))) => {
373 let focus = self.focus.as_ref()?;
374
375 if !focus.is_window_focused {
376 return None;
377 }
378
379 let clipboard::Content::Text(text) = content.as_ref() else {
380 return None;
381 };
382
383 Some(Update::Action(Action::Edit(Edit::Paste(Arc::new(
384 text.clone(),
385 )))))
386 }
387 Event::Mouse(event) => match event {
388 mouse::Event::ButtonPressed(mouse::Button::Left) => {
389 if let Some(cursor_position) = cursor.position_in(bounds) {
390 let cursor_position =
391 cursor_position - Vector::new(padding.left, padding.top);
392
393 let click = mouse::Click::new(
394 cursor_position,
395 mouse::Button::Left,
396 self.last_click,
397 );
398
399 self.focus = Some(Focus::now());
400 self.last_click = Some(click);
401 self.is_dragging = true;
402
403 Some(Update::Action(Action::Click(
404 click.position(),
405 click.kind(),
406 )))
407 } else if self.focus.is_some() {
408 self.focus = None;
409
410 Some(Update::Unfocus)
411 } else {
412 None
413 }
414 }
415 mouse::Event::ButtonReleased(mouse::Button::Left) => {
416 self.is_dragging = false;
417
418 Some(Update::Release)
419 }
420 mouse::Event::CursorMoved { .. } if self.is_dragging => {
421 let position = cursor.position_from(bounds.position())?
422 - Vector::new(padding.left, padding.top);
423
424 Some(Update::Action(Action::Drag(position)))
425 }
426 mouse::Event::WheelScrolled { delta } if cursor.is_over(bounds) => {
427 let bounds = editor.bounds();
428
429 if bounds.height >= i32::MAX as f32 {
430 return None;
431 }
432
433 let lines = match delta {
434 mouse::ScrollDelta::Lines { y, .. } => {
435 if y.abs() > 0.0 {
436 y.signum() * -(y.abs() * 4.0).max(1.0)
437 } else {
438 0.0
439 }
440 }
441 mouse::ScrollDelta::Pixels { y, .. } => -y / 4.0,
442 };
443
444 let lines = lines + self.partial_scroll;
445 self.partial_scroll = lines.fract();
446
447 Some(Update::Action(Action::Scroll {
448 lines: lines as i32,
449 }))
450 }
451 _ => None,
452 },
453 Event::Touch(event) => match event {
454 touch::Event::FingerPressed { .. } => {
455 if let Some(cursor_position) = cursor.position_in(bounds) {
456 let cursor_position =
457 cursor_position - Vector::new(padding.left, padding.top);
458
459 let click = mouse::Click::new(
460 cursor_position,
461 mouse::Button::Left,
462 self.last_click,
463 );
464
465 self.focus = Some(Focus::now());
466 self.last_click = Some(click);
467 self.is_dragging = true;
468
469 Some(Update::Action(Action::Click(
470 click.position(),
471 click.kind(),
472 )))
473 } else if self.focus.is_some() {
474 self.focus = None;
475
476 Some(Update::Unfocus)
477 } else {
478 None
479 }
480 }
481 touch::Event::FingerLifted { .. } | touch::Event::FingerLost { .. } => {
482 self.is_dragging = false;
483
484 Some(Update::Release)
485 }
486 touch::Event::FingerMoved { .. } if self.is_dragging => {
487 let position =
488 cursor.position_in(bounds)? - Vector::new(padding.left, padding.top);
489
490 Some(Update::Action(Action::Drag(position)))
491 }
492 touch::Event::FingerMoved { .. } => None,
493 },
494 Event::InputMethod(event) => match event {
495 input_method::Event::Opened | input_method::Event::Closed => {
496 let is_open = matches!(event, input_method::Event::Opened);
497 self.preedit = is_open.then(input_method::Preedit::new);
498
499 Some(Update::InputMethod)
500 }
501 input_method::Event::Preedit(content, selection) if self.focus.is_some() => {
502 self.preedit = Some(input_method::Preedit {
503 content: content.clone(),
504 selection: selection.clone(),
505 text_size: Some(editor.text_size()),
506 });
507
508 Some(Update::InputMethod)
509 }
510 input_method::Event::Commit(content) if self.focus.is_some() => Some(
511 Update::Action(Action::Edit(Edit::Paste(Arc::new(content.clone())))),
512 ),
513 _ => None,
514 },
515 Event::Keyboard(keyboard::Event::KeyPressed {
516 key,
517 modified_key,
518 physical_key,
519 modifiers,
520 text,
521 ..
522 }) => {
523 let key_press = KeyPress {
524 key: key.clone(),
525 modified_key: modified_key.clone(),
526 physical_key: *physical_key,
527 modifiers: *modifiers,
528 text: text.clone(),
529 is_focused: self.is_focused(),
530 };
531
532 fn apply_binding<Message>(
533 binding: Binding<Message>,
534 editor: &impl Editor,
535 state: &mut State,
536 ) -> Option<Update<Message>> {
537 let action = |action| Update::Action(action);
538 let edit = |edit| action(Action::Edit(edit));
539
540 match binding {
541 Binding::Unfocus => {
542 state.focus = None;
543 state.is_dragging = false;
544
545 None
546 }
547 Binding::Copy => {
548 let selection = editor.copy()?;
549
550 Some(Update::Copy(selection))
551 }
552 Binding::Cut => {
553 let selection = editor.copy()?;
554
555 Some(Update::Sequence(vec![
556 Update::Copy(selection),
557 edit(Edit::Backspace),
558 ]))
559 }
560 Binding::Paste => Some(Update::Paste),
561 Binding::Undo => Some(edit(Edit::Undo)),
562 Binding::Redo => Some(edit(Edit::Redo)),
563 Binding::Move(motion) => Some(action(Action::Move(motion))),
564 Binding::Select(motion) => Some(action(Action::Select(motion))),
565 Binding::SelectWord => Some(action(Action::SelectWord)),
566 Binding::SelectLine => Some(action(Action::SelectLine)),
567 Binding::SelectAll => Some(action(Action::SelectAll)),
568 Binding::Insert(c) => Some(edit(Edit::Insert(c))),
569 Binding::Enter => Some(edit(Edit::Enter)),
570 Binding::Backspace => Some(edit(Edit::Backspace)),
571 Binding::BackspaceWord => Some(edit(Edit::BackspaceWord)),
572 Binding::BackspaceLine => Some(edit(Edit::BackspaceLine)),
573 Binding::Delete => Some(action(Action::Edit(Edit::Delete))),
574 Binding::DeleteWord => Some(edit(Edit::DeleteWord)),
575 Binding::DeleteLine => Some(edit(Edit::DeleteLine)),
576 Binding::Sequence(sequence) => {
577 let updates: Vec<_> = sequence
578 .into_iter()
579 .flat_map(|binding| apply_binding(binding, editor, state))
580 .collect();
581
582 if updates.is_empty() {
583 return None;
584 }
585
586 Some(Update::Sequence(updates))
587 }
588 Binding::Custom(message) => Some(Update::Custom(message)),
589 }
590 }
591
592 let update = apply_binding(key_binding(key_press)?, editor, self);
593
594 if let Some(focus) = &mut self.focus {
595 focus.updated_at = Instant::now();
596 }
597
598 update
599 }
600 _ => None,
601 }
602 }
603
604 pub fn input_method<'a>(
606 &'a self,
607 editor: &impl Editor,
608 position: Point,
609 ) -> InputMethod<&'a str> {
610 let Some(Focus {
611 is_window_focused: true,
612 ..
613 }) = &self.focus
614 else {
615 return InputMethod::Disabled;
616 };
617
618 let translation = position - Point::ORIGIN;
619
620 let cursor = match editor.selection() {
621 Selection::Caret(position) => position,
622 Selection::Range(ranges) => ranges.first().cloned().unwrap_or_default().position(),
623 };
624
625 let line_height = editor.line_height().to_absolute(editor.text_size());
626
627 let position = cursor + translation;
628
629 InputMethod::Enabled {
630 cursor: Rectangle::new(position, Size::new(1.0, f32::from(line_height))),
631 purpose: input_method::Purpose::Normal,
632 preedit: self.preedit.as_ref().map(input_method::Preedit::as_ref),
633 }
634 }
635
636 pub fn draw<Renderer: text::Renderer>(
638 &self,
639 editor: &Renderer::Editor,
640 renderer: &mut Renderer,
641 position: Point,
642 clip_bounds: Rectangle,
643 style: Style,
644 ) {
645 let bounds = Rectangle::new(position, editor.bounds());
646
647 let Some(clip_bounds) = clip_bounds.intersection(&bounds) else {
648 return;
649 };
650
651 if !editor.is_empty() {
652 renderer.fill_editor(editor, position, style.value, clip_bounds);
653 }
654
655 if !self.is_focused() {
656 return;
657 }
658
659 let translation = position - Point::ORIGIN;
660 let text_size = editor.text_size();
661 let line_height = editor.line_height();
662
663 match editor.selection() {
664 Selection::Caret(position) if self.is_cursor_visible() => {
665 let cursor = Rectangle::new(
666 position + translation,
667 Size::new(
668 if renderer::CRISP {
669 (1.0 / renderer.hint_factor().unwrap_or(1.0)).max(1.0)
670 } else {
671 1.0
672 },
673 line_height.to_absolute(text_size).into(),
674 ),
675 );
676
677 if let Some(clipped_cursor) = clip_bounds.intersection(&cursor) {
678 renderer.fill_quad(
679 renderer::Quad {
680 bounds: clipped_cursor,
681 ..renderer::Quad::default()
682 },
683 style.value,
684 );
685 }
686 }
687 Selection::Range(ranges) => {
688 for range in ranges
689 .into_iter()
690 .filter_map(|range| clip_bounds.intersection(&(range + translation)))
691 {
692 renderer.fill_quad(
693 renderer::Quad {
694 bounds: range.round(),
695 ..renderer::Quad::default()
696 },
697 style.selection,
698 );
699 }
700 }
701 Selection::Caret(_) => {
702 renderer.fill_quad(renderer::Quad::default(), Color::TRANSPARENT);
704 }
705 }
706 }
707
708 pub fn is_cursor_visible(&self) -> bool {
710 self.focus.as_ref().is_some_and(Focus::is_cursor_visible)
711 }
712}
713
714pub struct Style {
716 pub value: Color,
718
719 pub selection: Color,
721}
722
723#[derive(Debug, Clone)]
724struct Focus {
725 updated_at: Instant,
726 now: Instant,
727 is_window_focused: bool,
728}
729
730impl Focus {
731 const CURSOR_BLINK_INTERVAL_MILLIS: u128 = 500;
732
733 fn now() -> Self {
734 let now = Instant::now();
735
736 Self {
737 updated_at: now,
738 now,
739 is_window_focused: true,
740 }
741 }
742
743 fn is_cursor_visible(&self) -> bool {
744 self.is_window_focused
745 && ((self.now - self.updated_at).as_millis() / Self::CURSOR_BLINK_INTERVAL_MILLIS)
746 .is_multiple_of(2)
747 }
748}
749
750impl State {
751 pub fn is_focused(&self) -> bool {
753 self.focus.is_some()
754 }
755}
756
757impl Focusable for State {
758 fn is_focused(&self) -> bool {
759 self.focus.is_some()
760 }
761
762 fn focus(&mut self) {
763 self.focus = Some(Focus::now());
764 }
765
766 fn unfocus(&mut self) {
767 self.focus = None;
768 }
769}
770
771#[derive(Debug, Clone, PartialEq)]
773pub enum Binding<Message> {
774 Unfocus,
776 Copy,
778 Cut,
780 Paste,
782 Undo,
784 Redo,
786 Move(Motion),
788 Select(Motion),
790 SelectWord,
792 SelectLine,
794 SelectAll,
796 Insert(char),
798 Enter,
800 Backspace,
802 BackspaceWord,
804 BackspaceLine,
806 Delete,
808 DeleteWord,
810 DeleteLine,
812 Sequence(Vec<Self>),
814 Custom(Message),
816}
817
818#[derive(Debug, Clone, PartialEq, Eq)]
820pub struct KeyPress {
821 pub key: keyboard::Key,
825 pub modified_key: keyboard::Key,
829 pub physical_key: keyboard::key::Physical,
833 pub modifiers: keyboard::Modifiers,
835 pub text: Option<SmolStr>,
837 pub is_focused: bool,
839}
840
841impl<Message> Binding<Message> {
842 pub fn from_key_press(event: KeyPress) -> Option<Self> {
844 let KeyPress {
845 key,
846 modified_key,
847 physical_key,
848 modifiers,
849 text,
850 is_focused,
851 } = event;
852
853 if !is_focused {
854 return None;
855 }
856
857 let combination = match key.to_latin(physical_key) {
858 Some('c') if modifiers.command() => Some(Self::Copy),
859 Some('x') if modifiers.command() => Some(Self::Cut),
860 Some('v') if modifiers.command() && !modifiers.alt() => Some(Self::Paste),
861 Some('a') if modifiers.command() => Some(Self::SelectAll),
862 Some('z') if modifiers.command() => Some(Self::Undo),
863 Some('y') if modifiers.command() => Some(Self::Redo),
864 _ => None,
865 };
866
867 if let Some(binding) = combination {
868 return Some(binding);
869 }
870
871 #[cfg(target_os = "macos")]
872 let modified_key = convert_macos_shortcut(&key, modifiers).unwrap_or(modified_key);
873
874 match modified_key.as_ref() {
875 keyboard::Key::Named(key::Named::Enter) => Some(Self::Enter),
876 keyboard::Key::Named(key::Named::Backspace) => Some(
877 if modifiers.macos_command() || (modifiers.command() && modifiers.shift()) {
878 Self::BackspaceLine
879 } else if modifiers.jump() {
880 Self::BackspaceWord
881 } else {
882 Self::Backspace
883 },
884 ),
885 keyboard::Key::Named(key::Named::Delete)
886 if text.is_none() || text.as_deref() == Some("\u{7f}") =>
887 {
888 Some(
889 if modifiers.macos_command() || (modifiers.command() && modifiers.shift()) {
890 Self::DeleteLine
891 } else if modifiers.jump() {
892 Self::DeleteWord
893 } else {
894 Self::Delete
895 },
896 )
897 }
898 keyboard::Key::Named(key::Named::Escape) => Some(Self::Unfocus),
899 _ => {
900 if let Some(text) = text {
901 let c = text.chars().find(|c| !c.is_control())?;
902
903 Some(Self::Insert(c))
904 } else if let keyboard::Key::Named(named_key) = key.as_ref() {
905 let motion = motion(named_key)?;
906
907 let motion = if modifiers.macos_command() {
908 match motion {
909 Motion::Left => Motion::Home,
910 Motion::Right => Motion::End,
911 _ => motion,
912 }
913 } else {
914 motion
915 };
916
917 let motion = if modifiers.jump() {
918 motion.widen()
919 } else {
920 motion
921 };
922
923 Some(if modifiers.shift() {
924 Self::Select(motion)
925 } else {
926 Self::Move(motion)
927 })
928 } else {
929 None
930 }
931 }
932 }
933 }
934}
935
936pub enum Update<Message> {
938 Action(Action),
940 Focus,
942 Unfocus,
944 InputMethod,
946 Release,
948 Copy(String),
950 Paste,
952 RedrawAt(Instant),
954 Custom(Message),
956 Sequence(Vec<Update<Message>>),
958}
959
960fn motion(key: key::Named) -> Option<Motion> {
961 match key {
962 key::Named::ArrowLeft => Some(Motion::Left),
963 key::Named::ArrowRight => Some(Motion::Right),
964 key::Named::ArrowUp => Some(Motion::Up),
965 key::Named::ArrowDown => Some(Motion::Down),
966 key::Named::Home => Some(Motion::Home),
967 key::Named::End => Some(Motion::End),
968 key::Named::PageUp => Some(Motion::PageUp),
969 key::Named::PageDown => Some(Motion::PageDown),
970 _ => None,
971 }
972}
973
974#[cfg(target_os = "macos")]
975fn convert_macos_shortcut(
976 key: &keyboard::Key,
977 modifiers: keyboard::Modifiers,
978) -> Option<keyboard::Key> {
979 if modifiers != keyboard::Modifiers::CTRL {
980 return None;
981 }
982
983 let key = match key.as_ref() {
984 keyboard::Key::Character("b") => key::Named::ArrowLeft,
985 keyboard::Key::Character("f") => key::Named::ArrowRight,
986 keyboard::Key::Character("a") => key::Named::Home,
987 keyboard::Key::Character("e") => key::Named::End,
988 keyboard::Key::Character("h") => key::Named::Backspace,
989 keyboard::Key::Character("d") => key::Named::Delete,
990 _ => return None,
991 };
992
993 Some(keyboard::Key::Named(key))
994}
995
996impl<T: Editor> TextInput for T {
997 fn text(&self) -> text::Fragment<'_> {
998 text::Fragment::Owned(Editor::text(self))
999 }
1000
1001 fn move_cursor_to_front(&mut self) {
1002 self.perform(Action::Move(Motion::DocumentStart));
1003 }
1004
1005 fn move_cursor_to_end(&mut self) {
1006 self.perform(Action::Move(Motion::DocumentEnd));
1007 }
1008
1009 fn move_cursor_to(&mut self, position: text::Position) {
1010 self.move_to(Cursor {
1011 position,
1012 selection: None,
1013 });
1014 }
1015
1016 fn select_all(&mut self) {
1017 self.perform(Action::SelectAll);
1018 }
1019
1020 fn select_range(&mut self, start: text::Position, end: text::Position) {
1021 self.move_to(Cursor {
1022 position: start,
1023 selection: Some(end),
1024 });
1025 }
1026}