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}