mirror of
https://github.com/nushell/nushell.git
synced 2025-02-05 05:00:11 +01:00
Separate highlighting from fuzzy search
This commit is contained in:
parent
0a0be19bed
commit
0c9a62aeec
@ -14,8 +14,8 @@ pub fn interactive_fuzzy_search(lines: &Vec<&str>, max_results: usize) -> Select
|
|||||||
enum State {
|
enum State {
|
||||||
Selecting,
|
Selecting,
|
||||||
Quit,
|
Quit,
|
||||||
Selected(usize),
|
Selected(String),
|
||||||
Edit(usize),
|
Edit(String),
|
||||||
}
|
}
|
||||||
let mut state = State::Selecting;
|
let mut state = State::Selecting;
|
||||||
if let Ok(_raw) = RawScreen::into_raw_mode() {
|
if let Ok(_raw) = RawScreen::into_raw_mode() {
|
||||||
@ -29,11 +29,9 @@ pub fn interactive_fuzzy_search(lines: &Vec<&str>, max_results: usize) -> Select
|
|||||||
let mut sync_stdin = input.read_sync();
|
let mut sync_stdin = input.read_sync();
|
||||||
|
|
||||||
while state == State::Selecting {
|
while state == State::Selecting {
|
||||||
let search_result = fuzzy_search(&searchinput, &lines, max_results);
|
let mut search_result = fuzzy_search(&searchinput, &lines, max_results);
|
||||||
let selected_lines: Vec<&str> = search_result
|
let selected_lines: Vec<String> =
|
||||||
.iter()
|
search_result.iter().map(|item| highlight(&item)).collect();
|
||||||
.map(|item| &item.highlighted_text as &str)
|
|
||||||
.collect();
|
|
||||||
paint_selection_list(&selected_lines, selected);
|
paint_selection_list(&selected_lines, selected);
|
||||||
if let Some(ev) = sync_stdin.next() {
|
if let Some(ev) = sync_stdin.next() {
|
||||||
match ev {
|
match ev {
|
||||||
@ -52,10 +50,10 @@ pub fn interactive_fuzzy_search(lines: &Vec<&str>, max_results: usize) -> Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyEvent::Char('\n') => {
|
KeyEvent::Char('\n') => {
|
||||||
state = State::Selected(search_result[selected].text_idx);
|
state = State::Selected(search_result.remove(selected).text);
|
||||||
}
|
}
|
||||||
KeyEvent::Char('\t') | KeyEvent::Right => {
|
KeyEvent::Char('\t') | KeyEvent::Right => {
|
||||||
state = State::Edit(search_result[selected].text_idx);
|
state = State::Edit(search_result.remove(selected).text);
|
||||||
}
|
}
|
||||||
KeyEvent::Char(ch) => {
|
KeyEvent::Char(ch) => {
|
||||||
searchinput.push(ch);
|
searchinput.push(ch);
|
||||||
@ -66,7 +64,7 @@ pub fn interactive_fuzzy_search(lines: &Vec<&str>, max_results: usize) -> Select
|
|||||||
selected = 0;
|
selected = 0;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// println!("{}", format!("OTHER InputEvent: {:?}\n\n", k));
|
// println!("OTHER InputEvent: {:?}", k);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -84,26 +82,25 @@ pub fn interactive_fuzzy_search(lines: &Vec<&str>, max_results: usize) -> Select
|
|||||||
terminal.clear(ClearType::FromCursorDown).unwrap();
|
terminal.clear(ClearType::FromCursorDown).unwrap();
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
State::Selected(idx) => SelectionResult::Selected(lines[idx].to_string()),
|
State::Selected(line) => SelectionResult::Selected(line),
|
||||||
State::Edit(idx) => SelectionResult::Edit(lines[idx].to_string()),
|
State::Edit(line) => SelectionResult::Edit(line),
|
||||||
_ => SelectionResult::NoSelection,
|
_ => SelectionResult::NoSelection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Match {
|
pub struct Match {
|
||||||
highlighted_text: String,
|
text: String,
|
||||||
text_idx: usize,
|
char_matches: Vec<(usize, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fuzzy_search(searchstr: &str, lines: &Vec<&str>, max_results: usize) -> Vec<Match> {
|
pub fn fuzzy_search(searchstr: &str, lines: &Vec<&str>, max_results: usize) -> Vec<Match> {
|
||||||
if searchstr.is_empty() {
|
if searchstr.is_empty() {
|
||||||
return lines
|
return lines
|
||||||
.iter()
|
.iter()
|
||||||
.take(max_results)
|
.take(max_results)
|
||||||
.enumerate()
|
.map(|line| Match {
|
||||||
.map(|(i, line)| Match {
|
text: line.to_string(),
|
||||||
highlighted_text: line.to_string(),
|
char_matches: Vec::new(),
|
||||||
text_idx: i,
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
@ -117,41 +114,43 @@ fn fuzzy_search(searchstr: &str, lines: &Vec<&str>, max_results: usize) -> Vec<M
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
matches.sort_by(|a, b| b.1.score().cmp(&a.1.score()));
|
matches.sort_by(|a, b| b.1.score().cmp(&a.1.score()));
|
||||||
|
|
||||||
let highlight = Colour::Cyan;
|
|
||||||
let results: Vec<Match> = matches
|
let results: Vec<Match> = matches
|
||||||
.iter()
|
.iter()
|
||||||
.take(max_results)
|
.take(max_results)
|
||||||
.map(|(i, m)| {
|
.map(|(i, m)| Match {
|
||||||
let r = &lines[*i];
|
text: lines[*i].to_string(),
|
||||||
let mut outstr = String::with_capacity(r.len());
|
char_matches: m.continuous_matches(),
|
||||||
let mut idx = 0;
|
|
||||||
for (match_idx, len) in m.continuous_matches() {
|
|
||||||
outstr.push_str(&r[idx..match_idx]);
|
|
||||||
idx = match_idx + len;
|
|
||||||
outstr.push_str(&format!("{}", highlight.paint(&r[match_idx..idx])));
|
|
||||||
}
|
|
||||||
if idx < r.len() {
|
|
||||||
outstr.push_str(&r[idx..r.len()]);
|
|
||||||
}
|
|
||||||
Match {
|
|
||||||
highlighted_text: outstr,
|
|
||||||
text_idx: *i,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_selection_list(lines: &Vec<&str>, selected: usize) {
|
fn highlight(textmatch: &Match) -> String {
|
||||||
|
let hlcol = Colour::Cyan;
|
||||||
|
let text = &textmatch.text;
|
||||||
|
let mut outstr = String::with_capacity(text.len());
|
||||||
|
let mut idx = 0;
|
||||||
|
for (match_idx, len) in &textmatch.char_matches {
|
||||||
|
outstr.push_str(&text[idx..*match_idx]);
|
||||||
|
idx = match_idx + len;
|
||||||
|
outstr.push_str(&format!("{}", hlcol.paint(&text[*match_idx..idx])));
|
||||||
|
}
|
||||||
|
if idx < text.len() {
|
||||||
|
outstr.push_str(&text[idx..text.len()]);
|
||||||
|
}
|
||||||
|
outstr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_selection_list(lines: &Vec<String>, selected: usize) {
|
||||||
let dimmed = Colour::White.dimmed();
|
let dimmed = Colour::White.dimmed();
|
||||||
let cursor = cursor();
|
let cursor = cursor();
|
||||||
let (_x, y) = cursor.pos();
|
let (_x, y) = cursor.pos();
|
||||||
for (i, line) in lines.iter().enumerate() {
|
for (i, line) in lines.iter().enumerate() {
|
||||||
let _ = cursor.goto(0, y + (i as u16));
|
let _ = cursor.goto(0, y + (i as u16));
|
||||||
if selected == i {
|
if selected == i {
|
||||||
println!("{}", *line);
|
println!("{}", line);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", dimmed.paint(*line));
|
println!("{}", dimmed.paint(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _ = cursor.goto(0, y + (lines.len() as u16));
|
let _ = cursor.goto(0, y + (lines.len() as u16));
|
||||||
@ -164,3 +163,9 @@ fn paint_selection_list(lines: &Vec<&str>, selected: usize) {
|
|||||||
// Clear additional lines from previous selection
|
// Clear additional lines from previous selection
|
||||||
terminal().clear(ClearType::FromCursorDown).unwrap();
|
terminal().clear(ClearType::FromCursorDown).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fuzzy_match() {
|
||||||
|
let matches = fuzzy_search("cb", &vec!["abc", "cargo build"], 1);
|
||||||
|
assert_eq!(matches[0].text, "cargo build");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user