@@ -9,9 +9,9 @@ use crate::{core_editor::get_default_clipboard, EditCommand};
9
9
pub struct Editor {
10
10
line_buffer : LineBuffer ,
11
11
cut_buffer : Box < dyn Clipboard > ,
12
-
13
12
edit_stack : EditStack < LineBuffer > ,
14
13
last_undo_behavior : UndoBehavior ,
14
+ selection_anchor : Option < usize > ,
15
15
}
16
16
17
17
impl Default for Editor {
@@ -21,6 +21,7 @@ impl Default for Editor {
21
21
cut_buffer : Box :: new ( get_default_clipboard ( ) ) ,
22
22
edit_stack : EditStack :: new ( ) ,
23
23
last_undo_behavior : UndoBehavior :: CreateUndoPoint ,
24
+ selection_anchor : None ,
24
25
}
25
26
}
26
27
}
@@ -40,28 +41,32 @@ impl Editor {
40
41
41
42
pub ( crate ) fn run_edit_command ( & mut self , command : & EditCommand ) {
42
43
match command {
43
- EditCommand :: MoveToStart => self . line_buffer . move_to_start ( ) ,
44
- EditCommand :: MoveToLineStart => self . line_buffer . move_to_line_start ( ) ,
45
- EditCommand :: MoveToEnd => self . line_buffer . move_to_end ( ) ,
46
- EditCommand :: MoveToLineEnd => self . line_buffer . move_to_line_end ( ) ,
47
- EditCommand :: MoveToPosition ( pos) => self . line_buffer . set_insertion_point ( * pos) ,
48
- EditCommand :: MoveLeft => self . line_buffer . move_left ( ) ,
49
- EditCommand :: MoveRight => self . line_buffer . move_right ( ) ,
50
- EditCommand :: MoveWordLeft => self . line_buffer . move_word_left ( ) ,
51
- EditCommand :: MoveBigWordLeft => self . line_buffer . move_big_word_left ( ) ,
52
- EditCommand :: MoveWordRight => self . line_buffer . move_word_right ( ) ,
53
- EditCommand :: MoveWordRightStart => self . line_buffer . move_word_right_start ( ) ,
54
- EditCommand :: MoveBigWordRightStart => self . line_buffer . move_big_word_right_start ( ) ,
55
- EditCommand :: MoveWordRightEnd => self . line_buffer . move_word_right_end ( ) ,
56
- EditCommand :: MoveBigWordRightEnd => self . line_buffer . move_big_word_right_end ( ) ,
57
- EditCommand :: InsertChar ( c) => self . line_buffer . insert_char ( * c) ,
44
+ EditCommand :: MoveToStart { select } => self . move_to_start ( * select) ,
45
+ EditCommand :: MoveToLineStart { select } => self . move_to_line_start ( * select) ,
46
+ EditCommand :: MoveToEnd { select } => self . move_to_end ( * select) ,
47
+ EditCommand :: MoveToLineEnd { select } => self . move_to_line_end ( * select) ,
48
+ EditCommand :: MoveToPosition { position, select } => {
49
+ self . move_to_position ( * position, * select)
50
+ }
51
+ EditCommand :: MoveLeft { select } => self . move_left ( * select) ,
52
+ EditCommand :: MoveRight { select } => self . move_right ( * select) ,
53
+ EditCommand :: MoveWordLeft { select } => self . move_word_left ( * select) ,
54
+ EditCommand :: MoveBigWordLeft { select } => self . move_big_word_left ( * select) ,
55
+ EditCommand :: MoveWordRight { select } => self . move_word_right ( * select) ,
56
+ EditCommand :: MoveWordRightStart { select } => self . move_word_right_start ( * select) ,
57
+ EditCommand :: MoveBigWordRightStart { select } => {
58
+ self . move_big_word_right_start ( * select)
59
+ }
60
+ EditCommand :: MoveWordRightEnd { select } => self . move_word_right_end ( * select) ,
61
+ EditCommand :: MoveBigWordRightEnd { select } => self . move_big_word_right_end ( * select) ,
62
+ EditCommand :: InsertChar ( c) => self . insert_char ( * c) ,
58
63
EditCommand :: Complete => { }
59
- EditCommand :: InsertString ( str) => self . line_buffer . insert_str ( str) ,
60
- EditCommand :: InsertNewline => self . line_buffer . insert_newline ( ) ,
64
+ EditCommand :: InsertString ( str) => self . insert_str ( str) ,
65
+ EditCommand :: InsertNewline => self . insert_newline ( ) ,
61
66
EditCommand :: ReplaceChar ( chr) => self . replace_char ( * chr) ,
62
67
EditCommand :: ReplaceChars ( n_chars, str) => self . replace_chars ( * n_chars, str) ,
63
- EditCommand :: Backspace => self . line_buffer . delete_left_grapheme ( ) ,
64
- EditCommand :: Delete => self . line_buffer . delete_right_grapheme ( ) ,
68
+ EditCommand :: Backspace => self . backspace ( ) ,
69
+ EditCommand :: Delete => self . delete ( ) ,
65
70
EditCommand :: CutChar => self . cut_char ( ) ,
66
71
EditCommand :: BackspaceWord => self . line_buffer . delete_word_left ( ) ,
67
72
EditCommand :: DeleteWord => self . line_buffer . delete_word_right ( ) ,
@@ -90,16 +95,31 @@ impl Editor {
90
95
EditCommand :: Redo => self . redo ( ) ,
91
96
EditCommand :: CutRightUntil ( c) => self . cut_right_until_char ( * c, false , true ) ,
92
97
EditCommand :: CutRightBefore ( c) => self . cut_right_until_char ( * c, true , true ) ,
93
- EditCommand :: MoveRightUntil ( c) => self . move_right_until_char ( * c, false , true ) ,
94
- EditCommand :: MoveRightBefore ( c) => self . move_right_until_char ( * c, true , true ) ,
98
+ EditCommand :: MoveRightUntil { c, select } => {
99
+ self . move_right_until_char ( * c, false , true , * select)
100
+ }
101
+ EditCommand :: MoveRightBefore { c, select } => {
102
+ self . move_right_until_char ( * c, true , true , * select)
103
+ }
95
104
EditCommand :: CutLeftUntil ( c) => self . cut_left_until_char ( * c, false , true ) ,
96
105
EditCommand :: CutLeftBefore ( c) => self . cut_left_until_char ( * c, true , true ) ,
97
- EditCommand :: MoveLeftUntil ( c) => self . move_left_until_char ( * c, false , true ) ,
98
- EditCommand :: MoveLeftBefore ( c) => self . move_left_until_char ( * c, true , true ) ,
106
+ EditCommand :: MoveLeftUntil { c, select } => {
107
+ self . move_left_until_char ( * c, false , true , * select)
108
+ }
109
+ EditCommand :: MoveLeftBefore { c, select } => {
110
+ self . move_left_until_char ( * c, true , true , * select)
111
+ }
112
+ EditCommand :: SelectAll => self . select_all ( ) ,
113
+ EditCommand :: CutSelection => self . cut_selection ( ) ,
114
+ EditCommand :: CopySelection => self . copy_selection ( ) ,
99
115
}
116
+ if !matches ! ( command. edit_type( ) , EditType :: MoveCursor { select: true } ) {
117
+ self . selection_anchor = None ;
118
+ }
119
+ if let EditType :: MoveCursor { select : true } = command. edit_type ( ) { }
100
120
101
121
let new_undo_behavior = match ( command, command. edit_type ( ) ) {
102
- ( _, EditType :: MoveCursor ) => UndoBehavior :: MoveCursor ,
122
+ ( _, EditType :: MoveCursor { .. } ) => UndoBehavior :: MoveCursor ,
103
123
( EditCommand :: InsertChar ( c) , EditType :: EditText ) => UndoBehavior :: InsertCharacter ( * c) ,
104
124
( EditCommand :: Delete , EditType :: EditText ) => {
105
125
let deleted_char = self . edit_stack . current ( ) . grapheme_right ( ) . chars ( ) . next ( ) ;
@@ -112,8 +132,21 @@ impl Editor {
112
132
( _, EditType :: UndoRedo ) => UndoBehavior :: UndoRedo ,
113
133
( _, _) => UndoBehavior :: CreateUndoPoint ,
114
134
} ;
135
+
115
136
self . update_undo_state ( new_undo_behavior) ;
116
137
}
138
+ fn update_selection_anchor ( & mut self , select : bool ) {
139
+ self . selection_anchor = if select {
140
+ self . selection_anchor
141
+ . or_else ( || Some ( self . insertion_point ( ) ) )
142
+ } else {
143
+ None
144
+ } ;
145
+ }
146
+ fn move_to_position ( & mut self , position : usize , select : bool ) {
147
+ self . update_selection_anchor ( select) ;
148
+ self . line_buffer . set_insertion_point ( position)
149
+ }
117
150
118
151
pub ( crate ) fn move_line_up ( & mut self ) {
119
152
self . line_buffer . move_line_up ( ) ;
@@ -170,25 +203,24 @@ impl Editor {
170
203
self . edit_stack . reset ( ) ;
171
204
}
172
205
173
- pub ( crate ) fn move_to_start ( & mut self , undo_behavior : UndoBehavior ) {
206
+ pub ( crate ) fn move_to_start ( & mut self , select : bool ) {
207
+ self . update_selection_anchor ( select) ;
174
208
self . line_buffer . move_to_start ( ) ;
175
- self . update_undo_state ( undo_behavior) ;
176
209
}
177
210
178
- pub ( crate ) fn move_to_end ( & mut self , undo_behavior : UndoBehavior ) {
211
+ pub ( crate ) fn move_to_end ( & mut self , select : bool ) {
212
+ self . update_selection_anchor ( select) ;
179
213
self . line_buffer . move_to_end ( ) ;
180
- self . update_undo_state ( undo_behavior) ;
181
214
}
182
215
183
- # [ allow ( dead_code ) ]
184
- pub ( crate ) fn move_to_line_start ( & mut self , undo_behavior : UndoBehavior ) {
216
+ pub ( crate ) fn move_to_line_start ( & mut self , select : bool ) {
217
+ self . update_selection_anchor ( select ) ;
185
218
self . line_buffer . move_to_line_start ( ) ;
186
- self . update_undo_state ( undo_behavior) ;
187
219
}
188
220
189
- pub ( crate ) fn move_to_line_end ( & mut self , undo_behavior : UndoBehavior ) {
221
+ pub ( crate ) fn move_to_line_end ( & mut self , select : bool ) {
222
+ self . update_selection_anchor ( select) ;
190
223
self . line_buffer . move_to_line_end ( ) ;
191
- self . update_undo_state ( undo_behavior) ;
192
224
}
193
225
194
226
fn undo ( & mut self ) {
@@ -201,7 +233,7 @@ impl Editor {
201
233
self . line_buffer = val. clone ( ) ;
202
234
}
203
235
204
- fn update_undo_state ( & mut self , undo_behavior : UndoBehavior ) {
236
+ pub ( crate ) fn update_undo_state ( & mut self , undo_behavior : UndoBehavior ) {
205
237
if matches ! ( undo_behavior, UndoBehavior :: UndoRedo ) {
206
238
self . last_undo_behavior = UndoBehavior :: UndoRedo ;
207
239
return ;
@@ -357,6 +389,7 @@ impl Editor {
357
389
}
358
390
359
391
fn insert_cut_buffer_before ( & mut self ) {
392
+ self . delete_selection ( ) ;
360
393
match self . cut_buffer . get ( ) {
361
394
( content, ClipboardMode :: Normal ) => {
362
395
self . line_buffer . insert_str ( & content) ;
@@ -375,6 +408,7 @@ impl Editor {
375
408
}
376
409
377
410
fn insert_cut_buffer_after ( & mut self ) {
411
+ self . delete_selection ( ) ;
378
412
match self . cut_buffer . get ( ) {
379
413
( content, ClipboardMode :: Normal ) => {
380
414
self . line_buffer . move_right ( ) ;
@@ -393,15 +427,29 @@ impl Editor {
393
427
}
394
428
}
395
429
396
- fn move_right_until_char ( & mut self , c : char , before_char : bool , current_line : bool ) {
430
+ fn move_right_until_char (
431
+ & mut self ,
432
+ c : char ,
433
+ before_char : bool ,
434
+ current_line : bool ,
435
+ select : bool ,
436
+ ) {
437
+ self . update_selection_anchor ( select) ;
397
438
if before_char {
398
439
self . line_buffer . move_right_before ( c, current_line) ;
399
440
} else {
400
441
self . line_buffer . move_right_until ( c, current_line) ;
401
442
}
402
443
}
403
444
404
- fn move_left_until_char ( & mut self , c : char , before_char : bool , current_line : bool ) {
445
+ fn move_left_until_char (
446
+ & mut self ,
447
+ c : char ,
448
+ before_char : bool ,
449
+ current_line : bool ,
450
+ select : bool ,
451
+ ) {
452
+ self . update_selection_anchor ( select) ;
405
453
if before_char {
406
454
self . line_buffer . move_left_before ( c, current_line) ;
407
455
} else {
@@ -462,6 +510,115 @@ impl Editor {
462
510
463
511
self . line_buffer . insert_str ( string) ;
464
512
}
513
+
514
+ fn move_left ( & mut self , select : bool ) {
515
+ self . update_selection_anchor ( select) ;
516
+ self . line_buffer . move_left ( ) ;
517
+ }
518
+
519
+ fn move_right ( & mut self , select : bool ) {
520
+ self . update_selection_anchor ( select) ;
521
+ self . line_buffer . move_right ( ) ;
522
+ }
523
+
524
+ fn select_all ( & mut self ) {
525
+ self . selection_anchor = Some ( 0 ) ;
526
+ self . line_buffer . move_to_end ( ) ;
527
+ }
528
+
529
+ fn cut_selection ( & mut self ) {
530
+ if let Some ( ( start, end) ) = self . get_selection ( ) {
531
+ let cut_slice = & self . line_buffer . get_buffer ( ) [ start..end] ;
532
+ self . cut_buffer . set ( cut_slice, ClipboardMode :: Normal ) ;
533
+ self . line_buffer . clear_range_safe ( start, end) ;
534
+ self . selection_anchor = None ;
535
+ }
536
+ }
537
+
538
+ fn copy_selection ( & mut self ) {
539
+ if let Some ( ( start, end) ) = self . get_selection ( ) {
540
+ let cut_slice = & self . line_buffer . get_buffer ( ) [ start..end] ;
541
+ self . cut_buffer . set ( cut_slice, ClipboardMode :: Normal ) ;
542
+ }
543
+ }
544
+
545
+ /// If a selection is active returns the selected range, otherwise None.
546
+ /// The range is guaranteed to be ascending.
547
+ pub fn get_selection ( & self ) -> Option < ( usize , usize ) > {
548
+ self . selection_anchor . map ( |selection_anchor| {
549
+ if self . insertion_point ( ) > selection_anchor {
550
+ ( selection_anchor, self . insertion_point ( ) )
551
+ } else {
552
+ ( self . insertion_point ( ) , selection_anchor)
553
+ }
554
+ } )
555
+ }
556
+
557
+ fn delete_selection ( & mut self ) {
558
+ if let Some ( ( start, end) ) = self . get_selection ( ) {
559
+ self . line_buffer . clear_range_safe ( start, end) ;
560
+ self . selection_anchor = None ;
561
+ }
562
+ }
563
+
564
+ fn backspace ( & mut self ) {
565
+ if self . selection_anchor . is_some ( ) {
566
+ self . delete_selection ( ) ;
567
+ } else {
568
+ self . line_buffer . delete_left_grapheme ( ) ;
569
+ }
570
+ }
571
+
572
+ fn delete ( & mut self ) {
573
+ if self . selection_anchor . is_some ( ) {
574
+ self . delete_selection ( ) ;
575
+ } else {
576
+ self . line_buffer . delete_right_grapheme ( ) ;
577
+ }
578
+ }
579
+
580
+ fn move_word_left ( & mut self , select : bool ) {
581
+ self . move_to_position ( self . line_buffer . word_left_index ( ) , select) ;
582
+ }
583
+
584
+ fn move_big_word_left ( & mut self , select : bool ) {
585
+ self . move_to_position ( self . line_buffer . big_word_left_index ( ) , select) ;
586
+ }
587
+
588
+ fn move_word_right ( & mut self , select : bool ) {
589
+ self . move_to_position ( self . line_buffer . word_right_index ( ) , select) ;
590
+ }
591
+
592
+ fn move_word_right_start ( & mut self , select : bool ) {
593
+ self . move_to_position ( self . line_buffer . word_right_start_index ( ) , select) ;
594
+ }
595
+
596
+ fn move_big_word_right_start ( & mut self , select : bool ) {
597
+ self . move_to_position ( self . line_buffer . big_word_right_start_index ( ) , select) ;
598
+ }
599
+
600
+ fn move_word_right_end ( & mut self , select : bool ) {
601
+ self . move_to_position ( self . line_buffer . word_right_end_index ( ) , select) ;
602
+ }
603
+
604
+ fn move_big_word_right_end ( & mut self , select : bool ) {
605
+ self . move_to_position ( self . line_buffer . big_word_right_end_index ( ) , select) ;
606
+ }
607
+
608
+ fn insert_char ( & mut self , c : char ) {
609
+ self . delete_selection ( ) ;
610
+ self . line_buffer . insert_char ( c) ;
611
+ }
612
+
613
+ fn insert_str ( & mut self , str : & str ) {
614
+ self . delete_selection ( ) ;
615
+ self . line_buffer . insert_str ( str) ;
616
+ }
617
+
618
+ fn insert_newline ( & mut self ) {
619
+ self . delete_selection ( ) ;
620
+ self . line_buffer . insert_newline ( ) ;
621
+ }
465
622
}
466
623
467
624
#[ cfg( test) ]
0 commit comments