From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/dialoguer/src/theme.rs | 976 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 976 insertions(+) create mode 100644 vendor/dialoguer/src/theme.rs (limited to 'vendor/dialoguer/src/theme.rs') 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, + ) -> 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, + ) -> 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, + /// Prompt suffix value and style + pub prompt_suffix: StyledObject, + /// Prompt on success prefix value and style + pub success_prefix: StyledObject, + /// Prompt on success suffix value and style + pub success_suffix: StyledObject, + /// Error prefix value and style + pub error_prefix: StyledObject, + /// 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, + /// Inctive item in select prefix value and style + pub inactive_item_prefix: StyledObject, + /// Checked item in multi select prefix value and style + pub checked_item_prefix: StyledObject, + /// Unchecked item in multi select prefix value and style + pub unchecked_item_prefix: StyledObject, + /// Picked item in sort prefix value and style + pub picked_item_prefix: StyledObject, + /// Unpicked item in sort prefix value and style + pub unpicked_item_prefix: StyledObject, + /// 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, + ) -> 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, + ) -> 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 { + 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) -> io::Result { + 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) -> 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 { + 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 { + 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(()) + } +} -- cgit v1.2.3