1515//! assert_eq!(input.to_string(), "Hello World");
1616//! ```
1717
18+ enum Side {
19+ Left ,
20+ Right ,
21+ }
22+
1823/// Input requests are used to change the input state.
1924///
2025/// Different backends can be used to convert events into requests.
@@ -35,6 +40,7 @@ pub enum InputRequest {
3540 DeleteNextWord ,
3641 DeleteLine ,
3742 DeleteTillEnd ,
43+ Yank ,
3844}
3945
4046#[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
@@ -63,14 +69,21 @@ pub type InputResponse = Option<StateChanged>;
6369pub struct Input {
6470 value : String ,
6571 cursor : usize ,
72+ yank : String ,
73+ last_was_cut : bool ,
6674}
6775
6876impl Input {
6977 /// Initialize a new instance with a given value
7078 /// Cursor will be set to the given value's length.
7179 pub fn new ( value : String ) -> Self {
7280 let len = value. chars ( ) . count ( ) ;
73- Self { value, cursor : len }
81+ Self {
82+ value,
83+ cursor : len,
84+ yank : String :: new ( ) ,
85+ last_was_cut : false ,
86+ }
7487 }
7588
7689 /// Set the value manually.
@@ -101,10 +114,29 @@ impl Input {
101114 val
102115 }
103116
117+ fn add_to_yank ( & mut self , deleted : String , side : Side ) {
118+ if self . last_was_cut {
119+ match side {
120+ Side :: Left => self . yank . insert_str ( 0 , & deleted) ,
121+ Side :: Right => self . yank . push_str ( & deleted) ,
122+ }
123+ } else {
124+ self . yank = deleted;
125+ }
126+ }
127+
128+ fn set_last_was_cut ( & mut self , req : InputRequest ) {
129+ use InputRequest :: * ;
130+ self . last_was_cut = matches ! (
131+ req,
132+ DeleteLine | DeletePrevWord | DeleteNextWord | DeleteTillEnd
133+ ) ;
134+ }
135+
104136 /// Handle request and emit response.
105137 pub fn handle ( & mut self , req : InputRequest ) -> InputResponse {
106138 use InputRequest :: * ;
107- match req {
139+ let result = match req {
108140 SetCursor ( pos) => {
109141 let pos = pos. min ( self . value . chars ( ) . count ( ) ) ;
110142 if self . cursor == pos {
@@ -244,12 +276,17 @@ impl Input {
244276 if self . value . is_empty ( ) {
245277 None
246278 } else {
247- let cursor = self . cursor ;
279+ let side = if self . cursor == self . value . chars ( ) . count ( ) {
280+ Side :: Left
281+ } else {
282+ Side :: Right
283+ } ;
284+ self . add_to_yank ( self . value . clone ( ) , side) ;
248285 self . value = "" . into ( ) ;
249286 self . cursor = 0 ;
250287 Some ( StateChanged {
251288 value : true ,
252- cursor : self . cursor == cursor ,
289+ cursor : true ,
253290 } )
254291 }
255292 }
@@ -258,7 +295,6 @@ impl Input {
258295 if self . cursor == 0 {
259296 None
260297 } else {
261- let remaining = self . value . chars ( ) . skip ( self . cursor ) ;
262298 let rev = self
263299 . value
264300 . chars ( )
@@ -268,6 +304,14 @@ impl Input {
268304 . skip_while ( |c| c. is_alphanumeric ( ) )
269305 . collect :: < Vec < char > > ( ) ;
270306 let rev_len = rev. len ( ) ;
307+ let deleted: String = self
308+ . value
309+ . chars ( )
310+ . skip ( rev_len)
311+ . take ( self . cursor - rev_len)
312+ . collect ( ) ;
313+ self . add_to_yank ( deleted, Side :: Left ) ;
314+ let remaining = self . value . chars ( ) . skip ( self . cursor ) ;
271315 self . value = rev. into_iter ( ) . rev ( ) . chain ( remaining) . collect ( ) ;
272316 self . cursor = rev_len;
273317 Some ( StateChanged {
@@ -281,18 +325,24 @@ impl Input {
281325 if self . cursor == self . value . chars ( ) . count ( ) {
282326 None
283327 } else {
284- self . value = self
328+ let after : Vec < _ > = self
285329 . value
286330 . chars ( )
287- . take ( self . cursor )
288- . chain (
289- self . value
290- . chars ( )
291- . skip ( self . cursor )
292- . skip_while ( |c| c. is_alphanumeric ( ) )
293- . skip_while ( |c| !c. is_alphanumeric ( ) ) ,
294- )
331+ . skip ( self . cursor )
332+ . skip_while ( |c| c. is_alphanumeric ( ) )
333+ . skip_while ( |c| !c. is_alphanumeric ( ) )
295334 . collect ( ) ;
335+ let deleted_count =
336+ self . value . chars ( ) . count ( ) - self . cursor - after. len ( ) ;
337+ let deleted: String = self
338+ . value
339+ . chars ( )
340+ . skip ( self . cursor )
341+ . take ( deleted_count)
342+ . collect ( ) ;
343+ self . add_to_yank ( deleted, Side :: Right ) ;
344+ self . value =
345+ self . value . chars ( ) . take ( self . cursor ) . chain ( after) . collect ( ) ;
296346
297347 Some ( StateChanged {
298348 value : true ,
@@ -327,13 +377,43 @@ impl Input {
327377 }
328378
329379 DeleteTillEnd => {
380+ let deleted: String = self . value . chars ( ) . skip ( self . cursor ) . collect ( ) ;
381+ self . add_to_yank ( deleted, Side :: Right ) ;
330382 self . value = self . value . chars ( ) . take ( self . cursor ) . collect ( ) ;
331383 Some ( StateChanged {
332384 value : true ,
333385 cursor : false ,
334386 } )
335387 }
336- }
388+
389+ Yank => {
390+ if self . yank . is_empty ( ) {
391+ None
392+ } else if self . cursor == self . value . chars ( ) . count ( ) {
393+ self . value . push_str ( & self . yank ) ;
394+ self . cursor += self . yank . chars ( ) . count ( ) ;
395+ Some ( StateChanged {
396+ value : true ,
397+ cursor : true ,
398+ } )
399+ } else {
400+ self . value = self
401+ . value
402+ . chars ( )
403+ . take ( self . cursor )
404+ . chain ( self . yank . chars ( ) )
405+ . chain ( self . value . chars ( ) . skip ( self . cursor ) )
406+ . collect ( ) ;
407+ self . cursor += self . yank . chars ( ) . count ( ) ;
408+ Some ( StateChanged {
409+ value : true ,
410+ cursor : true ,
411+ } )
412+ }
413+ }
414+ } ;
415+ self . set_last_was_cut ( req) ;
416+ result
337417 }
338418
339419 /// Get a reference to the current value.
@@ -594,4 +674,141 @@ mod tests {
594674 assert_eq ! ( input. visual_cursor( ) , 23 ) ;
595675 assert_eq ! ( input. visual_scroll( 6 ) , 18 ) ;
596676 }
677+
678+ #[ test]
679+ fn yank_delete_line ( ) {
680+ let mut input: Input = TEXT . into ( ) ;
681+ input. handle ( InputRequest :: DeleteLine ) ;
682+ assert_eq ! ( input. value( ) , "" ) ;
683+ assert_eq ! ( input. cursor( ) , 0 ) ;
684+ assert_eq ! ( input. yank, TEXT ) ;
685+
686+ input. handle ( InputRequest :: Yank ) ;
687+ assert_eq ! ( input. value( ) , TEXT ) ;
688+ assert_eq ! ( input. cursor( ) , TEXT . chars( ) . count( ) ) ;
689+ assert_eq ! ( input. yank, TEXT ) ;
690+ }
691+
692+ #[ test]
693+ fn yank_delete_till_end ( ) {
694+ let mut input = Input :: from ( TEXT ) . with_cursor ( 6 ) ;
695+ input. handle ( InputRequest :: DeleteTillEnd ) ;
696+ assert_eq ! ( input. value( ) , "first " ) ;
697+ assert_eq ! ( input. cursor( ) , 6 ) ;
698+ assert_eq ! ( input. yank, "second, third." ) ;
699+
700+ input. handle ( InputRequest :: Yank ) ;
701+ assert_eq ! ( input. value( ) , "first second, third." ) ;
702+ assert_eq ! ( input. cursor( ) , TEXT . chars( ) . count( ) ) ;
703+ assert_eq ! ( input. yank, "second, third." ) ;
704+ }
705+
706+ #[ test]
707+ fn yank_delete_prev_word ( ) {
708+ let mut input = Input :: from ( TEXT ) . with_cursor ( 12 ) ;
709+ input. handle ( InputRequest :: DeletePrevWord ) ;
710+ assert_eq ! ( input. value( ) , "first , third." ) ;
711+ assert_eq ! ( input. yank, "second" ) ;
712+
713+ input. handle ( InputRequest :: Yank ) ;
714+ assert_eq ! ( input. value( ) , "first second, third." ) ;
715+ assert_eq ! ( input. yank, "second" ) ;
716+ }
717+
718+ #[ test]
719+ fn yank_delete_next_word ( ) {
720+ let mut input = Input :: from ( TEXT ) . with_cursor ( 6 ) ;
721+ input. handle ( InputRequest :: DeleteNextWord ) ;
722+ assert_eq ! ( input. value( ) , "first third." ) ;
723+ assert_eq ! ( input. yank, "second, " ) ;
724+
725+ input. handle ( InputRequest :: Yank ) ;
726+ assert_eq ! ( input. value( ) , "first second, third." ) ;
727+ assert_eq ! ( input. yank, "second, " ) ;
728+ }
729+
730+ #[ test]
731+ fn yank_empty ( ) {
732+ let mut input: Input = TEXT . into ( ) ;
733+ let result = input. handle ( InputRequest :: Yank ) ;
734+ assert_eq ! ( result, None ) ;
735+ assert_eq ! ( input. value( ) , TEXT ) ;
736+ assert_eq ! ( input. yank, "" ) ;
737+ }
738+
739+ #[ test]
740+ fn yank_at_middle ( ) {
741+ let mut input = Input :: from ( TEXT ) . with_cursor ( 6 ) ;
742+ input. handle ( InputRequest :: DeleteTillEnd ) ;
743+ assert_eq ! ( input. value( ) , "first " ) ;
744+ assert_eq ! ( input. yank, "second, third." ) ;
745+ input. handle ( InputRequest :: GoToStart ) ;
746+ input. handle ( InputRequest :: Yank ) ;
747+ assert_eq ! ( input. value( ) , "second, third.first " ) ;
748+ assert_eq ! ( input. cursor( ) , 14 ) ;
749+ assert_eq ! ( input. yank, "second, third." ) ;
750+ }
751+
752+ #[ test]
753+ fn yank_consecutive_delete_prev_word ( ) {
754+ let mut input = Input :: from ( TEXT ) . with_cursor ( TEXT . chars ( ) . count ( ) ) ;
755+ input. handle ( InputRequest :: DeletePrevWord ) ;
756+ assert_eq ! ( input. value( ) , "first second, " ) ;
757+ assert_eq ! ( input. yank, "third." ) ;
758+ input. handle ( InputRequest :: DeletePrevWord ) ;
759+ assert_eq ! ( input. value( ) , "first " ) ;
760+ assert_eq ! ( input. yank, "second, third." ) ;
761+ input. handle ( InputRequest :: Yank ) ;
762+ assert_eq ! ( input. value( ) , "first second, third." ) ;
763+ }
764+
765+ #[ test]
766+ fn yank_consecutive_delete_next_word ( ) {
767+ let mut input = Input :: from ( TEXT ) . with_cursor ( 0 ) ;
768+ input. handle ( InputRequest :: DeleteNextWord ) ;
769+ assert_eq ! ( input. value( ) , "second, third." ) ;
770+ assert_eq ! ( input. yank, "first " ) ;
771+ input. handle ( InputRequest :: DeleteNextWord ) ;
772+ assert_eq ! ( input. value( ) , "third." ) ;
773+ assert_eq ! ( input. yank, "first second, " ) ;
774+ input. handle ( InputRequest :: Yank ) ;
775+ assert_eq ! ( input. value( ) , "first second, third." ) ;
776+ }
777+
778+ #[ test]
779+ fn yank_insert_breaks_cut_sequence ( ) {
780+ let mut input = Input :: from ( TEXT ) . with_cursor ( TEXT . chars ( ) . count ( ) ) ;
781+ input. handle ( InputRequest :: DeletePrevWord ) ;
782+ assert_eq ! ( input. yank, "third." ) ;
783+ input. handle ( InputRequest :: InsertChar ( 'x' ) ) ;
784+ input. handle ( InputRequest :: DeletePrevChar ) ;
785+ input. handle ( InputRequest :: DeletePrevWord ) ;
786+ assert_eq ! ( input. yank, "second, " ) ;
787+ }
788+
789+ #[ test]
790+ fn yank_mixed_delete_word_and_line ( ) {
791+ let mut input = Input :: from ( TEXT ) . with_cursor ( 6 ) ;
792+ input. handle ( InputRequest :: DeletePrevWord ) ;
793+ assert_eq ! ( input. value( ) , "second, third." ) ;
794+ assert_eq ! ( input. yank, "first " ) ;
795+ input. handle ( InputRequest :: DeleteLine ) ;
796+ assert_eq ! ( input. value( ) , "" ) ;
797+ assert_eq ! ( input. yank, "first second, third." ) ;
798+ input. handle ( InputRequest :: Yank ) ;
799+ assert_eq ! ( input. value( ) , "first second, third." ) ;
800+ }
801+
802+ #[ test]
803+ fn yank_mixed_delete_word_and_line_from_end ( ) {
804+ let mut input = Input :: from ( TEXT ) . with_cursor ( TEXT . chars ( ) . count ( ) ) ;
805+ input. handle ( InputRequest :: DeletePrevWord ) ;
806+ assert_eq ! ( input. value( ) , "first second, " ) ;
807+ assert_eq ! ( input. yank, "third." ) ;
808+ input. handle ( InputRequest :: DeleteLine ) ;
809+ assert_eq ! ( input. value( ) , "" ) ;
810+ assert_eq ! ( input. yank, "first second, third." ) ;
811+ input. handle ( InputRequest :: Yank ) ;
812+ assert_eq ! ( input. value( ) , "first second, third." ) ;
813+ }
597814}
0 commit comments