@@ -1717,20 +1717,6 @@ impl Reedline {
17171717 /// Executes [`EditCommand`] actions by modifying the internal state appropriately. Does not output itself.
17181718 pub fn run_edit_commands ( & mut self , commands : & [ EditCommand ] ) {
17191719 if self . input_mode == InputMode :: HistoryTraversal {
1720- if matches ! (
1721- self . history_cursor. get_navigation( ) ,
1722- HistoryNavigationQuery :: Normal ( _)
1723- ) {
1724- if let Some ( string) = self . history_cursor . string_at_cursor ( ) {
1725- // NOTE: `set_buffer` resets the insertion point,
1726- // which we should avoid during history navigation through the same buffer
1727- // https://github.com/nushell/reedline/pull/899
1728- if string != self . editor . get_buffer ( ) {
1729- self . editor
1730- . set_buffer ( string, UndoBehavior :: HistoryNavigation ) ;
1731- }
1732- }
1733- }
17341720 self . input_mode = InputMode :: Regular ;
17351721 }
17361722
@@ -2300,7 +2286,7 @@ impl Reedline {
23002286mod tests {
23012287 use super :: * ;
23022288 use crate :: terminal_extensions:: semantic_prompt:: PromptKind ;
2303- use crate :: DefaultPrompt ;
2289+ use crate :: { ColumnarMenu , DefaultPrompt , MenuBuilder } ;
23042290 use rstest:: rstest;
23052291
23062292 #[ test]
@@ -2685,4 +2671,169 @@ mod tests {
26852671 "must expand when highlighter does not override should_expand_abbr"
26862672 ) ;
26872673 }
2674+
2675+ #[ rstest]
2676+ #[ case( "" ) ]
2677+ #[ case( "line of text" ) ]
2678+ #[ case(
2679+ "longgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg line of text"
2680+ ) ]
2681+ fn test_move_to_line_start ( #[ case] input : & str ) {
2682+ let mut reedline = Reedline :: create ( ) ;
2683+
2684+ // Write the string, and then move to the start of the line.
2685+ let insertion = EditCommand :: InsertString ( String :: from ( input) ) ;
2686+ reedline. run_edit_commands ( & [ insertion] ) ;
2687+
2688+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2689+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2690+
2691+ assert_eq ! ( reedline. editor. line_buffer( ) . insertion_point( ) , 0 ) ;
2692+ }
2693+
2694+ #[ rstest]
2695+ #[ case( "" ) ]
2696+ #[ case( "line of text" ) ]
2697+ #[ case(
2698+ "longgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg line of text"
2699+ ) ]
2700+ fn test_move_to_line_start_history ( #[ case] input : & str ) {
2701+ let mut reedline = Reedline :: create ( ) ;
2702+
2703+ // Enter the string into history, then scroll back up and move to the start of the line.
2704+ let history = HistoryItem :: from_command_line ( input) ;
2705+ reedline. history . save ( history) . unwrap ( ) ;
2706+
2707+ reedline. previous_history ( ) ;
2708+
2709+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2710+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2711+
2712+ assert_eq ! ( reedline. editor. line_buffer( ) . insertion_point( ) , 0 ) ;
2713+ }
2714+
2715+ #[ rstest]
2716+ #[ case( "a\n b" , 2 ) ]
2717+ #[ case( "123456789\n 123456789\n 123456789" , 20 ) ]
2718+ #[ case( "0\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9" , 18 ) ]
2719+ fn test_move_to_line_start_multiline ( #[ case] input : & str , #[ case] last_line_start : usize ) {
2720+ let mut reedline = Reedline :: create ( ) ;
2721+
2722+ // Write the string, and then move to the start of the last line.
2723+ let insertion = EditCommand :: InsertString ( String :: from ( input) ) ;
2724+ reedline. run_edit_commands ( & [ insertion] ) ;
2725+
2726+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2727+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2728+
2729+ assert_eq ! (
2730+ reedline. editor. line_buffer( ) . insertion_point( ) ,
2731+ last_line_start
2732+ ) ;
2733+ }
2734+
2735+ #[ rstest]
2736+ #[ case( "a\n b" ) ]
2737+ #[ case( "123456789\n 123456789\n 123456789" ) ]
2738+ #[ case( "0\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9" ) ]
2739+ fn test_move_to_line_start_multiline_history_up_start ( #[ case] input : & str ) {
2740+ let mut reedline = Reedline :: create ( ) ;
2741+
2742+ // Enter the string into history, then scroll back up and move to the start of the line.
2743+ let history = HistoryItem :: from_command_line ( input) ;
2744+ reedline. history . save ( history) . unwrap ( ) ;
2745+
2746+ reedline. previous_history ( ) ;
2747+
2748+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2749+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2750+
2751+ assert_eq ! ( reedline. editor. line_buffer( ) . insertion_point( ) , 0 ) ;
2752+ }
2753+
2754+ #[ rstest]
2755+ #[ case( "a\n b" , 2 ) ]
2756+ #[ case( "123456789\n 123456789\n 123456789" , 10 ) ]
2757+ #[ case( "0\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9" , 2 ) ]
2758+ fn test_move_to_line_start_multiline_history_up_down_start (
2759+ #[ case] input : & str ,
2760+ #[ case] second_line_start : usize ,
2761+ ) {
2762+ let mut reedline = Reedline :: create ( ) ;
2763+
2764+ // Enter the string again, then scroll up in history, move down one line,
2765+ // and move to the start of the second line.
2766+ let history = HistoryItem :: from_command_line ( input) ;
2767+ reedline. history . save ( history) . unwrap ( ) ;
2768+
2769+ reedline. previous_history ( ) ;
2770+
2771+ reedline. down_command ( ) ;
2772+
2773+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2774+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2775+
2776+ assert_eq ! (
2777+ reedline. editor. line_buffer( ) . insertion_point( ) ,
2778+ second_line_start
2779+ ) ;
2780+ }
2781+
2782+ #[ rstest]
2783+ #[ case( "a\n b" , 2 ) ]
2784+ #[ case( "123456789\n 123456789\n 123456789" , 20 ) ]
2785+ #[ case( "0\n 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9" , 18 ) ]
2786+ fn test_move_to_line_start_multiline_history_up_end_start (
2787+ #[ case] input : & str ,
2788+ #[ case] last_line_start : usize ,
2789+ ) {
2790+ let mut reedline = Reedline :: create ( ) ;
2791+
2792+ // Enter the string again, then scroll up in history, move to the end of the text,
2793+ // and move to the start of the last line.
2794+ let history = HistoryItem :: from_command_line ( input) ;
2795+ reedline. history . save ( history) . unwrap ( ) ;
2796+
2797+ reedline. previous_history ( ) ;
2798+
2799+ let move_to_end = EditCommand :: MoveToEnd { select : false } ;
2800+ reedline. run_edit_commands ( & [ move_to_end] ) ;
2801+
2802+ let move_to_start = EditCommand :: MoveToLineStart { select : false } ;
2803+ reedline. run_edit_commands ( & [ move_to_start] ) ;
2804+
2805+ assert_eq ! (
2806+ reedline. editor. line_buffer( ) . insertion_point( ) ,
2807+ last_line_start
2808+ ) ;
2809+ }
2810+
2811+ #[ test]
2812+ fn test_complete_line_from_history ( ) {
2813+ let completer = Box :: new ( DefaultCompleter :: new ( Vec :: from ( [ String :: from ( "67" ) ] ) ) ) ;
2814+ let completion_menu = ReedlineMenu :: EngineCompleter ( Box :: new (
2815+ ColumnarMenu :: default ( ) . with_name ( "completion_menu" ) ,
2816+ ) ) ;
2817+ let mut reedline = Reedline :: create ( )
2818+ . with_quick_completions ( true )
2819+ . with_completer ( completer)
2820+ . with_menu ( completion_menu) ;
2821+
2822+ // Save "6" to the history and scroll back to it
2823+ let history = HistoryItem :: from_command_line ( "6" ) ;
2824+ reedline. history . save ( history) . unwrap ( ) ;
2825+ reedline. previous_history ( ) ;
2826+ assert_eq ! ( reedline. current_buffer_contents( ) , "6" ) ;
2827+
2828+ // Perform quick completion
2829+ let prompt = DefaultPrompt :: default ( ) ;
2830+ let completion = ReedlineEvent :: Menu ( String :: from ( "completion_menu" ) ) ;
2831+ reedline. handle_event ( & prompt, completion) . unwrap ( ) ;
2832+ assert_eq ! ( reedline. current_buffer_contents( ) , "67" ) ;
2833+
2834+ // Insert the "x" to the prompt
2835+ let insertion = EditCommand :: InsertString ( String :: from ( "x" ) ) ;
2836+ reedline. run_edit_commands ( & [ insertion] ) ;
2837+ assert_eq ! ( reedline. current_buffer_contents( ) , "67x" ) ;
2838+ }
26882839}
0 commit comments