use crate::state::{AppState, PackageItem, Source};
#[inline]
fn return_if_true(cond: bool, it: PackageItem, out: &mut Vec<PackageItem>) {
if cond {
out.push(it);
}
}
pub fn apply_filters_and_sort_preserve_selection(app: &mut AppState) {
let prev_name = app.results.get(app.selected).map(|p| p.name.clone());
let mut filtered: Vec<PackageItem> = Vec::with_capacity(app.all_results.len());
for it in app.all_results.iter().cloned() {
let include = match &it.source {
Source::Aur => app.results_filter_show_aur,
Source::Official { repo, .. } => {
let owner = app
.details_cache
.get(&it.name)
.map(|d| d.owner.clone())
.unwrap_or_default();
if crate::index::is_manjaro_name_or_owner(&it.name, &owner) {
return_if_true(app.results_filter_show_manjaro, it, &mut filtered);
continue;
}
crate::logic::distro::repo_toggle_for(repo, app)
}
};
if include {
filtered.push(it);
}
}
app.results = filtered;
crate::logic::invalidate_sort_caches(app);
crate::logic::sort_results_preserve_selection(app);
if let Some(name) = prev_name {
if let Some(pos) = app.results.iter().position(|p| p.name == name) {
app.selected = pos;
app.list_state.select(Some(pos));
} else if !app.results.is_empty() {
app.selected = app.selected.min(app.results.len() - 1);
app.list_state.select(Some(app.selected));
} else {
app.selected = 0;
app.list_state.select(None);
}
} else if app.results.is_empty() {
app.selected = 0;
app.list_state.select(None);
} else {
app.selected = app.selected.min(app.results.len() - 1);
app.list_state.select(Some(app.selected));
}
}
#[cfg(test)]
mod tests {
use super::*;
fn item_official(name: &str, repo: &str) -> PackageItem {
PackageItem {
name: name.to_string(),
version: "1.0".to_string(),
description: format!("{name} desc"),
source: Source::Official {
repo: repo.to_string(),
arch: "x86_64".to_string(),
},
popularity: None,
out_of_date: None,
orphaned: false,
}
}
#[test]
fn apply_filters_and_preserve_selection() {
let mut app = AppState {
all_results: vec![
PackageItem {
name: "aur1".into(),
version: "1".into(),
description: String::new(),
source: Source::Aur,
popularity: Some(1.0),
out_of_date: None,
orphaned: false,
},
item_official("core1", "core"),
item_official("extra1", "extra"),
item_official("other1", "community"),
],
results_filter_show_aur: false,
results_filter_show_core: true,
results_filter_show_extra: false,
results_filter_show_multilib: false,
..Default::default()
};
apply_filters_and_sort_preserve_selection(&mut app);
assert!(app.results.iter().all(
|p| matches!(&p.source, Source::Official{repo, ..} if repo.eq_ignore_ascii_case("core"))
));
}
#[test]
fn apply_filters_cachyos_and_eos_interaction() {
let mut app = AppState {
all_results: vec![
PackageItem {
name: "cx".into(),
version: "1".into(),
description: String::new(),
source: Source::Official {
repo: "cachyos-core".into(),
arch: "x86_64".into(),
},
popularity: None,
out_of_date: None,
orphaned: false,
},
PackageItem {
name: "ey".into(),
version: "1".into(),
description: String::new(),
source: Source::Official {
repo: "endeavouros".into(),
arch: "x86_64".into(),
},
popularity: None,
out_of_date: None,
orphaned: false,
},
item_official("core1", "core"),
],
results_filter_show_core: true,
results_filter_show_extra: true,
results_filter_show_multilib: true,
results_filter_show_eos: false,
results_filter_show_cachyos: true,
..Default::default()
};
apply_filters_and_sort_preserve_selection(&mut app);
assert!(app.results.iter().any(|p| match &p.source {
Source::Official { repo, .. } => repo.to_lowercase().starts_with("cachyos"),
Source::Aur => false,
}));
assert!(app.results.iter().all(|p| match &p.source {
Source::Official { repo, .. } => !repo.eq_ignore_ascii_case("endeavouros"),
Source::Aur => true,
}));
}
#[test]
fn logic_filter_unknown_official_inclusion_policy() {
let mut app = AppState {
all_results: vec![
PackageItem {
name: "x1".into(),
version: "1".into(),
description: String::new(),
source: Source::Official {
repo: "weirdrepo".into(),
arch: "x86_64".into(),
},
popularity: None,
out_of_date: None,
orphaned: false,
},
item_official("core1", "core"),
],
results_filter_show_aur: true,
results_filter_show_core: true,
results_filter_show_extra: true,
results_filter_show_multilib: false,
results_filter_show_eos: true,
results_filter_show_cachyos: true,
..Default::default()
};
apply_filters_and_sort_preserve_selection(&mut app);
assert!(app.results.iter().all(|p| match &p.source {
Source::Official { repo, .. } => repo.eq_ignore_ascii_case("core"),
Source::Aur => false,
}));
app.results_filter_show_multilib = true;
apply_filters_and_sort_preserve_selection(&mut app);
assert!(app.results.iter().any(|p| match &p.source {
Source::Official { repo, .. } => repo.eq_ignore_ascii_case("weirdrepo"),
Source::Aur => false,
}));
}
}