From e7fa91786aba572963e645086febe050b30a73a3 Mon Sep 17 00:00:00 2001 From: Thomas Simmer Date: Fri, 22 Mar 2024 13:10:09 +0100 Subject: [PATCH] Add header and footer on select, fuzzy_select, multi_select and sort --- examples/select.rs | 8 +++++++- src/prompts/fuzzy_select.rs | 5 +++++ src/prompts/multi_select.rs | 4 ++++ src/prompts/select.rs | 7 +++++-- src/prompts/sort.rs | 4 ++++ src/theme/colorful.rs | 16 ++++++++++++++++ src/theme/mod.rs | 10 ++++++++++ src/theme/render.rs | 8 ++++++++ 8 files changed, 59 insertions(+), 3 deletions(-) diff --git a/examples/select.rs b/examples/select.rs index d282c20b..882a5034 100644 --- a/examples/select.rs +++ b/examples/select.rs @@ -1,3 +1,4 @@ +use console::style; use dialoguer::{theme::ColorfulTheme, Select}; fn main() { @@ -30,7 +31,12 @@ fn main() { println!("You didn't select anything!"); } - let selection = Select::with_theme(&ColorfulTheme::default()) + let theme = ColorfulTheme { + header: style("-----------------------".to_string()).for_stderr(), + footer: style("-----------------------".to_string()).for_stderr(), + ..ColorfulTheme::default() + }; + let selection = Select::with_theme(&theme) .with_prompt("Pick your flavor, hint it might be on the second page") .default(0) .max_length(2) diff --git a/src/prompts/fuzzy_select.rs b/src/prompts/fuzzy_select.rs index 9f067986..3712fff4 100644 --- a/src/prompts/fuzzy_select.rs +++ b/src/prompts/fuzzy_select.rs @@ -238,6 +238,8 @@ impl FuzzySelect<'_> { render.clear()?; render.fuzzy_select_prompt(self.prompt.as_str(), &search_term, byte_indices[cursor])?; + render.header()?; + // Maps all items to a tuple of item and its match score. let mut filtered_list = self .items @@ -263,6 +265,9 @@ impl FuzzySelect<'_> { &search_term, )?; } + + render.footer()?; + term.flush()?; match (term.read_key()?, sel, vim_mode) { diff --git a/src/prompts/multi_select.rs b/src/prompts/multi_select.rs index 42b301d2..a6a6c823 100644 --- a/src/prompts/multi_select.rs +++ b/src/prompts/multi_select.rs @@ -238,6 +238,8 @@ impl MultiSelect<'_> { .render_prompt(|paging_info| render.multi_select_prompt(prompt, paging_info))?; } + render.header()?; + for (idx, item) in self .items .iter() @@ -248,6 +250,8 @@ impl MultiSelect<'_> { render.multi_select_prompt_item(item, checked[idx], sel == idx)?; } + render.footer()?; + term.flush()?; match term.read_key()? { diff --git a/src/prompts/select.rs b/src/prompts/select.rs index 872975db..2d1ffcf9 100644 --- a/src/prompts/select.rs +++ b/src/prompts/select.rs @@ -1,6 +1,5 @@ -use std::{io, ops::Rem}; - use console::{Key, Term}; +use std::{io, ops::Rem}; use crate::{ theme::{render::TermThemeRenderer, SimpleTheme, Theme}, @@ -226,6 +225,8 @@ impl Select<'_> { paging.render_prompt(|paging_info| render.select_prompt(prompt, paging_info))?; } + render.header()?; + for (idx, item) in self .items .iter() @@ -236,6 +237,8 @@ impl Select<'_> { render.select_prompt_item(item, sel == idx)?; } + render.footer()?; + term.flush()?; match term.read_key()? { diff --git a/src/prompts/sort.rs b/src/prompts/sort.rs index 4b1b0c88..63636124 100644 --- a/src/prompts/sort.rs +++ b/src/prompts/sort.rs @@ -205,6 +205,8 @@ impl Sort<'_> { paging.render_prompt(|paging_info| render.sort_prompt(prompt, paging_info))?; } + render.header()?; + for (idx, item) in order .iter() .enumerate() @@ -214,6 +216,8 @@ impl Sort<'_> { render.sort_prompt_item(&self.items[*item], checked, sel == idx)?; } + render.footer()?; + term.flush()?; match term.read_key()? { diff --git a/src/theme/colorful.rs b/src/theme/colorful.rs index 97569509..1d8c44fc 100644 --- a/src/theme/colorful.rs +++ b/src/theme/colorful.rs @@ -50,6 +50,10 @@ pub struct ColorfulTheme { // Formats the highlighting if matched characters #[cfg(feature = "fuzzy-select")] pub fuzzy_match_highlight_style: Style, + // Header for multiple items components + pub header: StyledObject, + // Footer for multiple items components + pub footer: StyledObject, } impl Default for ColorfulTheme { @@ -77,6 +81,8 @@ impl Default for ColorfulTheme { fuzzy_cursor_style: Style::new().for_stderr().black().on_white(), #[cfg(feature = "fuzzy-select")] fuzzy_match_highlight_style: Style::new().for_stderr().bold(), + header: style("".to_string()).for_stderr(), + footer: style("".to_string()).for_stderr(), } } } @@ -423,4 +429,14 @@ impl Theme for ColorfulTheme { let prompt_suffix = &self.prompt_suffix; write!(f, "{prompt_suffix} {st_head}{st_cursor}{st_tail}",) } + + /// Format header. + fn format_header(&self, f: &mut dyn fmt::Write) -> fmt::Result { + write!(f, "{}\n", &self.header) + } + + /// Format footer. + fn format_footer(&self, f: &mut dyn fmt::Write) -> fmt::Result { + write!(f, "{}", &self.footer) + } } diff --git a/src/theme/mod.rs b/src/theme/mod.rs index d22001cf..5eec824b 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -262,4 +262,14 @@ pub trait Theme { let (st_head, st_tail) = search_term.split_at(bytes_pos); write!(f, "{st_head}|{st_tail}") } + + /// Format header. + fn format_header(&self, _f: &mut dyn fmt::Write) -> fmt::Result { + Ok(()) + } + + /// Format footer. + fn format_footer(&self, _f: &mut dyn fmt::Write) -> fmt::Result { + Ok(()) + } } diff --git a/src/theme/render.rs b/src/theme/render.rs index e6f3addf..05b7f07d 100644 --- a/src/theme/render.rs +++ b/src/theme/render.rs @@ -259,4 +259,12 @@ impl<'a> TermThemeRenderer<'a> { self.height = 0; Ok(()) } + + pub fn header(&mut self) -> Result { + self.write_formatted_str(|this, buf| this.theme.format_header(buf)) + } + + pub fn footer(&mut self) -> Result { + self.write_formatted_str(|this, buf| this.theme.format_footer(buf)) + } }