aboutsummaryrefslogtreecommitdiff
path: root/vendor/dialoguer/src/theme.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/dialoguer/src/theme.rs
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/dialoguer/src/theme.rs')
-rw-r--r--vendor/dialoguer/src/theme.rs976
1 files changed, 976 insertions, 0 deletions
diff --git a/vendor/dialoguer/src/theme.rs b/vendor/dialoguer/src/theme.rs
new file mode 100644
index 0000000..1fbde92
--- /dev/null
+++ b/vendor/dialoguer/src/theme.rs
@@ -0,0 +1,976 @@
+//! Customizes the rendering of the elements.
+use std::{fmt, io};
+
+use console::{measure_text_width, style, Style, StyledObject, Term};
+#[cfg(feature = "fuzzy-select")]
+use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
+
+/// Implements a theme for dialoguer.
+pub trait Theme {
+ /// Formats a prompt.
+ #[inline]
+ fn format_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ write!(f, "{}:", prompt)
+ }
+
+ /// Formats out an error.
+ #[inline]
+ fn format_error(&self, f: &mut dyn fmt::Write, err: &str) -> fmt::Result {
+ write!(f, "error: {}", err)
+ }
+
+ /// Formats a confirm prompt.
+ fn format_confirm_prompt(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ default: Option<bool>,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(f, "{} ", &prompt)?;
+ }
+ match default {
+ None => write!(f, "[y/n] ")?,
+ Some(true) => write!(f, "[Y/n] ")?,
+ Some(false) => write!(f, "[y/N] ")?,
+ }
+ Ok(())
+ }
+
+ /// Formats a confirm prompt after selection.
+ fn format_confirm_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ selection: Option<bool>,
+ ) -> fmt::Result {
+ let selection = selection.map(|b| if b { "yes" } else { "no" });
+
+ match selection {
+ Some(selection) if prompt.is_empty() => {
+ write!(f, "{}", selection)
+ }
+ Some(selection) => {
+ write!(f, "{} {}", &prompt, selection)
+ }
+ None if prompt.is_empty() => Ok(()),
+ None => {
+ write!(f, "{}", &prompt)
+ }
+ }
+ }
+
+ /// Formats an input prompt.
+ fn format_input_prompt(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ default: Option<&str>,
+ ) -> fmt::Result {
+ match default {
+ Some(default) if prompt.is_empty() => write!(f, "[{}]: ", default),
+ Some(default) => write!(f, "{} [{}]: ", prompt, default),
+ None => write!(f, "{}: ", prompt),
+ }
+ }
+
+ /// Formats an input prompt after selection.
+ #[inline]
+ fn format_input_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ sel: &str,
+ ) -> fmt::Result {
+ write!(f, "{}: {}", prompt, sel)
+ }
+
+ /// Formats a password prompt.
+ #[inline]
+ #[cfg(feature = "password")]
+ fn format_password_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ self.format_input_prompt(f, prompt, None)
+ }
+
+ /// Formats a password prompt after selection.
+ #[inline]
+ #[cfg(feature = "password")]
+ fn format_password_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ ) -> fmt::Result {
+ self.format_input_prompt_selection(f, prompt, "[hidden]")
+ }
+
+ /// Formats a select prompt.
+ #[inline]
+ fn format_select_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ self.format_prompt(f, prompt)
+ }
+
+ /// Formats a select prompt after selection.
+ #[inline]
+ fn format_select_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ sel: &str,
+ ) -> fmt::Result {
+ self.format_input_prompt_selection(f, prompt, sel)
+ }
+
+ /// Formats a multi select prompt.
+ #[inline]
+ fn format_multi_select_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ self.format_prompt(f, prompt)
+ }
+
+ /// Formats a sort prompt.
+ #[inline]
+ fn format_sort_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ self.format_prompt(f, prompt)
+ }
+
+ /// Formats a multi_select prompt after selection.
+ fn format_multi_select_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ selections: &[&str],
+ ) -> fmt::Result {
+ write!(f, "{}: ", prompt)?;
+ for (idx, sel) in selections.iter().enumerate() {
+ write!(f, "{}{}", if idx == 0 { "" } else { ", " }, sel)?;
+ }
+ Ok(())
+ }
+
+ /// Formats a sort prompt after selection.
+ #[inline]
+ fn format_sort_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ selections: &[&str],
+ ) -> fmt::Result {
+ self.format_multi_select_prompt_selection(f, prompt, selections)
+ }
+
+ /// Formats a select prompt item.
+ fn format_select_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ active: bool,
+ ) -> fmt::Result {
+ write!(f, "{} {}", if active { ">" } else { " " }, text)
+ }
+
+ /// Formats a multi select prompt item.
+ fn format_multi_select_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ checked: bool,
+ active: bool,
+ ) -> fmt::Result {
+ write!(
+ f,
+ "{} {}",
+ match (checked, active) {
+ (true, true) => "> [x]",
+ (true, false) => " [x]",
+ (false, true) => "> [ ]",
+ (false, false) => " [ ]",
+ },
+ text
+ )
+ }
+
+ /// Formats a sort prompt item.
+ fn format_sort_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ picked: bool,
+ active: bool,
+ ) -> fmt::Result {
+ write!(
+ f,
+ "{} {}",
+ match (picked, active) {
+ (true, true) => "> [x]",
+ (false, true) => "> [ ]",
+ (_, false) => " [ ]",
+ },
+ text
+ )
+ }
+
+ /// 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(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ search_term: &str,
+ cursor_pos: usize,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ 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.to_string(), cursor)
+ }
+ }
+}
+
+/// The default theme.
+pub struct SimpleTheme;
+
+impl Theme for SimpleTheme {}
+
+/// A colorful theme
+pub struct ColorfulTheme {
+ /// The style for default values
+ pub defaults_style: Style,
+ /// The style for prompt
+ pub prompt_style: Style,
+ /// Prompt prefix value and style
+ pub prompt_prefix: StyledObject<String>,
+ /// Prompt suffix value and style
+ pub prompt_suffix: StyledObject<String>,
+ /// Prompt on success prefix value and style
+ pub success_prefix: StyledObject<String>,
+ /// Prompt on success suffix value and style
+ pub success_suffix: StyledObject<String>,
+ /// Error prefix value and style
+ pub error_prefix: StyledObject<String>,
+ /// The style for error message
+ pub error_style: Style,
+ /// The style for hints
+ pub hint_style: Style,
+ /// The style for values on prompt success
+ pub values_style: Style,
+ /// The style for active items
+ pub active_item_style: Style,
+ /// The style for inactive items
+ pub inactive_item_style: Style,
+ /// Active item in select prefix value and style
+ pub active_item_prefix: StyledObject<String>,
+ /// Inctive item in select prefix value and style
+ pub inactive_item_prefix: StyledObject<String>,
+ /// Checked item in multi select prefix value and style
+ pub checked_item_prefix: StyledObject<String>,
+ /// Unchecked item in multi select prefix value and style
+ pub unchecked_item_prefix: StyledObject<String>,
+ /// Picked item in sort prefix value and style
+ pub picked_item_prefix: StyledObject<String>,
+ /// Unpicked item in sort prefix value and style
+ pub unpicked_item_prefix: StyledObject<String>,
+ /// 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,
+}
+
+impl Default for ColorfulTheme {
+ fn default() -> ColorfulTheme {
+ ColorfulTheme {
+ defaults_style: Style::new().for_stderr().cyan(),
+ prompt_style: Style::new().for_stderr().bold(),
+ prompt_prefix: style("?".to_string()).for_stderr().yellow(),
+ prompt_suffix: style("›".to_string()).for_stderr().black().bright(),
+ success_prefix: style("✔".to_string()).for_stderr().green(),
+ success_suffix: style("·".to_string()).for_stderr().black().bright(),
+ error_prefix: style("✘".to_string()).for_stderr().red(),
+ error_style: Style::new().for_stderr().red(),
+ hint_style: Style::new().for_stderr().black().bright(),
+ values_style: Style::new().for_stderr().green(),
+ active_item_style: Style::new().for_stderr().cyan(),
+ inactive_item_style: Style::new().for_stderr(),
+ active_item_prefix: style("❯".to_string()).for_stderr().green(),
+ inactive_item_prefix: style(" ".to_string()).for_stderr(),
+ checked_item_prefix: style("✔".to_string()).for_stderr().green(),
+ unchecked_item_prefix: style("✔".to_string()).for_stderr().black(),
+ picked_item_prefix: style("❯".to_string()).for_stderr().green(),
+ 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(),
+ inline_selections: true,
+ }
+ }
+}
+
+impl Theme for ColorfulTheme {
+ /// Formats a prompt.
+ fn format_prompt(&self, f: &mut dyn fmt::Write, prompt: &str) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.prompt_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+
+ write!(f, "{}", &self.prompt_suffix)
+ }
+
+ /// Formats an error
+ fn format_error(&self, f: &mut dyn fmt::Write, err: &str) -> fmt::Result {
+ write!(
+ f,
+ "{} {}",
+ &self.error_prefix,
+ self.error_style.apply_to(err)
+ )
+ }
+
+ /// Formats an input prompt.
+ fn format_input_prompt(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ default: Option<&str>,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.prompt_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+
+ match default {
+ Some(default) => write!(
+ f,
+ "{} {} ",
+ self.hint_style.apply_to(&format!("({})", default)),
+ &self.prompt_suffix
+ ),
+ None => write!(f, "{} ", &self.prompt_suffix),
+ }
+ }
+
+ /// Formats a confirm prompt.
+ fn format_confirm_prompt(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ default: Option<bool>,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.prompt_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+
+ match default {
+ None => write!(
+ f,
+ "{} {}",
+ self.hint_style.apply_to("(y/n)"),
+ &self.prompt_suffix
+ ),
+ Some(true) => write!(
+ f,
+ "{} {} {}",
+ self.hint_style.apply_to("(y/n)"),
+ &self.prompt_suffix,
+ self.defaults_style.apply_to("yes")
+ ),
+ Some(false) => write!(
+ f,
+ "{} {} {}",
+ self.hint_style.apply_to("(y/n)"),
+ &self.prompt_suffix,
+ self.defaults_style.apply_to("no")
+ ),
+ }
+ }
+
+ /// Formats a confirm prompt after selection.
+ fn format_confirm_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ selection: Option<bool>,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.success_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+ let selection = selection.map(|b| if b { "yes" } else { "no" });
+
+ match selection {
+ Some(selection) => {
+ write!(
+ f,
+ "{} {}",
+ &self.success_suffix,
+ self.values_style.apply_to(selection)
+ )
+ }
+ None => {
+ write!(f, "{}", &self.success_suffix)
+ }
+ }
+ }
+
+ /// Formats an input prompt after selection.
+ fn format_input_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ sel: &str,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.success_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+
+ write!(
+ f,
+ "{} {}",
+ &self.success_suffix,
+ self.values_style.apply_to(sel)
+ )
+ }
+
+ /// Formats a password prompt after selection.
+ #[cfg(feature = "password")]
+ fn format_password_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ ) -> fmt::Result {
+ self.format_input_prompt_selection(f, prompt, "********")
+ }
+
+ /// Formats a multi select prompt after selection.
+ fn format_multi_select_prompt_selection(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ selections: &[&str],
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &self.success_prefix,
+ self.prompt_style.apply_to(prompt)
+ )?;
+ }
+
+ write!(f, "{} ", &self.success_suffix)?;
+
+ if self.inline_selections {
+ for (idx, sel) in selections.iter().enumerate() {
+ write!(
+ f,
+ "{}{}",
+ if idx == 0 { "" } else { ", " },
+ self.values_style.apply_to(sel)
+ )?;
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Formats a select prompt item.
+ fn format_select_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ active: bool,
+ ) -> fmt::Result {
+ let details = if active {
+ (
+ &self.active_item_prefix,
+ self.active_item_style.apply_to(text),
+ )
+ } else {
+ (
+ &self.inactive_item_prefix,
+ self.inactive_item_style.apply_to(text),
+ )
+ };
+
+ write!(f, "{} {}", details.0, details.1)
+ }
+
+ /// Formats a multi select prompt item.
+ fn format_multi_select_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ checked: bool,
+ active: bool,
+ ) -> fmt::Result {
+ let details = match (checked, active) {
+ (true, true) => (
+ &self.checked_item_prefix,
+ self.active_item_style.apply_to(text),
+ ),
+ (true, false) => (
+ &self.checked_item_prefix,
+ self.inactive_item_style.apply_to(text),
+ ),
+ (false, true) => (
+ &self.unchecked_item_prefix,
+ self.active_item_style.apply_to(text),
+ ),
+ (false, false) => (
+ &self.unchecked_item_prefix,
+ self.inactive_item_style.apply_to(text),
+ ),
+ };
+
+ write!(f, "{} {}", details.0, details.1)
+ }
+
+ /// Formats a sort prompt item.
+ fn format_sort_prompt_item(
+ &self,
+ f: &mut dyn fmt::Write,
+ text: &str,
+ picked: bool,
+ active: bool,
+ ) -> fmt::Result {
+ let details = match (picked, active) {
+ (true, true) => (
+ &self.picked_item_prefix,
+ self.active_item_style.apply_to(text),
+ ),
+ (false, true) => (
+ &self.unpicked_item_prefix,
+ self.active_item_style.apply_to(text),
+ ),
+ (_, false) => (
+ &self.unpicked_item_prefix,
+ self.inactive_item_style.apply_to(text),
+ ),
+ };
+
+ 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 {
+ &self.active_item_prefix
+ } else {
+ &self.inactive_item_prefix
+ }
+ )?;
+
+ 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) {
+ if active {
+ write!(
+ f,
+ "{}",
+ self.active_item_style
+ .apply_to(self.fuzzy_match_highlight_style.apply_to(c))
+ )?;
+ } else {
+ write!(f, "{}", self.fuzzy_match_highlight_style.apply_to(c))?;
+ }
+ } else {
+ if active {
+ write!(f, "{}", self.active_item_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(
+ &self,
+ f: &mut dyn fmt::Write,
+ prompt: &str,
+ search_term: &str,
+ cursor_pos: usize,
+ ) -> fmt::Result {
+ if !prompt.is_empty() {
+ write!(
+ f,
+ "{} {} ",
+ &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.to_string(),
+ cursor
+ )
+ }
+ }
+}
+
+/// Helper struct to conveniently render a theme of a term.
+pub(crate) struct TermThemeRenderer<'a> {
+ term: &'a Term,
+ theme: &'a dyn Theme,
+ height: usize,
+ prompt_height: usize,
+ prompts_reset_height: bool,
+}
+
+impl<'a> TermThemeRenderer<'a> {
+ pub fn new(term: &'a Term, theme: &'a dyn Theme) -> TermThemeRenderer<'a> {
+ TermThemeRenderer {
+ term,
+ theme,
+ height: 0,
+ prompt_height: 0,
+ prompts_reset_height: true,
+ }
+ }
+
+ #[cfg(feature = "password")]
+ pub fn set_prompts_reset_height(&mut self, val: bool) {
+ self.prompts_reset_height = val;
+ }
+
+ #[cfg(feature = "password")]
+ pub fn term(&self) -> &Term {
+ self.term
+ }
+
+ pub fn add_line(&mut self) {
+ self.height += 1;
+ }
+
+ fn write_formatted_str<
+ F: FnOnce(&mut TermThemeRenderer, &mut dyn fmt::Write) -> fmt::Result,
+ >(
+ &mut self,
+ f: F,
+ ) -> io::Result<usize> {
+ let mut buf = String::new();
+ f(self, &mut buf).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
+ self.height += buf.chars().filter(|&x| x == '\n').count();
+ self.term.write_str(&buf)?;
+ Ok(measure_text_width(&buf))
+ }
+
+ fn write_formatted_line<
+ F: FnOnce(&mut TermThemeRenderer, &mut dyn fmt::Write) -> fmt::Result,
+ >(
+ &mut self,
+ f: F,
+ ) -> io::Result<()> {
+ let mut buf = String::new();
+ f(self, &mut buf).map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
+ self.height += buf.chars().filter(|&x| x == '\n').count() + 1;
+ self.term.write_line(&buf)
+ }
+
+ fn write_formatted_prompt<
+ F: FnOnce(&mut TermThemeRenderer, &mut dyn fmt::Write) -> fmt::Result,
+ >(
+ &mut self,
+ f: F,
+ ) -> io::Result<()> {
+ self.write_formatted_line(f)?;
+ if self.prompts_reset_height {
+ self.prompt_height = self.height;
+ self.height = 0;
+ }
+ Ok(())
+ }
+
+ fn write_paging_info(buf: &mut dyn fmt::Write, paging_info: (usize, usize)) -> fmt::Result {
+ write!(buf, " [Page {}/{}] ", paging_info.0, paging_info.1)
+ }
+
+ pub fn error(&mut self, err: &str) -> io::Result<()> {
+ self.write_formatted_line(|this, buf| this.theme.format_error(buf, err))
+ }
+
+ pub fn confirm_prompt(&mut self, prompt: &str, default: Option<bool>) -> io::Result<usize> {
+ self.write_formatted_str(|this, buf| this.theme.format_confirm_prompt(buf, prompt, default))
+ }
+
+ pub fn confirm_prompt_selection(&mut self, prompt: &str, sel: Option<bool>) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_confirm_prompt_selection(buf, prompt, sel)
+ })
+ }
+
+ #[cfg(feature = "fuzzy-select")]
+ pub fn fuzzy_select_prompt(
+ &mut self,
+ prompt: &str,
+ search_term: &str,
+ cursor_pos: usize,
+ ) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme
+ .format_fuzzy_select_prompt(buf, prompt, search_term, cursor_pos)
+ })
+ }
+
+ pub fn input_prompt(&mut self, prompt: &str, default: Option<&str>) -> io::Result<usize> {
+ self.write_formatted_str(|this, buf| this.theme.format_input_prompt(buf, prompt, default))
+ }
+
+ pub fn input_prompt_selection(&mut self, prompt: &str, sel: &str) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_input_prompt_selection(buf, prompt, sel)
+ })
+ }
+
+ #[cfg(feature = "password")]
+ pub fn password_prompt(&mut self, prompt: &str) -> io::Result<usize> {
+ self.write_formatted_str(|this, buf| {
+ write!(buf, "\r")?;
+ this.theme.format_password_prompt(buf, prompt)
+ })
+ }
+
+ #[cfg(feature = "password")]
+ pub fn password_prompt_selection(&mut self, prompt: &str) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_password_prompt_selection(buf, prompt)
+ })
+ }
+
+ pub fn select_prompt(
+ &mut self,
+ prompt: &str,
+ paging_info: Option<(usize, usize)>,
+ ) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_select_prompt(buf, prompt)?;
+
+ if let Some(paging_info) = paging_info {
+ TermThemeRenderer::write_paging_info(buf, paging_info)?;
+ }
+
+ Ok(())
+ })
+ }
+
+ pub fn select_prompt_selection(&mut self, prompt: &str, sel: &str) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_select_prompt_selection(buf, prompt, sel)
+ })
+ }
+
+ pub fn select_prompt_item(&mut self, text: &str, active: bool) -> io::Result<()> {
+ self.write_formatted_line(|this, buf| {
+ this.theme.format_select_prompt_item(buf, text, active)
+ })
+ }
+
+ #[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,
+ paging_info: Option<(usize, usize)>,
+ ) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_multi_select_prompt(buf, prompt)?;
+
+ if let Some(paging_info) = paging_info {
+ TermThemeRenderer::write_paging_info(buf, paging_info)?;
+ }
+
+ Ok(())
+ })
+ }
+
+ pub fn multi_select_prompt_selection(&mut self, prompt: &str, sel: &[&str]) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme
+ .format_multi_select_prompt_selection(buf, prompt, sel)
+ })
+ }
+
+ pub fn multi_select_prompt_item(
+ &mut self,
+ text: &str,
+ checked: bool,
+ active: bool,
+ ) -> io::Result<()> {
+ self.write_formatted_line(|this, buf| {
+ this.theme
+ .format_multi_select_prompt_item(buf, text, checked, active)
+ })
+ }
+
+ pub fn sort_prompt(
+ &mut self,
+ prompt: &str,
+ paging_info: Option<(usize, usize)>,
+ ) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_sort_prompt(buf, prompt)?;
+
+ if let Some(paging_info) = paging_info {
+ TermThemeRenderer::write_paging_info(buf, paging_info)?;
+ }
+
+ Ok(())
+ })
+ }
+
+ pub fn sort_prompt_selection(&mut self, prompt: &str, sel: &[&str]) -> io::Result<()> {
+ self.write_formatted_prompt(|this, buf| {
+ this.theme.format_sort_prompt_selection(buf, prompt, sel)
+ })
+ }
+
+ pub fn sort_prompt_item(&mut self, text: &str, picked: bool, active: bool) -> io::Result<()> {
+ self.write_formatted_line(|this, buf| {
+ this.theme
+ .format_sort_prompt_item(buf, text, picked, active)
+ })
+ }
+
+ pub fn clear(&mut self) -> io::Result<()> {
+ self.term
+ .clear_last_lines(self.height + self.prompt_height)?;
+ self.height = 0;
+ self.prompt_height = 0;
+ Ok(())
+ }
+
+ pub fn clear_preserve_prompt(&mut self, size_vec: &[usize]) -> io::Result<()> {
+ let mut new_height = self.height;
+ let prefix_width = 2;
+ //Check each item size, increment on finding an overflow
+ for size in size_vec {
+ if *size > self.term.size().1 as usize {
+ new_height += (((*size as f64 + prefix_width as f64) / self.term.size().1 as f64)
+ .ceil()) as usize
+ - 1;
+ }
+ }
+
+ self.term.clear_last_lines(new_height)?;
+ self.height = 0;
+ Ok(())
+ }
+}