@@ -107,7 +107,8 @@ impl LogSearchPopupPopup {
107107 self . mode = PopupMode :: JumpCommitSha ;
108108 self . jump_commit_id = None ;
109109 self . find_text . set_default_msg ( "commit sha" . into ( ) ) ;
110- self . find_text . enabled ( false ) ;
110+ // Field stays focused; invalid SHA is shown via block style.
111+ self . find_text . enabled ( true ) ;
111112 self . selection = Selection :: EnterText ;
112113 }
113114 }
@@ -164,106 +165,66 @@ impl LogSearchPopupPopup {
164165 }
165166 }
166167
167- fn get_text_options ( & self ) -> Vec < Line < ' _ > > {
168- let x_summary =
169- if self . options . 0 . contains ( SearchFields :: MESSAGE_SUMMARY )
170- {
171- "X"
172- } else {
173- " "
174- } ;
175-
176- let x_body =
177- if self . options . 0 . contains ( SearchFields :: MESSAGE_BODY ) {
178- "X"
179- } else {
180- " "
181- } ;
182-
183- let x_files =
184- if self . options . 0 . contains ( SearchFields :: FILENAMES ) {
185- "X"
186- } else {
187- " "
188- } ;
189-
190- let x_authors =
191- if self . options . 0 . contains ( SearchFields :: AUTHORS ) {
192- "X"
193- } else {
194- " "
195- } ;
196-
197- let x_opt_fuzzy =
198- if self . options . 1 . contains ( SearchOptions :: FUZZY_SEARCH ) {
199- "X"
200- } else {
201- " "
202- } ;
168+ fn option_mark ( on : bool ) -> & ' static str {
169+ if on {
170+ "X"
171+ } else {
172+ " "
173+ }
174+ }
203175
204- let x_opt_casesensitive =
205- if self . options . 1 . contains ( SearchOptions :: CASE_SENSITIVE )
206- {
207- "X"
208- } else {
209- " "
210- } ;
176+ fn option_line (
177+ & self ,
178+ checked : bool ,
179+ label : & str ,
180+ selected : bool ,
181+ ) -> Line < ' _ > {
182+ Line :: from ( vec ! [ Span :: styled(
183+ format!( "[{}] {label}" , Self :: option_mark( checked) ) ,
184+ // enabled=true keeps normal fg; selected applies selection_bg
185+ self . theme. text( true , selected) ,
186+ ) ] )
187+ }
211188
189+ fn get_text_options ( & self ) -> Vec < Line < ' _ > > {
212190 vec ! [
213- Line :: from( vec![ Span :: styled(
214- format!( "[{x_opt_fuzzy}] fuzzy search" ) ,
215- self . theme. text(
216- matches!( self . selection, Selection :: FuzzyOption ) ,
217- false ,
218- ) ,
219- ) ] ) ,
220- Line :: from( vec![ Span :: styled(
221- format!( "[{x_opt_casesensitive}] case sensitive" ) ,
222- self . theme. text(
223- matches!( self . selection, Selection :: CaseOption ) ,
224- false ,
225- ) ,
226- ) ] ) ,
227- Line :: from( vec![ Span :: styled(
228- format!( "[{x_summary}] summary" ) ,
229- self . theme. text(
230- matches!(
231- self . selection,
232- Selection :: SummarySearch
233- ) ,
234- false ,
235- ) ,
236- ) ] ) ,
237- Line :: from( vec![ Span :: styled(
238- format!( "[{x_body}] message body" ) ,
239- self . theme. text(
240- matches!(
241- self . selection,
242- Selection :: MessageBodySearch
243- ) ,
244- false ,
245- ) ,
246- ) ] ) ,
247- Line :: from( vec![ Span :: styled(
248- format!( "[{x_files}] committed files" ) ,
249- self . theme. text(
250- matches!(
251- self . selection,
252- Selection :: FilenameSearch
253- ) ,
254- false ,
255- ) ,
256- ) ] ) ,
257- Line :: from( vec![ Span :: styled(
258- format!( "[{x_authors}] authors" ) ,
259- self . theme. text(
260- matches!(
261- self . selection,
262- Selection :: AuthorsSearch
263- ) ,
264- false ,
191+ self . option_line(
192+ self . options. 1 . contains( SearchOptions :: FUZZY_SEARCH ) ,
193+ "fuzzy search" ,
194+ matches!( self . selection, Selection :: FuzzyOption ) ,
195+ ) ,
196+ self . option_line(
197+ self . options
198+ . 1
199+ . contains( SearchOptions :: CASE_SENSITIVE ) ,
200+ "case sensitive" ,
201+ matches!( self . selection, Selection :: CaseOption ) ,
202+ ) ,
203+ self . option_line(
204+ self . options
205+ . 0
206+ . contains( SearchFields :: MESSAGE_SUMMARY ) ,
207+ "summary" ,
208+ matches!( self . selection, Selection :: SummarySearch ) ,
209+ ) ,
210+ self . option_line(
211+ self . options. 0 . contains( SearchFields :: MESSAGE_BODY ) ,
212+ "message body" ,
213+ matches!(
214+ self . selection,
215+ Selection :: MessageBodySearch
265216 ) ,
266- ) ] ) ,
217+ ) ,
218+ self . option_line(
219+ self . options. 0 . contains( SearchFields :: FILENAMES ) ,
220+ "committed files" ,
221+ matches!( self . selection, Selection :: FilenameSearch ) ,
222+ ) ,
223+ self . option_line(
224+ self . options. 0 . contains( SearchFields :: AUTHORS ) ,
225+ "authors" ,
226+ matches!( self . selection, Selection :: AuthorsSearch ) ,
227+ ) ,
267228 ]
268229 }
269230
@@ -315,7 +276,7 @@ impl LogSearchPopupPopup {
315276 }
316277 }
317278
318- const fn move_selection ( & mut self , arg : bool ) {
279+ fn move_selection ( & mut self , arg : bool ) {
319280 if arg {
320281 //up
321282 self . selection = match self . selection {
@@ -513,9 +474,6 @@ impl LogSearchPopupPopup {
513474 self . execute_confirm ( ) ;
514475 } else if self . find_text . event ( event) ?. is_consumed ( ) {
515476 self . validate_commit_sha ( ) ;
516- self . find_text . enabled (
517- !self . find_text . get_text ( ) . trim ( ) . is_empty ( ) ,
518- ) ;
519477 }
520478 }
521479
@@ -629,3 +587,58 @@ impl Component for LogSearchPopupPopup {
629587 Ok ( ( ) )
630588 }
631589}
590+
591+ #[ cfg( test) ]
592+ mod tests {
593+ use super :: * ;
594+ use crate :: app:: Environment ;
595+ use crossterm:: event:: { KeyCode , KeyEvent , KeyModifiers } ;
596+ use ratatui:: { backend:: TestBackend , style:: Color , Terminal } ;
597+
598+ fn key ( code : KeyCode ) -> Event {
599+ Event :: Key ( KeyEvent :: new ( code, KeyModifiers :: NONE ) )
600+ }
601+
602+ #[ test]
603+ fn search_option_selection_uses_selection_background ( ) {
604+ let env = Environment :: test_env ( ) ;
605+ let mut popup = LogSearchPopupPopup :: new ( & env) ;
606+ popup. open ( ) . unwrap ( ) ;
607+
608+ // Move focus from the text field onto the first option.
609+ popup. event ( & key ( KeyCode :: Down ) ) . unwrap ( ) ;
610+
611+ let backend = TestBackend :: new ( 80 , 24 ) ;
612+ let mut terminal = Terminal :: new ( backend) . unwrap ( ) ;
613+ terminal
614+ . draw ( |f| {
615+ popup. draw ( f, f. area ( ) ) . unwrap ( ) ;
616+ } )
617+ . unwrap ( ) ;
618+
619+ let buf = terminal. backend ( ) . buffer ( ) ;
620+ // Find the "fuzzy search" row and assert it has selection_bg.
621+ let mut found_selected = false ;
622+ let area = * buf. area ( ) ;
623+ for y in area. top ( ) ..area. bottom ( ) {
624+ for x in area. left ( ) ..area. right ( ) {
625+ let cell = & buf[ ( x, y) ] ;
626+ if cell. symbol ( ) == "f"
627+ && cell. fg == Color :: White
628+ && cell. bg == Color :: Blue
629+ {
630+ // Selection highlight: command_fg on selection_bg
631+ found_selected = true ;
632+ break ;
633+ }
634+ }
635+ if found_selected {
636+ break ;
637+ }
638+ }
639+ assert ! (
640+ found_selected,
641+ "focused search option should use selection background"
642+ ) ;
643+ }
644+ }
0 commit comments