use super::{App, View};
fn fields_match_normalized_query(query: &str, fields: &[&str]) -> bool {
fields
.iter()
.any(|field| field.to_ascii_lowercase().contains(query))
}
impl App {
pub fn list_total_len(&self) -> usize {
match self.view {
View::RfcList => self.index.rfcs.len(),
View::AdrList => self.index.adrs.len(),
View::WorkList => self.index.work_items.len(),
_ => 0,
}
}
pub(super) fn invalidate_indices(&mut self) {
self.indices_dirty = true;
}
fn recompute_indices(&mut self) {
if !self.indices_dirty {
return;
}
let query = self.filter_query.trim().to_ascii_lowercase();
let has_query = !query.is_empty();
self.cached_indices = match self.view {
View::RfcList => self
.index
.rfcs
.iter()
.enumerate()
.filter_map(|(idx, rfc)| {
if !has_query {
return Some(idx);
}
if fields_match_normalized_query(
&query,
&[
rfc.rfc.rfc_id.as_str(),
rfc.rfc.title.as_str(),
rfc.rfc.status.as_ref(),
rfc.rfc.phase.as_ref(),
],
) {
Some(idx)
} else {
None
}
})
.collect(),
View::AdrList => self
.index
.adrs
.iter()
.enumerate()
.filter_map(|(idx, adr)| {
if !has_query {
return Some(idx);
}
let meta = adr.meta();
if fields_match_normalized_query(
&query,
&[meta.id.as_str(), meta.title.as_str(), meta.status.as_ref()],
) {
Some(idx)
} else {
None
}
})
.collect(),
View::WorkList => self
.index
.work_items
.iter()
.enumerate()
.filter_map(|(idx, item)| {
if !has_query {
return Some(idx);
}
let meta = item.meta();
if fields_match_normalized_query(
&query,
&[meta.id.as_str(), meta.title.as_str(), meta.status.as_ref()],
) {
Some(idx)
} else {
None
}
})
.collect(),
_ => Vec::new(),
};
self.indices_dirty = false;
}
pub fn list_indices(&mut self) -> Vec<usize> {
self.recompute_indices();
self.cached_indices.clone()
}
pub fn list_len(&mut self) -> usize {
self.recompute_indices();
self.cached_indices.len()
}
pub fn filter_active(&self) -> bool {
!self.filter_query.trim().is_empty()
}
pub fn enter_filter_mode(&mut self) {
self.filter_mode = true;
}
pub fn exit_filter_mode(&mut self) {
self.filter_mode = false;
}
pub fn clear_filter(&mut self) {
self.filter_query.clear();
self.invalidate_indices();
self.ensure_selection_in_bounds();
}
pub fn push_filter_char(&mut self, ch: char) {
self.filter_query.push(ch);
self.invalidate_indices();
self.ensure_selection_in_bounds();
}
pub fn pop_filter_char(&mut self) {
self.filter_query.pop();
self.invalidate_indices();
self.ensure_selection_in_bounds();
}
pub fn ensure_selection_in_bounds(&mut self) {
let len = self.list_len();
if len == 0 {
self.selected = 0;
self.table_state.select(None);
return;
}
if self.selected >= len {
self.selected = len - 1;
}
self.table_state.select(Some(self.selected));
}
}
#[cfg(test)]
mod tests {
use super::fields_match_normalized_query;
#[test]
fn fields_match_normalized_query_checks_mixed_case_fields() {
assert!(fields_match_normalized_query(
"norm",
&["RFC-0001", "Title", "Normative", "Spec"],
));
assert!(fields_match_normalized_query(
"rfc-0001",
&["RFC-0001", "Title", "draft"],
));
assert!(!fields_match_normalized_query(
"missing",
&["RFC-0001", "Title", "draft"],
));
}
}