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::style::{Color, Style};
|
||||||
use ratatui::widgets::{Block, Borders, Cell, Paragraph, Row, Table, TableState};
|
use ratatui::widgets::{Block, Borders, Cell, Paragraph, Row, Table, TableState};
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
|
use tracing::trace;
|
||||||
use tui_input::{Input, InputRequest};
|
use tui_input::{Input, InputRequest};
|
||||||
|
|
||||||
use crate::state::{clear_selected_project_file, write_selected_project_file};
|
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<()> {
|
pub fn run(projects: Projects) -> Result<()> {
|
||||||
clear_selected_project_file()?;
|
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);
|
state.search.handle(InputRequest::DeletePrevChar);
|
||||||
Message::SearchUpdate
|
Message::SearchUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, _, KeyCode::Enter) => Message::Confirm,
|
(_, _, KeyCode::Enter) => Message::Confirm,
|
||||||
|
|
||||||
_ => Message::Noop,
|
_ => Message::Noop,
|
||||||
@ -224,11 +225,13 @@ fn draw_list(state: &mut State, frame: &mut Frame, area: Rect) {
|
|||||||
|
|
||||||
let search_value = state.search.value();
|
let search_value = state.search.value();
|
||||||
|
|
||||||
if path_str.contains(search_value) {
|
if search_value.is_empty() {
|
||||||
Some(path_str.to_string())
|
return Some(path_str.to_string());
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let indices = fuzzy_search(search_value, path_str)?;
|
||||||
|
trace!(?search_value, ?path_str, ?indices);
|
||||||
|
Some(path_str.to_string())
|
||||||
})
|
})
|
||||||
.collect();
|
.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);
|
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