Skip to content

Commit

Permalink
Fix panic in fuzzy-select when using non-ASCII characters
Browse files Browse the repository at this point in the history
  • Loading branch information
stormshield-kg committed Sep 11, 2023
1 parent 9baa851 commit dc230eb
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 39 deletions.
29 changes: 18 additions & 11 deletions src/prompts/fuzzy_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl FuzzySelect<'_> {

fn _interact_on(self, term: &Term, allow_quit: bool) -> Result<Option<usize>> {
// Place cursor at the end of the search term
let mut position = self.initial_text.len();
let mut cursor = self.initial_text.chars().count();
let mut search_term = self.initial_text.to_owned();

let mut render = TermThemeRenderer::new(term, self.theme);
Expand Down Expand Up @@ -224,8 +224,15 @@ impl FuzzySelect<'_> {
let mut vim_mode = false;

loop {
let mut byte_indices = search_term
.char_indices()
.map(|(index, _)| index)
.collect::<Vec<_>>();

byte_indices.push(search_term.len());

render.clear()?;
render.fuzzy_select_prompt(self.prompt.as_str(), &search_term, position)?;
render.fuzzy_select_prompt(self.prompt.as_str(), &search_term, byte_indices[cursor])?;

// Maps all items to a tuple of item and its match score.
let mut filtered_list = self
Expand Down Expand Up @@ -304,14 +311,14 @@ impl FuzzySelect<'_> {
}
term.flush()?;
}
(Key::ArrowLeft, _, _) | (Key::Char('h'), _, true) if position > 0 => {
position -= 1;
(Key::ArrowLeft, _, _) | (Key::Char('h'), _, true) if cursor > 0 => {
cursor -= 1;
term.flush()?;
}
(Key::ArrowRight, _, _) | (Key::Char('l'), _, true)
if position < search_term.len() =>
if cursor < byte_indices.len() - 1 =>
{
position += 1;
cursor += 1;
term.flush()?;
}
(Key::Enter, Some(sel), _) if !filtered_list.is_empty() => {
Expand All @@ -331,14 +338,14 @@ impl FuzzySelect<'_> {
term.show_cursor()?;
return Ok(sel_string_pos_in_items);
}
(Key::Backspace, _, _) if position > 0 => {
position -= 1;
search_term.remove(position);
(Key::Backspace, _, _) if cursor > 0 => {
cursor -= 1;
search_term.remove(byte_indices[cursor]);
term.flush()?;
}
(Key::Char(chr), _, _) if !chr.is_ascii_control() => {
search_term.insert(position, chr);
position += 1;
search_term.insert(byte_indices[cursor], chr);
cursor += 1;
term.flush()?;
sel = Some(0);
starting_row = 0;
Expand Down
27 changes: 10 additions & 17 deletions src/theme/colorful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,31 +408,24 @@ impl Theme for ColorfulTheme {
f: &mut dyn fmt::Write,
prompt: &str,
search_term: &str,
cursor_pos: usize,
bytes_pos: usize,
) -> fmt::Result {
if !prompt.is_empty() {
write!(
f,
"{} {} ",
&self.prompt_prefix,
self.prompt_prefix,
self.prompt_style.apply_to(prompt)
)?;
}

if cursor_pos < search_term.len() {
let st_head = search_term[0..cursor_pos].to_string();
let st_tail = search_term[cursor_pos + 1..search_term.len()].to_string();
let st_cursor = self
.fuzzy_cursor_style
.apply_to(search_term.to_string().chars().nth(cursor_pos).unwrap());
write!(
f,
"{} {}{}{}",
&self.prompt_suffix, st_head, st_cursor, st_tail
)
} else {
let cursor = self.fuzzy_cursor_style.apply_to(" ");
write!(f, "{} {}{}", &self.prompt_suffix, search_term, cursor)
}
let (st_head, remaining) = search_term.split_at(bytes_pos);
let mut chars = remaining.chars();
let chr = chars.next().unwrap_or(' ');
let st_cursor = self.fuzzy_cursor_style.apply_to(chr);
let st_tail = chars.as_str();

let prompt_suffix = &self.prompt_suffix;
write!(f, "{prompt_suffix} {st_head}{st_cursor}{st_tail}",)
}
}
15 changes: 4 additions & 11 deletions src/theme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,20 +253,13 @@ pub trait Theme {
f: &mut dyn fmt::Write,
prompt: &str,
search_term: &str,
cursor_pos: usize,
bytes_pos: usize,
) -> fmt::Result {
if !prompt.is_empty() {
write!(f, "{} ", prompt)?;
write!(f, "{prompt} ")?;
}

if cursor_pos < search_term.len() {
let st_head = search_term[0..cursor_pos].to_string();
let st_tail = search_term[cursor_pos..search_term.len()].to_string();
let st_cursor = "|".to_string();
write!(f, "{}{}{}", st_head, st_cursor, st_tail)
} else {
let cursor = "|".to_string();
write!(f, "{}{}", search_term, cursor)
}
let (st_head, st_tail) = search_term.split_at(bytes_pos);
write!(f, "{st_head}|{st_tail}")
}
}

0 comments on commit dc230eb

Please sign in to comment.