feat(tui): Implement fuzzy searching
This commit is contained in:
parent
38fe976261
commit
99e7d3895a
59
src/tui.rs
59
src/tui.rs
@ -7,6 +7,7 @@ use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::widgets::{Block, Borders, Cell, Paragraph, Row, Table, TableState};
|
||||
use ratatui::Frame;
|
||||
use tracing::trace;
|
||||
use tui_input::{Input, InputRequest};
|
||||
|
||||
use crate::state::{clear_selected_project_file, write_selected_project_file};
|
||||
@ -61,6 +62,7 @@ impl State {
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn run(projects: Projects) -> Result<()> {
|
||||
clear_selected_project_file()?;
|
||||
|
||||
@ -115,7 +117,6 @@ fn handle_key_event(state: &mut State, tx: &mut mpsc::Sender<Message>, event: Ke
|
||||
state.search.handle(InputRequest::DeletePrevChar);
|
||||
Message::SearchUpdate
|
||||
}
|
||||
|
||||
(_, _, KeyCode::Enter) => Message::Confirm,
|
||||
|
||||
_ => Message::Noop,
|
||||
@ -224,11 +225,13 @@ fn draw_list(state: &mut State, frame: &mut Frame, area: Rect) {
|
||||
|
||||
let search_value = state.search.value();
|
||||
|
||||
if path_str.contains(search_value) {
|
||||
Some(path_str.to_string())
|
||||
} else {
|
||||
None
|
||||
if search_value.is_empty() {
|
||||
return Some(path_str.to_string());
|
||||
}
|
||||
|
||||
let indices = fuzzy_search(search_value, path_str)?;
|
||||
trace!(?search_value, ?path_str, ?indices);
|
||||
Some(path_str.to_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -245,3 +248,49 @@ fn draw_list(state: &mut State, frame: &mut Frame, area: Rect) {
|
||||
|
||||
frame.render_stateful_widget(table, area, &mut state.project_table);
|
||||
}
|
||||
|
||||
|
||||
fn fuzzy_search(search: &str, text: &str) -> Option<Vec<usize>> {
|
||||
let mut found_indices = Vec::new();
|
||||
let mut start_idx = 0;
|
||||
|
||||
for ch in search.chars() {
|
||||
let remaining = &text[start_idx..];
|
||||
|
||||
let mut found = false;
|
||||
|
||||
for (byte_idx, txt_ch) in remaining.char_indices() {
|
||||
if ch == txt_ch {
|
||||
found_indices.push(start_idx + byte_idx);
|
||||
start_idx += byte_idx + txt_ch.len_utf8();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if search.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(found_indices)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fuzzy_test() {
|
||||
assert_eq!(fuzzy_search("st", "st"), Some(vec![0, 1]));
|
||||
assert_eq!(fuzzy_search("st", "some text"), Some(vec![0, 5]));
|
||||
assert_eq!(fuzzy_search("st", "nothing"), None);
|
||||
assert_eq!(fuzzy_search("st", ""), None);
|
||||
assert_eq!(fuzzy_search("", "nonempty"), None);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user