1
1
use super :: {
2
2
visibility_blocking, CommandBlocking , CommandInfo , Component ,
3
- DrawableComponent , EventState , TextInputComponent ,
3
+ DrawableComponent , EventState , ScrollType , TextInputComponent ,
4
4
} ;
5
5
use crate :: {
6
6
keys:: SharedKeyConfig ,
@@ -29,7 +29,8 @@ pub struct FileFindPopup {
29
29
query : Option < String > ,
30
30
theme : SharedTheme ,
31
31
files : Vec < TreeFile > ,
32
- selection : Option < usize > ,
32
+ selection : usize ,
33
+ selected_index : Option < usize > ,
33
34
files_filtered : Vec < usize > ,
34
35
key_config : SharedKeyConfig ,
35
36
}
@@ -58,8 +59,9 @@ impl FileFindPopup {
58
59
theme,
59
60
files : Vec :: new ( ) ,
60
61
files_filtered : Vec :: new ( ) ,
62
+ selected_index : None ,
61
63
key_config,
62
- selection : None ,
64
+ selection : 0 ,
63
65
}
64
66
}
65
67
@@ -94,22 +96,21 @@ impl FileFindPopup {
94
96
} )
95
97
} ) ,
96
98
) ;
97
-
98
- self . refresh_selection ( ) ;
99
- } else {
100
- self . files_filtered
101
- . extend ( self . files . iter ( ) . enumerate ( ) . map ( |a| a. 0 ) ) ;
102
99
}
100
+
101
+ self . selection = 0 ;
102
+ self . refresh_selection ( ) ;
103
103
}
104
104
105
105
fn refresh_selection ( & mut self ) {
106
- let selection = self . files_filtered . first ( ) . copied ( ) ;
106
+ let selection =
107
+ self . files_filtered . get ( self . selection ) . copied ( ) ;
107
108
108
- if self . selection != selection {
109
- self . selection = selection;
109
+ if self . selected_index != selection {
110
+ self . selected_index = selection;
110
111
111
112
let file = self
112
- . selection
113
+ . selected_index
113
114
. and_then ( |index| self . files . get ( index) )
114
115
. map ( |f| f. path . clone ( ) ) ;
115
116
@@ -129,6 +130,25 @@ impl FileFindPopup {
129
130
130
131
Ok ( ( ) )
131
132
}
133
+
134
+ fn move_selection ( & mut self , move_type : ScrollType ) -> bool {
135
+ let new_selection = match move_type {
136
+ ScrollType :: Up => self . selection . saturating_sub ( 1 ) ,
137
+ ScrollType :: Down => self . selection . saturating_add ( 1 ) ,
138
+ _ => self . selection ,
139
+ } ;
140
+
141
+ let new_selection = new_selection
142
+ . clamp ( 0 , self . files_filtered . len ( ) . saturating_sub ( 1 ) ) ;
143
+
144
+ if new_selection != self . selection {
145
+ self . selection = new_selection;
146
+ self . refresh_selection ( ) ;
147
+ return true ;
148
+ }
149
+
150
+ false
151
+ }
132
152
}
133
153
134
154
impl DrawableComponent for FileFindPopup {
@@ -138,9 +158,28 @@ impl DrawableComponent for FileFindPopup {
138
158
area : Rect ,
139
159
) -> Result < ( ) > {
140
160
if self . is_visible ( ) {
141
- const SIZE : ( u16 , u16 ) = ( 50 , 25 ) ;
142
- let area =
143
- ui:: centered_rect_absolute ( SIZE . 0 , SIZE . 1 , area) ;
161
+ const MAX_SIZE : ( u16 , u16 ) = ( 50 , 20 ) ;
162
+
163
+ let any_hits = !self . files_filtered . is_empty ( ) ;
164
+
165
+ let area = ui:: centered_rect_absolute (
166
+ MAX_SIZE . 0 , MAX_SIZE . 1 , area,
167
+ ) ;
168
+
169
+ let area = if any_hits {
170
+ area
171
+ } else {
172
+ Layout :: default ( )
173
+ . direction ( Direction :: Vertical )
174
+ . constraints (
175
+ [
176
+ Constraint :: Length ( 3 ) ,
177
+ Constraint :: Percentage ( 100 ) ,
178
+ ]
179
+ . as_ref ( ) ,
180
+ )
181
+ . split ( area) [ 0 ]
182
+ } ;
144
183
145
184
f. render_widget ( Clear , area) ;
146
185
f. render_widget (
@@ -155,7 +194,7 @@ impl DrawableComponent for FileFindPopup {
155
194
area,
156
195
) ;
157
196
158
- let area = Layout :: default ( )
197
+ let chunks = Layout :: default ( )
159
198
. direction ( Direction :: Vertical )
160
199
. constraints (
161
200
[
@@ -169,45 +208,46 @@ impl DrawableComponent for FileFindPopup {
169
208
vertical : 1 ,
170
209
} ) ) ;
171
210
172
- self . find_text . draw ( f, area[ 0 ] ) ?;
173
-
174
- let height = usize:: from ( area[ 1 ] . height ) ;
175
- let width = usize:: from ( area[ 1 ] . width ) ;
176
-
177
- let items =
178
- self . files_filtered . iter ( ) . take ( height) . map ( |idx| {
179
- let selected = self
180
- . selection
181
- . map_or ( false , |selection| selection == * idx) ;
182
- Span :: styled (
183
- Cow :: from ( trim_length_left (
184
- self . files [ * idx]
185
- . path
186
- . to_str ( )
187
- . unwrap_or_default ( ) ,
188
- width,
189
- ) ) ,
190
- self . theme . text ( selected, false ) ,
191
- )
192
- } ) ;
193
-
194
- let title = format ! (
195
- "Hits: {}/{}" ,
196
- height. min( self . files_filtered. len( ) ) ,
197
- self . files_filtered. len( )
198
- ) ;
199
-
200
- ui:: draw_list_block (
201
- f,
202
- area[ 1 ] ,
203
- Block :: default ( )
204
- . title ( Span :: styled (
205
- title,
206
- self . theme . title ( true ) ,
207
- ) )
208
- . borders ( Borders :: TOP ) ,
209
- items,
210
- ) ;
211
+ self . find_text . draw ( f, chunks[ 0 ] ) ?;
212
+
213
+ if any_hits {
214
+ let title =
215
+ format ! ( "Hits: {}" , self . files_filtered. len( ) ) ;
216
+
217
+ let height = usize:: from ( chunks[ 1 ] . height ) ;
218
+ let width = usize:: from ( chunks[ 1 ] . width ) ;
219
+
220
+ let items =
221
+ self . files_filtered . iter ( ) . take ( height) . map (
222
+ |idx| {
223
+ let selected = self
224
+ . selected_index
225
+ . map_or ( false , |index| index == * idx) ;
226
+ Span :: styled (
227
+ Cow :: from ( trim_length_left (
228
+ self . files [ * idx]
229
+ . path
230
+ . to_str ( )
231
+ . unwrap_or_default ( ) ,
232
+ width,
233
+ ) ) ,
234
+ self . theme . text ( selected, false ) ,
235
+ )
236
+ } ,
237
+ ) ;
238
+
239
+ ui:: draw_list_block (
240
+ f,
241
+ chunks[ 1 ] ,
242
+ Block :: default ( )
243
+ . title ( Span :: styled (
244
+ title,
245
+ self . theme . title ( true ) ,
246
+ ) )
247
+ . borders ( Borders :: TOP ) ,
248
+ items,
249
+ ) ;
250
+ }
211
251
}
212
252
Ok ( ( ) )
213
253
}
@@ -228,6 +268,12 @@ impl Component for FileFindPopup {
228
268
)
229
269
. order ( 1 ) ,
230
270
) ;
271
+
272
+ out. push ( CommandInfo :: new (
273
+ strings:: commands:: scroll ( & self . key_config ) ,
274
+ true ,
275
+ true ,
276
+ ) ) ;
231
277
}
232
278
233
279
visibility_blocking ( self )
@@ -243,6 +289,10 @@ impl Component for FileFindPopup {
243
289
|| * key == self . key_config . enter
244
290
{
245
291
self . hide ( ) ;
292
+ } else if * key == self . key_config . move_down {
293
+ self . move_selection ( ScrollType :: Down ) ;
294
+ } else if * key == self . key_config . move_up {
295
+ self . move_selection ( ScrollType :: Up ) ;
246
296
}
247
297
}
248
298
0 commit comments