use crate::history::{CommandHistory, HistoryMatch};
pub struct HistoryManager {
pub search_query: String,
pub matches: Vec<HistoryMatch>,
pub selected_index: usize,
}
impl HistoryManager {
#[must_use]
pub fn new() -> Self {
Self {
search_query: String::new(),
matches: Vec::new(),
selected_index: 0,
}
}
pub fn update_matches(&mut self, history: &CommandHistory) {
if self.search_query.is_empty() {
self.matches = history
.get_session_entries()
.iter()
.map(|entry| HistoryMatch {
entry: entry.clone(),
score: 100,
indices: Vec::new(),
})
.collect();
} else {
self.matches = history.search(&self.search_query);
}
if self.selected_index >= self.matches.len() && !self.matches.is_empty() {
self.selected_index = self.matches.len() - 1;
}
}
pub fn next_match(&mut self) {
if !self.matches.is_empty() {
self.selected_index = (self.selected_index + 1) % self.matches.len();
}
}
pub fn previous_match(&mut self) {
if !self.matches.is_empty() {
if self.selected_index == 0 {
self.selected_index = self.matches.len() - 1;
} else {
self.selected_index -= 1;
}
}
}
#[must_use]
pub fn get_selected(&self) -> Option<&HistoryMatch> {
if self.selected_index < self.matches.len() {
self.matches.get(self.selected_index)
} else {
None
}
}
pub fn clear(&mut self) {
self.search_query.clear();
self.matches.clear();
self.selected_index = 0;
}
pub fn set_search(&mut self, query: String, history: &CommandHistory) {
self.search_query = query;
self.update_matches(history);
}
#[must_use]
pub fn get_visible_range(&self, height: usize) -> (usize, usize) {
if self.matches.is_empty() {
return (0, 0);
}
let total = self.matches.len();
let half_height = height / 2;
let start = if self.selected_index <= half_height {
0
} else if self.selected_index + half_height >= total {
total.saturating_sub(height)
} else {
self.selected_index - half_height
};
let end = (start + height).min(total);
(start, end)
}
}
impl Default for HistoryManager {
fn default() -> Self {
Self::new()
}
}