@@ -5477,6 +5477,26 @@ impl App {
54775477 }
54785478 false
54795479 }
5480+ "moveRight" => {
5481+ // Right arrow: accept the typeahead suggestion when the
5482+ // cursor sits at the end of the input (fish-style);
5483+ // otherwise move the cursor. Acceptance works while
5484+ // streaming so the popup stays interactive when a turn is
5485+ // in flight — Enter then queues the completed command.
5486+ if !self . prompt_input . suggestions . is_empty ( )
5487+ && self . prompt_input . cursor == self . prompt_input . text . len ( )
5488+ {
5489+ if self . prompt_input . suggestion_index . is_none ( ) {
5490+ self . prompt_input . suggestion_index = Some ( 0 ) ;
5491+ }
5492+ self . prompt_input . accept_suggestion ( ) ;
5493+ self . refresh_prompt_input ( ) ;
5494+ } else {
5495+ self . prompt_input . move_right ( ) ;
5496+ self . sync_legacy_prompt_fields ( ) ;
5497+ }
5498+ false
5499+ }
54805500 "killToStart" => {
54815501 if !self . is_streaming {
54825502 self . prompt_input . kill_line_backward ( ) ;
@@ -5652,19 +5672,19 @@ impl App {
56525672 false
56535673 }
56545674 "indent" => {
5655- // Tab: cycle agent mode when prompt is empty, accept
5656- // slash-command suggestion otherwise.
5657- if !self . is_streaming {
5658- if !self . prompt_input . suggestions . is_empty ( ) {
5659- if self . prompt_input . suggestion_index . is_none ( ) {
5660- self . prompt_input . suggestion_index = Some ( 0 ) ;
5661- }
5662- self . prompt_input . accept_suggestion ( ) ;
5663- self . refresh_prompt_input ( ) ;
5664- } else if self . prompt_input . is_empty ( ) {
5665- self . cycle_agent_mode ( ) ;
5666- self . companion_look_down ( ) ;
5675+ // Tab: accept the typeahead suggestion, or cycle agent mode
5676+ // when the prompt is empty. Acceptance is allowed while
5677+ // streaming so the popup stays interactive when a turn is
5678+ // in flight — Enter then queues the completed command.
5679+ if !self . prompt_input . suggestions . is_empty ( ) {
5680+ if self . prompt_input . suggestion_index . is_none ( ) {
5681+ self . prompt_input . suggestion_index = Some ( 0 ) ;
56675682 }
5683+ self . prompt_input . accept_suggestion ( ) ;
5684+ self . refresh_prompt_input ( ) ;
5685+ } else if !self . is_streaming && self . prompt_input . is_empty ( ) {
5686+ self . cycle_agent_mode ( ) ;
5687+ self . companion_look_down ( ) ;
56685688 }
56695689 false
56705690 }
@@ -8041,6 +8061,57 @@ role = "Research"
80418061 assert ! ( app. has_credentials) ;
80428062 }
80438063
8064+ #[ test]
8065+ fn right_arrow_at_end_accepts_typeahead_suggestion ( ) {
8066+ let mut app = make_app ( ) ;
8067+ app. prompt_input . text = "/mode" . to_string ( ) ;
8068+ app. prompt_input . cursor = app. prompt_input . text . len ( ) ;
8069+ app. refresh_prompt_input ( ) ;
8070+ assert ! (
8071+ !app. prompt_input. suggestions. is_empty( ) ,
8072+ "typing /mode must surface the /model suggestion"
8073+ ) ;
8074+
8075+ app. handle_keybinding_action ( "moveRight" ) ;
8076+
8077+ assert_eq ! ( app. prompt_input. text, "/model" ) ;
8078+ assert_eq ! ( app. prompt_input. cursor, app. prompt_input. text. len( ) ) ;
8079+ }
8080+
8081+ #[ test]
8082+ fn right_arrow_mid_text_moves_cursor_without_accepting ( ) {
8083+ let mut app = make_app ( ) ;
8084+ app. prompt_input . text = "/mode" . to_string ( ) ;
8085+ app. prompt_input . cursor = 1 ;
8086+ app. refresh_prompt_input ( ) ;
8087+ assert ! ( !app. prompt_input. suggestions. is_empty( ) ) ;
8088+
8089+ app. handle_keybinding_action ( "moveRight" ) ;
8090+
8091+ assert_eq ! (
8092+ app. prompt_input. text, "/mode" ,
8093+ "right arrow mid-text must move the cursor, not accept"
8094+ ) ;
8095+ assert_eq ! ( app. prompt_input. cursor, 2 ) ;
8096+ }
8097+
8098+ #[ test]
8099+ fn tab_accepts_typeahead_suggestion_while_streaming ( ) {
8100+ let mut app = make_app ( ) ;
8101+ app. is_streaming = true ;
8102+ app. prompt_input . text = "/mode" . to_string ( ) ;
8103+ app. prompt_input . cursor = app. prompt_input . text . len ( ) ;
8104+ app. refresh_prompt_input ( ) ;
8105+ assert ! ( !app. prompt_input. suggestions. is_empty( ) ) ;
8106+
8107+ app. handle_keybinding_action ( "indent" ) ;
8108+
8109+ assert_eq ! (
8110+ app. prompt_input. text, "/model" ,
8111+ "Tab must accept the suggestion even while a turn is streaming"
8112+ ) ;
8113+ }
8114+
80448115 #[ test]
80458116 fn model_picker_accepts_openai_codex_alias ( ) {
80468117 let temp = tempfile:: tempdir ( ) . expect ( "tempdir" ) ;
0 commit comments