pacsea/ui/helpers/filter.rs
1//! Filtering utilities for pane-specific index calculations.
2//!
3//! This module provides functions for filtering indices in the Recent and Install panes
4//! based on pane-find queries.
5
6use crate::state::types::AppMode;
7use crate::state::{AppState, Focus};
8
9/// What: Produce visible indices into `app.recent` considering pane-find when applicable.
10///
11/// Inputs:
12/// - `app`: Application state (focus, `pane_find`, recent list)
13///
14/// Output:
15/// - Vector of indices in ascending order without modifying application state.
16///
17/// # Panics
18/// - Panics if `pane_find` is `Some` but becomes `None` between the check and the `expect` call (should not happen in single-threaded usage)
19///
20/// Details:
21/// - Applies pane find filtering only when the Recent pane is focused and the finder string is
22/// non-empty; otherwise returns the full range.
23#[must_use]
24pub fn filtered_recent_indices(app: &AppState) -> Vec<usize> {
25 let apply =
26 matches!(app.focus, Focus::Recent) && app.pane_find.as_ref().is_some_and(|s| !s.is_empty());
27 let recents = if matches!(app.app_mode, AppMode::News) {
28 app.news_recent_values()
29 } else {
30 app.recent_values()
31 };
32 if !apply {
33 return (0..recents.len()).collect();
34 }
35 let pat = app
36 .pane_find
37 .as_ref()
38 .expect("pane_find should be Some when apply is true")
39 .to_lowercase();
40 recents
41 .iter()
42 .enumerate()
43 .filter_map(|(i, s)| {
44 if s.to_lowercase().contains(&pat) {
45 Some(i)
46 } else {
47 None
48 }
49 })
50 .collect()
51}
52
53/// What: Produce visible indices into `app.install_list` with optional pane-find filtering.
54///
55/// Inputs:
56/// - `app`: Application state (focus, `pane_find`, install list)
57///
58/// Output:
59/// - Vector of indices in ascending order without modifying application state.
60///
61/// # Panics
62/// - Panics if `pane_find` is `Some` but becomes `None` between the check and the `expect` call (should not happen in single-threaded usage)
63///
64/// Details:
65/// - Restricts matches to name or description substrings when the Install pane is focused and a
66/// pane-find expression is active; otherwise surfaces all indices.
67#[must_use]
68pub fn filtered_install_indices(app: &AppState) -> Vec<usize> {
69 let apply = matches!(app.focus, Focus::Install)
70 && app.pane_find.as_ref().is_some_and(|s| !s.is_empty());
71 if !apply {
72 return (0..app.install_list.len()).collect();
73 }
74 let pat = app
75 .pane_find
76 .as_ref()
77 .expect("pane_find should be Some when apply is true")
78 .to_lowercase();
79 app.install_list
80 .iter()
81 .enumerate()
82 .filter_map(|(i, p)| {
83 let name = p.name.to_lowercase();
84 let desc = p.description.to_lowercase();
85 if name.contains(&pat) || desc.contains(&pat) {
86 Some(i)
87 } else {
88 None
89 }
90 })
91 .collect()
92}