@@ -3,6 +3,7 @@ use bstr::BString;
33use crosstermion:: crossterm:: event:: KeyEventKind ;
44use crosstermion:: input:: Key ;
55use dua:: traverse:: { Tree , TreeIndex } ;
6+ use gix_glob:: pattern:: Case ;
67use petgraph:: Direction ;
78use std:: borrow:: Borrow ;
89use tui:: {
@@ -26,16 +27,24 @@ pub struct GlobPaneProps {
2627 pub has_focus : bool ,
2728}
2829
29- #[ derive( Default ) ]
3030pub struct GlobPane {
3131 pub input : String ,
3232 /// The index of the grapheme the cursor currently points to.
3333 /// This hopefully rightfully assumes that a grapheme will be matching the block size on screen
3434 /// and is treated as 'one character'. If not, it will be off, which isn't the end of the world.
3535 // TODO: use `tui-textarea` for proper cursor handling, needs native crossterm events.
3636 cursor_grapheme_idx : usize ,
37- /// Whether the glob search should be case-sensitive
38- pub case_sensitive : bool ,
37+ pub case : Case ,
38+ }
39+
40+ impl Default for GlobPane {
41+ fn default ( ) -> Self {
42+ GlobPane {
43+ input : "" . to_string ( ) ,
44+ cursor_grapheme_idx : 0 ,
45+ case : Case :: Fold ,
46+ }
47+ }
3948}
4049
4150impl GlobPane {
@@ -46,8 +55,11 @@ impl GlobPane {
4655 return ;
4756 }
4857 match key. code {
49- Char ( 'i' ) if key. modifiers . contains ( KeyModifiers :: CONTROL ) => {
50- self . case_sensitive = !self . case_sensitive ;
58+ Char ( 'f' ) if key. modifiers . contains ( KeyModifiers :: CONTROL ) => {
59+ self . case = match self . case {
60+ Case :: Sensitive => Case :: Fold ,
61+ Case :: Fold => Case :: Sensitive ,
62+ } ;
5163 }
5264 Char ( to_insert) => {
5365 self . enter_char ( to_insert) ;
@@ -119,11 +131,11 @@ impl GlobPane {
119131 has_focus,
120132 } = props. borrow ( ) ;
121133
122- let title = if self . case_sensitive {
123- "Git-Glob (case-sensitive)"
124- } else {
125- "Git-Glob (case-insensitive)"
134+ let title = match self . case {
135+ Case :: Sensitive => "Git-Glob (case-sensitive)" ,
136+ Case :: Fold => "Git-Glob (case-insensitive)" ,
126137 } ;
138+
127139 let block = Block :: default ( )
128140 . title ( title)
129141 . border_style ( * border_style)
@@ -156,7 +168,7 @@ impl GlobPane {
156168}
157169
158170fn draw_top_right_help ( area : Rect , title : & str , buf : & mut Buffer ) -> Rect {
159- let help_text = " search = enter | case = ^I | cancel = esc " ;
171+ let help_text = " search = enter | case = ^f | cancel = esc " ;
160172 let help_text_block_width = block_width ( help_text) ;
161173 let bound = Rect {
162174 width : area. width . saturating_sub ( 1 ) ,
@@ -188,7 +200,7 @@ fn glob_search_neighbours(
188200 root_index : TreeIndex ,
189201 glob : & gix_glob:: Pattern ,
190202 path : & mut BString ,
191- case_sensitive : bool ,
203+ case : Case ,
192204) {
193205 for node_index in tree. neighbors_directed ( root_index, Direction :: Outgoing ) {
194206 if let Some ( node) = tree. node_weight ( node_index) {
@@ -200,33 +212,33 @@ fn glob_search_neighbours(
200212 Some ( previous_len + 1 )
201213 } ;
202214 path. extend_from_slice ( gix_path:: into_bstr ( & node. name ) . as_ref ( ) ) ;
203- let case_mode = if case_sensitive {
204- gix_glob:: pattern:: Case :: Sensitive
205- } else {
206- gix_glob:: pattern:: Case :: Fold
207- } ;
208215 if glob. matches_repo_relative_path (
209216 path. as_ref ( ) ,
210217 basename_start,
211218 Some ( node. is_dir ) ,
212- case_mode ,
219+ case ,
213220 gix_glob:: wildmatch:: Mode :: NO_MATCH_SLASH_LITERAL ,
214221 ) {
215222 results. push ( node_index) ;
216223 } else {
217- glob_search_neighbours ( results, tree, node_index, glob, path, case_sensitive ) ;
224+ glob_search_neighbours ( results, tree, node_index, glob, path, case ) ;
218225 }
219226 path. truncate ( previous_len) ;
220227 }
221228 }
222229}
223230
224- pub fn glob_search ( tree : & Tree , root_index : TreeIndex , glob : & str , case_sensitive : bool ) -> Result < Vec < TreeIndex > > {
231+ pub fn glob_search (
232+ tree : & Tree ,
233+ root_index : TreeIndex ,
234+ glob : & str ,
235+ case : gix_glob:: pattern:: Case ,
236+ ) -> Result < Vec < TreeIndex > > {
225237 let glob = gix_glob:: Pattern :: from_bytes_without_negation ( glob. as_bytes ( ) )
226238 . with_context ( || anyhow ! ( "Glob was empty or only whitespace" ) ) ?;
227239 let mut results = Vec :: new ( ) ;
228240 let mut path = Default :: default ( ) ;
229- glob_search_neighbours ( & mut results, tree, root_index, & glob, & mut path, case_sensitive ) ;
241+ glob_search_neighbours ( & mut results, tree, root_index, & glob, & mut path, case ) ;
230242 Ok ( results)
231243}
232244
@@ -236,43 +248,21 @@ mod tests {
236248 use crosstermion:: crossterm:: event:: { KeyCode , KeyEventKind , KeyModifiers } ;
237249
238250 #[ test]
239- fn test_i_key_types_into_input ( ) {
251+ fn ctrl_f_key_types_into_input ( ) {
240252 let mut glob_pane = GlobPane :: default ( ) ;
241253 assert_eq ! ( glob_pane. input, "" ) ;
242- assert ! ( ! glob_pane. case_sensitive ) ; // default is case-insensitive
254+ assert_eq ! ( glob_pane. case , Case :: Fold ) ; // default is case-insensitive
243255
244- // Test that typing 'I' adds it to the input
245- let key_i = Key {
246- code : KeyCode :: Char ( 'I' ) ,
247- modifiers : KeyModifiers :: empty ( ) ,
248- kind : KeyEventKind :: Press ,
249- state : crosstermion:: crossterm:: event:: KeyEventState :: empty ( ) ,
250- } ;
251- glob_pane. process_events ( key_i) ;
252-
253- assert_eq ! ( glob_pane. input, "I" ) ;
254- assert ! ( !glob_pane. case_sensitive) ; // should remain unchanged
255- }
256-
257- #[ test]
258- fn test_ctrl_i_toggles_case_sensitivity ( ) {
259- let mut glob_pane = GlobPane :: default ( ) ;
260- assert ! ( !glob_pane. case_sensitive) ; // default is case-insensitive
261-
262- // Test that Ctrl+I toggles case sensitivity
263- let key_ctrl_i = Key {
264- code : KeyCode :: Char ( 'i' ) ,
256+ let ctrl_f = Key {
257+ code : KeyCode :: Char ( 'f' ) ,
265258 modifiers : KeyModifiers :: CONTROL ,
266259 kind : KeyEventKind :: Press ,
267260 state : crosstermion:: crossterm:: event:: KeyEventState :: empty ( ) ,
268261 } ;
269- glob_pane. process_events ( key_ctrl_i) ;
270-
271- assert_eq ! ( glob_pane. input, "" ) ; // input should remain empty
272- assert ! ( glob_pane. case_sensitive) ; // should toggle to case-sensitive
273-
274- // Test toggling back
275- glob_pane. process_events ( key_ctrl_i) ;
276- assert ! ( ! glob_pane. case_sensitive) ; // should toggle back to case-insensitive
262+ glob_pane. process_events ( ctrl_f) ;
263+ assert_eq ! ( glob_pane. case, Case :: Sensitive ) ;
264+
265+ glob_pane. process_events ( ctrl_f) ;
266+ assert_eq ! ( glob_pane. case, Case :: Fold ) ;
277267 }
278268}
0 commit comments