@@ -18,6 +18,16 @@ use crate::output::version_label;
1818const LIST_PAGE_SIZE : usize = 20 ;
1919const NO_MATCHES_LABEL : & str = " No matches" ;
2020
21+ struct PageRenderState < ' a > {
22+ prompt : & ' a str ,
23+ search_term : & ' a str ,
24+ cursor : usize ,
25+ filtered : & ' a [ ( usize , String ) ] ,
26+ selection : Option < usize > ,
27+ page_start : usize ,
28+ page_size : usize ,
29+ }
30+
2131/// Returns `true` when interactive prompts are safe to show.
2232pub fn should_use_interactive_tui ( ) -> bool {
2333 // Skip prompts in CI even if the streams look interactive so scripted runs stay deterministic.
@@ -143,13 +153,15 @@ fn pageable_fuzzy_select(prompt: &str, items: &[String]) -> Result<Option<usize>
143153 render_page (
144154 & term,
145155 & theme,
146- prompt,
147- & search_term,
148- cursor,
149- & filtered,
150- selection,
151- page_start,
152- page_size,
156+ PageRenderState {
157+ prompt,
158+ search_term : & search_term,
159+ cursor,
160+ filtered : & filtered,
161+ selection,
162+ page_start,
163+ page_size,
164+ } ,
153165 ) ?;
154166 rendered_lines = rendered_line_count ( & filtered, page_start, page_size) ;
155167 term. flush ( ) ?;
@@ -244,46 +256,36 @@ fn pageable_fuzzy_select(prompt: &str, items: &[String]) -> Result<Option<usize>
244256 }
245257}
246258
247- fn render_page (
248- term : & Term ,
249- theme : & dyn Theme ,
250- prompt : & str ,
251- search_term : & str ,
252- cursor : usize ,
253- filtered : & [ ( usize , String ) ] ,
254- selection : Option < usize > ,
255- page_start : usize ,
256- page_size : usize ,
257- ) -> Result < ( ) > {
259+ fn render_page ( term : & Term , theme : & dyn Theme , state : PageRenderState < ' _ > ) -> Result < ( ) > {
258260 let prompt_line = format_fuzzy_prompt (
259261 theme,
260- prompt,
261- search_term,
262- cursor,
263- filtered. len ( ) ,
264- page_start,
265- page_size,
262+ state . prompt ,
263+ state . search_term ,
264+ state . cursor ,
265+ state . filtered . len ( ) ,
266+ state . page_start ,
267+ state . page_size ,
266268 ) ?;
267269 term. write_line ( & prompt_line) ?;
268270
269- if filtered. is_empty ( ) {
271+ if state . filtered . is_empty ( ) {
270272 term. write_line ( NO_MATCHES_LABEL ) ?;
271273 return Ok ( ( ) ) ;
272274 }
273275
274276 let matcher = SkimMatcherV2 :: default ( ) ;
275277 let highlight_matches = true ;
276- let end = ( page_start + page_size) . min ( filtered. len ( ) ) ;
278+ let end = ( state . page_start + state . page_size ) . min ( state . filtered . len ( ) ) ;
277279
278- for ( visible_idx, ( _, item) ) in filtered[ page_start..end] . iter ( ) . enumerate ( ) {
279- let active = selection == Some ( page_start + visible_idx) ;
280+ for ( visible_idx, ( _, item) ) in state . filtered [ state . page_start ..end] . iter ( ) . enumerate ( ) {
281+ let active = state . selection == Some ( state . page_start + visible_idx) ;
280282 let line = format_fuzzy_item (
281283 theme,
282284 item,
283285 active,
284286 highlight_matches,
285287 & matcher,
286- search_term,
288+ state . search_term ,
287289 ) ?;
288290 term. write_line ( & line) ?;
289291 }
@@ -410,7 +412,7 @@ fn normalize_state(
410412}
411413
412414fn page_size_for_rows ( rows : usize ) -> usize {
413- ( rows. max ( 3 ) - 2 ) . min ( LIST_PAGE_SIZE ) . max ( 1 )
415+ ( rows. max ( 3 ) - 2 ) . clamp ( 1 , LIST_PAGE_SIZE )
414416}
415417
416418fn last_page_start ( total_items : usize , page_size : usize ) -> usize {
0 commit comments