@@ -51,11 +51,10 @@ use {
51
51
// a POLL_WAIT of zero means that every single event is treated as soon as it
52
52
// arrives. This doesn't allow for the possibility of more than 1 event
53
53
// happening at the same time.
54
- const POLL_WAIT : u64 = 10 ;
55
- // Since a paste event is multiple Event::Key events happening at the same time, we specify
56
- // how many events should be in the crossterm_events vector before it is considered
57
- // a paste. 10 events in 10 milliseconds is conservative enough (unlikely somebody
58
- // will type more than 10 characters in 10 milliseconds)
54
+ const POLL_WAIT : Duration = Duration :: from_millis ( 100 ) ;
55
+ // Since a paste event is multiple `Event::Key` events happening at the same
56
+ // time, we specify how many events should be in the `crossterm_events` vector
57
+ // before it is considered a paste. 10 events is conservative enough.
59
58
const EVENTS_THRESHOLD : usize = 10 ;
60
59
61
60
/// Determines if inputs should be used to extend the regular line buffer,
@@ -695,12 +694,7 @@ impl Reedline {
695
694
696
695
self . repaint ( prompt) ?;
697
696
698
- let mut crossterm_events: Vec < ReedlineRawEvent > = vec ! [ ] ;
699
- let mut reedline_events: Vec < ReedlineEvent > = vec ! [ ] ;
700
-
701
697
loop {
702
- let mut paste_enter_state = false ;
703
-
704
698
#[ cfg( feature = "external_printer" ) ]
705
699
if let Some ( ref external_printer) = self . external_printer {
706
700
// get messages from printer as crlf separated "lines"
@@ -716,76 +710,74 @@ impl Reedline {
716
710
}
717
711
}
718
712
719
- let mut latest_resize = None ;
720
- loop {
721
- // There could be multiple events queued up!
722
- // pasting text, resizes, blocking this thread (e.g. during debugging)
723
- // We should be able to handle all of them as quickly as possible without causing unnecessary output steps.
724
- if !event:: poll ( Duration :: from_millis ( POLL_WAIT ) ) ? {
725
- break ;
726
- }
727
-
728
- match event:: read ( ) ? {
729
- Event :: Resize ( x, y) => {
730
- latest_resize = Some ( ( x, y) ) ;
731
- }
732
- enter @ Event :: Key ( KeyEvent {
733
- code : KeyCode :: Enter ,
734
- modifiers : KeyModifiers :: NONE ,
735
- ..
736
- } ) => {
737
- let enter = ReedlineRawEvent :: convert_from ( enter) ;
738
- if let Some ( enter) = enter {
739
- crossterm_events. push ( enter) ;
740
- // Break early to check if the input is complete and
741
- // can be send to the hosting application. If
742
- // multiple complete entries are submitted, events
743
- // are still in the crossterm queue for us to
744
- // process.
745
- paste_enter_state = crossterm_events. len ( ) > EVENTS_THRESHOLD ;
746
- break ;
747
- }
748
- }
749
- x => {
750
- let raw_event = ReedlineRawEvent :: convert_from ( x) ;
751
- if let Some ( evt) = raw_event {
752
- crossterm_events. push ( evt) ;
753
- }
754
- }
713
+ // Helper function that returns true if the input is complete and
714
+ // can be sent to the hosting application.
715
+ fn completed ( events : & [ Event ] ) -> bool {
716
+ if let Some ( event) = events. last ( ) {
717
+ matches ! (
718
+ event,
719
+ Event :: Key ( KeyEvent {
720
+ code: KeyCode :: Enter ,
721
+ modifiers: KeyModifiers :: NONE ,
722
+ ..
723
+ } )
724
+ )
725
+ } else {
726
+ false
755
727
}
756
728
}
757
729
758
- if let Some ( ( x, y) ) = latest_resize {
759
- reedline_events. push ( ReedlineEvent :: Resize ( x, y) ) ;
730
+ let mut events: Vec < Event > = vec ! [ ] ;
731
+
732
+ // Block until we receive an event.
733
+ events. push ( crossterm:: event:: read ( ) ?) ;
734
+
735
+ // Receive all events in the queue without blocking. Will stop when
736
+ // a line of input is completed.
737
+ while !completed ( & events) && event:: poll ( Duration :: from_millis ( 0 ) ) ? {
738
+ events. push ( crossterm:: event:: read ( ) ?) ;
760
739
}
761
740
762
- // Accelerate pasted text by fusing `EditCommand`s
763
- //
764
- // (Text should only be `EditCommand::InsertChar`s)
765
- let mut last_edit_commands = None ;
766
- for event in crossterm_events. drain ( ..) {
767
- match ( & mut last_edit_commands, self . edit_mode . parse_event ( event) ) {
768
- ( None , ReedlineEvent :: Edit ( ec) ) => {
769
- last_edit_commands = Some ( ec) ;
770
- }
771
- ( None , other_event) => {
772
- reedline_events. push ( other_event) ;
773
- }
774
- ( Some ( ref mut last_ecs) , ReedlineEvent :: Edit ( ec) ) => {
775
- last_ecs. extend ( ec) ;
776
- }
777
- ( ref mut a @ Some ( _) , other_event) => {
778
- reedline_events. push ( ReedlineEvent :: Edit ( a. take ( ) . unwrap ( ) ) ) ;
741
+ // If we believe there's text pasting or resizing going on, batch
742
+ // more events at the cost of a slight delay.
743
+ if events. len ( ) > EVENTS_THRESHOLD
744
+ || events. iter ( ) . any ( |e| matches ! ( e, Event :: Resize ( _, _) ) )
745
+ {
746
+ while !completed ( & events) && event:: poll ( POLL_WAIT ) ? {
747
+ events. push ( crossterm:: event:: read ( ) ?) ;
748
+ }
749
+ }
779
750
780
- reedline_events. push ( other_event) ;
751
+ // Convert `Event` into `ReedlineEvent`. Also, fuse consecutive
752
+ // `ReedlineEvent::EditCommand` into one. Also, if there're multiple
753
+ // `ReedlineEvent::Resize`, only keep the last one.
754
+ let mut reedline_events: Vec < ReedlineEvent > = vec ! [ ] ;
755
+ let mut edits = vec ! [ ] ;
756
+ let mut resize = None ;
757
+ for event in events {
758
+ if let Some ( event) = ReedlineRawEvent :: convert_from ( event) {
759
+ match self . edit_mode . parse_event ( event) {
760
+ ReedlineEvent :: Edit ( edit) => edits. extend ( edit) ,
761
+ ReedlineEvent :: Resize ( x, y) => resize = Some ( ( x, y) ) ,
762
+ event => {
763
+ if !edits. is_empty ( ) {
764
+ reedline_events
765
+ . push ( ReedlineEvent :: Edit ( std:: mem:: take ( & mut edits) ) ) ;
766
+ }
767
+ reedline_events. push ( event) ;
768
+ }
781
769
}
782
770
}
783
771
}
784
- if let Some ( ec) = last_edit_commands {
785
- reedline_events. push ( ReedlineEvent :: Edit ( ec) ) ;
772
+ if !edits. is_empty ( ) {
773
+ reedline_events. push ( ReedlineEvent :: Edit ( edits) ) ;
774
+ }
775
+ if let Some ( ( x, y) ) = resize {
776
+ reedline_events. push ( ReedlineEvent :: Resize ( x, y) ) ;
786
777
}
787
778
788
- for event in reedline_events. drain ( ..) {
779
+ // Handle reedline events.
780
+ for event in reedline_events {
789
781
match self . handle_event ( prompt, event) ? {
790
782
EventStatus :: Exits ( signal) => {
791
783
// Check if we are merely suspended (to process an ExecuteHostCommand event)
@@ -798,9 +790,7 @@ impl Reedline {
798
790
return Ok ( signal) ;
799
791
}
800
792
EventStatus :: Handled => {
801
- if !paste_enter_state {
802
- self . repaint ( prompt) ?;
803
- }
793
+ self . repaint ( prompt) ?;
804
794
}
805
795
EventStatus :: Inapplicable => {
806
796
// Nothing changed, no need to repaint
0 commit comments