Skip to content

Commit

Permalink
Merge pull request #179 from deg0nz/highlight-fuzzy-indices
Browse files Browse the repository at this point in the history
Feature: Add Fuzzy Select match highlighting
  • Loading branch information
pksunkara committed Mar 7, 2022
2 parents 2d47e30 + f4c434a commit 4f8ffda
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/prompts/fuzzy_select.rs
Expand Up @@ -39,6 +39,7 @@ pub struct FuzzySelect<'a> {
prompt: String,
report: bool,
clear: bool,
highlight_matches: bool,
theme: &'a dyn Theme,
}

Expand Down Expand Up @@ -101,6 +102,14 @@ impl FuzzySelect<'_> {
self
}

/// Indicates whether to highlight matched indices
///
/// The default is to highlight the indices
pub fn highlight_matches(&mut self, val: bool) -> &mut Self {
self.highlight_matches = val;
self
}

/// Enables user interaction and returns the result.
///
/// The user can select the items using 'Enter' and the index of selected item will be returned.
Expand Down Expand Up @@ -180,7 +189,13 @@ impl FuzzySelect<'_> {
.skip(starting_row)
.take(visible_term_rows)
{
render.select_prompt_item(item, idx == sel)?;
render.fuzzy_select_prompt_item(
item,
idx == sel,
self.highlight_matches,
&matcher,
&search_term,
)?;
term.flush()?;
}

Expand Down Expand Up @@ -276,6 +291,7 @@ impl<'a> FuzzySelect<'a> {
prompt: "".into(),
report: true,
clear: true,
highlight_matches: true,
theme,
}
}
Expand Down
88 changes: 88 additions & 0 deletions src/theme.rs
Expand Up @@ -2,6 +2,8 @@
use std::{fmt, io};

use console::{style, Style, StyledObject, Term};
#[cfg(feature = "fuzzy-select")]
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};

/// Implements a theme for dialoguer.
pub trait Theme {
Expand Down Expand Up @@ -206,6 +208,36 @@ pub trait Theme {
)
}

/// Formats a fuzzy select prompt item.
#[cfg(feature = "fuzzy-select")]
fn format_fuzzy_select_prompt_item(
&self,
f: &mut dyn fmt::Write,
text: &str,
active: bool,
highlight_matches: bool,
matcher: &SkimMatcherV2,
search_term: &str,
) -> fmt::Result {
write!(f, "{} ", if active { ">" } else { " " })?;

if highlight_matches {
if let Some((_score, indices)) = matcher.fuzzy_indices(text, &search_term) {
for (idx, c) in text.chars().into_iter().enumerate() {
if indices.contains(&idx) {
write!(f, "{}", style(c).for_stderr().bold())?;
} else {
write!(f, "{}", c)?;
}
}

return Ok(());
}
}

write!(f, "{}", text)
}

/// Formats a fuzzy select prompt.
#[cfg(feature = "fuzzy-select")]
fn format_fuzzy_select_prompt(
Expand Down Expand Up @@ -277,6 +309,9 @@ pub struct ColorfulTheme {
/// Formats the cursor for a fuzzy select prompt
#[cfg(feature = "fuzzy-select")]
pub fuzzy_cursor_style: Style,
// Formats the highlighting if matched characters
#[cfg(feature = "fuzzy-select")]
pub fuzzy_match_highlight_style: Style,
/// Show the selections from certain prompts inline
pub inline_selections: bool,
}
Expand Down Expand Up @@ -304,6 +339,8 @@ impl Default for ColorfulTheme {
unpicked_item_prefix: style(" ".to_string()).for_stderr(),
#[cfg(feature = "fuzzy-select")]
fuzzy_cursor_style: Style::new().for_stderr().black().on_white(),
#[cfg(feature = "fuzzy-select")]
fuzzy_match_highlight_style: Style::new().for_stderr().bold().yellow(),
inline_selections: true,
}
}
Expand Down Expand Up @@ -577,6 +614,36 @@ impl Theme for ColorfulTheme {
write!(f, "{} {}", details.0, details.1)
}

/// Formats a fuzzy select prompt item.
#[cfg(feature = "fuzzy-select")]
fn format_fuzzy_select_prompt_item(
&self,
f: &mut dyn fmt::Write,
text: &str,
active: bool,
highlight_matches: bool,
matcher: &SkimMatcherV2,
search_term: &str,
) -> fmt::Result {
write!(f, "{} ", if active { ">" } else { " " })?;

if highlight_matches {
if let Some((_score, indices)) = matcher.fuzzy_indices(text, &search_term) {
for (idx, c) in text.chars().into_iter().enumerate() {
if indices.contains(&idx) {
write!(f, "{}", self.fuzzy_match_highlight_style.apply_to(c))?;
} else {
write!(f, "{}", c)?;
}
}

return Ok(());
}
}

write!(f, "{}", text)
}

/// Formats a fuzzy-selectprompt after selection.
#[cfg(feature = "fuzzy-select")]
fn format_fuzzy_select_prompt(
Expand Down Expand Up @@ -775,6 +842,27 @@ impl<'a> TermThemeRenderer<'a> {
})
}

#[cfg(feature = "fuzzy-select")]
pub fn fuzzy_select_prompt_item(
&mut self,
text: &str,
active: bool,
highlight: bool,
matcher: &SkimMatcherV2,
search_term: &str,
) -> io::Result<()> {
self.write_formatted_line(|this, buf| {
this.theme.format_fuzzy_select_prompt_item(
buf,
text,
active,
highlight,
matcher,
search_term,
)
})
}

pub fn multi_select_prompt(
&mut self,
prompt: &str,
Expand Down

0 comments on commit 4f8ffda

Please sign in to comment.