@@ -31,20 +31,39 @@ fn finish_change<'buffer, E: Edit<'buffer>>(
31
31
editor : & mut E ,
32
32
commands : & mut cosmic_undo_2:: Commands < Change > ,
33
33
changed : & mut bool ,
34
+ pivot : Option < usize > ,
34
35
) -> Option < Change > {
35
36
//TODO: join changes together
36
37
match editor. finish_change ( ) {
37
38
Some ( change) => {
38
39
if !change. items . is_empty ( ) {
39
40
commands. push ( change. clone ( ) ) ;
40
- * changed = true ;
41
+ * changed = eval_changed ( commands , pivot ) ;
41
42
}
42
43
Some ( change)
43
44
}
44
45
None => None ,
45
46
}
46
47
}
47
48
49
+ /// Evaluate if an [`ViEditor`] changed based on its last saved state.
50
+ fn eval_changed ( commands : & cosmic_undo_2:: Commands < Change > , pivot : Option < usize > ) -> bool {
51
+ // Editors are considered modified if the current change index is unequal to the last
52
+ // saved index or if `pivot` is None.
53
+ // The latter case handles a never saved editor with a current command index of None.
54
+ // Check the unit tests for an example.
55
+ match ( commands. current_command_index ( ) , pivot) {
56
+ ( Some ( current) , Some ( pivot) ) => current != pivot,
57
+ // Edge case for an editor with neither a save point nor any changes.
58
+ // This could be a new editor or an editor without a save point where undo() is called
59
+ // until the editor is fresh.
60
+ ( None , None ) => false ,
61
+ // Default to true because it's safer to assume a buffer has been modified so as to not
62
+ // lose changes
63
+ _ => true ,
64
+ }
65
+ }
66
+
48
67
fn search < ' buffer , E : Edit < ' buffer > > ( editor : & mut E , value : & str , forwards : bool ) -> bool {
49
68
let mut cursor = editor. cursor ( ) ;
50
69
let start_line = cursor. line ;
@@ -167,6 +186,7 @@ pub struct ViEditor<'syntax_system, 'buffer> {
167
186
search_opt : Option < ( String , bool ) > ,
168
187
commands : cosmic_undo_2:: Commands < Change > ,
169
188
changed : bool ,
189
+ save_pivot : Option < usize > ,
170
190
}
171
191
172
192
impl < ' syntax_system , ' buffer > ViEditor < ' syntax_system , ' buffer > {
@@ -179,6 +199,7 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
179
199
search_opt : None ,
180
200
commands : cosmic_undo_2:: Commands :: new ( ) ,
181
201
changed : false ,
202
+ save_pivot : None ,
182
203
}
183
204
}
184
205
@@ -233,6 +254,20 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
233
254
self . changed = changed;
234
255
}
235
256
257
+ /// Set current change as the save (or pivot) point.
258
+ ///
259
+ /// A pivot point is the last saved index. Anything before or after the pivot indicates that
260
+ /// the editor has been changed or is unsaved.
261
+ ///
262
+ /// Undoing changes down to the pivot point sets the editor as unchanged.
263
+ /// Redoing changes up to the pivot point sets the editor as unchanged.
264
+ ///
265
+ /// Undoing or redoing changes beyond the pivot point sets the editor to changed.
266
+ pub fn save_point ( & mut self ) {
267
+ self . save_pivot = Some ( self . commands . current_command_index ( ) . unwrap_or_default ( ) ) ;
268
+ self . changed = false ;
269
+ }
270
+
236
271
/// Set passthrough mode (true will turn off vi features)
237
272
pub fn set_passthrough ( & mut self , passthrough : bool ) {
238
273
if passthrough != self . passthrough {
@@ -251,19 +286,17 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
251
286
log:: debug!( "Redo" ) ;
252
287
for action in self . commands . redo ( ) {
253
288
undo_2_action ( & mut self . editor , action) ;
254
- //TODO: clear changed flag when back to last saved state?
255
- self . changed = true ;
256
289
}
290
+ self . changed = eval_changed ( & self . commands , self . save_pivot ) ;
257
291
}
258
292
259
293
/// Undo a change
260
294
pub fn undo ( & mut self ) {
261
295
log:: debug!( "Undo" ) ;
262
296
for action in self . commands . undo ( ) {
263
297
undo_2_action ( & mut self . editor , action) ;
264
- //TODO: clear changed flag when back to last saved state?
265
- self . changed = true ;
266
298
}
299
+ self . changed = eval_changed ( & self . commands , self . save_pivot ) ;
267
300
}
268
301
269
302
#[ cfg( feature = "swash" ) ]
@@ -550,7 +583,12 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer
550
583
}
551
584
552
585
fn finish_change ( & mut self ) -> Option < Change > {
553
- finish_change ( & mut self . editor , & mut self . commands , & mut self . changed )
586
+ finish_change (
587
+ & mut self . editor ,
588
+ & mut self . commands ,
589
+ & mut self . changed ,
590
+ self . save_pivot ,
591
+ )
554
592
}
555
593
556
594
fn action ( & mut self , font_system : & mut FontSystem , action : Action ) {
@@ -564,7 +602,12 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer
564
602
if self . passthrough {
565
603
editor. action ( font_system, action) ;
566
604
// Always finish change when passing through (TODO: group changes)
567
- finish_change ( editor, & mut self . commands , & mut self . changed ) ;
605
+ finish_change (
606
+ editor,
607
+ & mut self . commands ,
608
+ & mut self . changed ,
609
+ self . save_pivot ,
610
+ ) ;
568
611
return ;
569
612
}
570
613
@@ -589,7 +632,12 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer
589
632
log:: debug!( "Pass through action {:?}" , action) ;
590
633
editor. action ( font_system, action) ;
591
634
// Always finish change when passing through (TODO: group changes)
592
- finish_change ( editor, & mut self . commands , & mut self . changed ) ;
635
+ finish_change (
636
+ editor,
637
+ & mut self . commands ,
638
+ & mut self . changed ,
639
+ self . save_pivot ,
640
+ ) ;
593
641
return ;
594
642
}
595
643
} ;
@@ -620,7 +668,12 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer
620
668
return ;
621
669
}
622
670
Event :: ChangeFinish => {
623
- finish_change ( editor, & mut self . commands , & mut self . changed ) ;
671
+ finish_change (
672
+ editor,
673
+ & mut self . commands ,
674
+ & mut self . changed ,
675
+ self . save_pivot ,
676
+ ) ;
624
677
return ;
625
678
}
626
679
Event :: Delete => Action :: Delete ,
@@ -687,7 +740,12 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer
687
740
}
688
741
}
689
742
}
690
- finish_change ( editor, & mut self . commands , & mut self . changed ) ;
743
+ finish_change (
744
+ editor,
745
+ & mut self . commands ,
746
+ & mut self . changed ,
747
+ self . save_pivot ,
748
+ ) ;
691
749
}
692
750
return ;
693
751
}
0 commit comments