@@ -27,7 +27,7 @@ impl Default for LayoutListScreen {
2727 retain_plugin_panes : false ,
2828 apply_only_to_active_tab : false ,
2929 show_more_override_options : false ,
30- search_state : SearchState :: new ( ) ,
30+ search_state : SearchState :: new_in_search_mode ( ) ,
3131 last_rows : 0 ,
3232 last_cols : 0 ,
3333 }
@@ -42,7 +42,7 @@ impl LayoutListScreen {
4242 retain_plugin_panes : false ,
4343 apply_only_to_active_tab : false ,
4444 show_more_override_options : false ,
45- search_state : SearchState :: new ( ) ,
45+ search_state : SearchState :: new_in_search_mode ( ) ,
4646 last_rows : 0 ,
4747 last_cols : 0 ,
4848 }
@@ -101,7 +101,7 @@ impl LayoutListScreen {
101101 self . open_selected_layout ( display_layouts) ;
102102 KeyResponse :: none ( )
103103 } ,
104- BareKey :: Tab if key. has_no_modifiers ( ) => {
104+ BareKey :: Char ( 'o' ) if key. has_modifiers ( & [ KeyModifier :: Ctrl ] ) => {
105105 self . apply_selected_layout ( display_layouts) ;
106106 KeyResponse :: none ( )
107107 } ,
@@ -125,8 +125,8 @@ impl LayoutListScreen {
125125 KeyResponse :: render ( )
126126 } ,
127127 BareKey :: Esc if key. has_no_modifiers ( ) => {
128- self . clear_filter ( ) ;
129- KeyResponse :: render ( )
128+ close_self ( ) ;
129+ KeyResponse :: none ( )
130130 } ,
131131 _ => KeyResponse :: none ( ) ,
132132 }
@@ -138,27 +138,50 @@ impl LayoutListScreen {
138138 key : KeyWithModifier ,
139139 display_layouts : & [ DisplayLayout ] ,
140140 ) -> KeyResponse {
141- // Special handling for Enter and Esc
141+ // Search-first mode: Enter opens, Ctrl+O applies, Tab autocompletes,
142+ // arrows navigate, Esc exits to management mode
142143 match key. bare_key {
143144 BareKey :: Esc if key. has_no_modifiers ( ) => {
144- self . clear_filter ( ) ;
145+ // Clear text first; only exit to management mode if already empty
146+ if self . search_state . get_filter_input ( ) . is_empty ( ) {
147+ self . clear_filter ( ) ;
148+ } else {
149+ self . search_state . get_filter_input_mut ( ) . clear ( ) ;
150+ self . update_filter ( display_layouts) ;
151+ }
145152 return KeyResponse :: render ( ) ;
146153 } ,
147154 BareKey :: Enter if key. has_no_modifiers ( ) => {
148- if self . search_state . get_filter_input ( ) . is_empty ( )
149- || self . search_state . get_search_results ( ) . is_empty ( )
150- {
151- self . clear_filter ( ) ;
152- } else {
153- self . search_state . stop_typing ( ) ;
154- show_cursor ( None ) ;
155+ // Open the currently selected layout as new tab(s)
156+ self . open_selected_layout ( display_layouts) ;
157+ return KeyResponse :: none ( ) ;
158+ } ,
159+ BareKey :: Char ( 'o' ) if key. has_modifiers ( & [ KeyModifier :: Ctrl ] ) => {
160+ // Apply/override the currently selected layout to the session
161+ self . apply_selected_layout ( display_layouts) ;
162+ return KeyResponse :: none ( ) ;
163+ } ,
164+ BareKey :: Tab if key. has_no_modifiers ( ) => {
165+ // Complete: fill input with selected match name
166+ if self . search_state . fill_input_with_selected_match ( ) {
167+ self . update_filter ( display_layouts) ;
155168 }
156169 return KeyResponse :: render ( ) ;
157170 } ,
171+ BareKey :: Up if key. has_no_modifiers ( ) => {
172+ // Navigate filtered results while typing
173+ self . navigate_up ( display_layouts) ;
174+ return KeyResponse :: render ( ) ;
175+ } ,
176+ BareKey :: Down if key. has_no_modifiers ( ) => {
177+ // Navigate filtered results while typing
178+ self . navigate_down ( display_layouts) ;
179+ return KeyResponse :: render ( ) ;
180+ } ,
158181 _ => { } ,
159182 }
160183
161- // Pass all keys to TextInput
184+ // Pass remaining keys to TextInput
162185 let action = self . search_state . get_filter_input_mut ( ) . handle_key ( key) ;
163186
164187 match action {
@@ -167,8 +190,13 @@ impl LayoutListScreen {
167190 KeyResponse :: render ( )
168191 } ,
169192 InputAction :: Cancel => {
170- // Ctrl-C or Esc - clear filter
171- self . clear_filter ( ) ;
193+ // Ctrl-C - clear text first; only exit to management mode if already empty
194+ if self . search_state . get_filter_input ( ) . is_empty ( ) {
195+ self . clear_filter ( ) ;
196+ } else {
197+ self . search_state . get_filter_input_mut ( ) . clear ( ) ;
198+ self . update_filter ( display_layouts) ;
199+ }
172200 KeyResponse :: render ( )
173201 } ,
174202 InputAction :: Submit => {
@@ -304,6 +332,7 @@ impl LayoutListScreen {
304332 self . apply_only_to_active_tab ,
305333 Default :: default ( ) ,
306334 ) ;
335+ close_self ( ) ;
307336 }
308337 }
309338
@@ -364,10 +393,16 @@ impl LayoutListScreen {
364393 }
365394
366395 fn open_selected_layout ( & self , display_layouts : & [ DisplayLayout ] ) {
367- if let Some ( DisplayLayout :: Valid ( chosen_layout) ) =
368- display_layouts. get ( self . selected_layout_index )
369- {
370- new_tabs_with_layout_info ( chosen_layout) ;
396+ let selected = display_layouts. get ( self . selected_layout_index ) ;
397+ if let Some ( DisplayLayout :: Valid ( chosen_layout) ) = selected {
398+ let tab_ids = new_tabs_with_layout_info ( chosen_layout) ;
399+ if self . should_default_to_current_tab ( display_layouts) {
400+ if let Some ( & tab_id) = tab_ids. first ( ) {
401+ let layout_name = selected. unwrap ( ) . name ( ) ;
402+ rename_tab_with_id ( tab_id as u64 , layout_name) ;
403+ }
404+ }
405+ close_self ( ) ;
371406 }
372407 }
373408
@@ -385,6 +420,13 @@ impl LayoutListScreen {
385420 let ( base_x, base_y) =
386421 self . calculate_base_coordinates ( rows, cols, total_width, total_height) ;
387422
423+ // In search mode, shift everything down by 1 row
424+ let base_y = if self . search_state . is_typing ( ) || self . search_state . is_active ( ) {
425+ base_y + 1
426+ } else {
427+ base_y
428+ } ;
429+
388430 let layouts_to_render = self . effective_layouts ( display_layouts) ;
389431 let ( content_height, controls_y) = self . calculate_layout ( rows, & display_layouts) ;
390432
@@ -461,13 +503,17 @@ impl LayoutListScreen {
461503 let rows_in_table = display_layouts. len ( ) + 1 ; // 1 for the title row
462504 let controls_height = self . get_controls_height ( ) ;
463505 let filter_row_height = if self . is_searching ( ) { 1 } else { 0 } ;
506+ let search_mode_offset = if self . is_searching ( ) { 1 } else { 0 } ;
464507 let padding = 1 ;
465508 let mut content_height = std:: cmp:: max ( rows_in_table, 5 ) ;
466- if content_height + controls_height + padding + filter_row_height >= rows {
509+ if content_height + controls_height + padding + filter_row_height + search_mode_offset
510+ >= rows
511+ {
467512 content_height = rows
468513 . saturating_sub ( controls_height)
469514 . saturating_sub ( padding)
470515 . saturating_sub ( filter_row_height)
516+ . saturating_sub ( search_mode_offset)
471517 }
472518 let controls_y = content_height + padding + filter_row_height;
473519
@@ -520,10 +566,12 @@ impl LayoutListScreen {
520566 display_layouts : & [ DisplayLayout ] ,
521567 ) -> ( usize , usize ) {
522568 let filter_row_height = if self . is_searching ( ) { 1 } else { 0 } ;
569+ let search_mode_offset = if self . is_searching ( ) { 1 } else { 0 } ;
523570 let ( content_height, _) = self . calculate_layout ( rows, display_layouts) ;
524571 let padding = 1 ;
525572 let controls_height = self . get_controls_height ( ) ;
526- let total_height = filter_row_height + content_height + padding + controls_height;
573+ let total_height =
574+ filter_row_height + search_mode_offset + content_height + padding + controls_height;
527575
528576 let controls = Controls :: new (
529577 self . retain_terminal_panes ,
@@ -612,6 +660,13 @@ impl LayoutListScreen {
612660 total_height,
613661 ) ;
614662
663+ // In search mode, cursor must account for the extra row offset
664+ let base_y = if self . search_state . is_typing ( ) || self . search_state . is_active ( ) {
665+ base_y + 1
666+ } else {
667+ base_y
668+ } ;
669+
615670 self . search_state
616671 . update_filter ( display_layouts, base_x, base_y) ;
617672
0 commit comments