From 645f3687622240de844ed281b1d56dc8d4e13922 Mon Sep 17 00:00:00 2001 From: NovaliX Date: Sun, 14 Aug 2022 00:06:01 +0200 Subject: [PATCH 01/31] Implemented OrderSelect --- src/question/mod.rs | 40 +++++ src/question/order_select/builder.rs | 222 ++++++++++++++++++++++++ src/question/order_select/mod.rs | 242 +++++++++++++++++++++++++++ 3 files changed, 504 insertions(+) create mode 100644 src/question/order_select/builder.rs create mode 100644 src/question/order_select/mod.rs diff --git a/src/question/mod.rs b/src/question/mod.rs index 2f84a05..a5a4697 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -9,6 +9,7 @@ mod handler; mod impl_macros; mod input; mod multi_select; +mod order_select; mod number; #[macro_use] mod options; @@ -24,6 +25,7 @@ pub use editor::EditorBuilder; pub use expand::ExpandBuilder; pub use input::InputBuilder; pub use multi_select::MultiSelectBuilder; +pub use order_select::OrderSelectBuilder; pub use number::{FloatBuilder, IntBuilder}; pub use password::PasswordBuilder; pub use raw_select::RawSelectBuilder; @@ -54,6 +56,7 @@ use options::Options; /// - [`select`](Question::select) /// - [`raw_select`](Question::raw_select) /// - [`multi_select`](Question::multi_select) +/// - [`order_select`](Question::order_select) /// - [`custom`](Question::custom) /// /// Every [`Question`] has 4 common options. @@ -431,6 +434,41 @@ impl Question<'static> { MultiSelectBuilder::new(name.into()) } + // TODO : update desc + /// Prompt that allows the user to select multiple items from a list of options + /// + /// Unlike the other list based prompts, this has a per choice boolean default. + /// + /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line, + /// but [`Choice::Separator`]s can only be single line. + /// + /// + /// + /// See the various methods on the [`builder`] for more details on each available option. + /// + /// # Examples + /// + /// ``` + /// use requestty::{Question, DefaultSeparator}; + /// + /// let multi_select = Question::multi_select("cheese") + /// .message("What cheese do you want?") + /// .choice_with_default("Mozzarella", true) + /// .choices(vec![ + /// "Cheddar", + /// "Parmesan", + /// ]) + /// .build(); + /// ``` + /// + /// [`builder`]: MultiSelectBuilder + pub fn order_select>(name: N) -> OrderSelectBuilder<'static> { + OrderSelectBuilder::new(name.into()) + } + /// Create a [`Question`] from a custom prompt. /// /// See [`Prompt`] for more information on writing custom prompts and the various methods on the @@ -488,6 +526,7 @@ enum QuestionKind<'a> { RawSelect(raw_select::RawSelect<'a>), Expand(expand::Expand<'a>), MultiSelect(multi_select::MultiSelect<'a>), + OrderSelect(order_select::OrderSelect<'a>), Password(password::Password<'a>), Editor(editor::Editor<'a>), Custom(Box), @@ -527,6 +566,7 @@ impl Question<'_> { QuestionKind::RawSelect(r) => r.ask(message, on_esc, answers, b, events)?, QuestionKind::Expand(e) => e.ask(message, on_esc, answers, b, events)?, QuestionKind::MultiSelect(c) => c.ask(message, on_esc, answers, b, events)?, + QuestionKind::OrderSelect(c) => c.ask(message, on_esc, answers, b, events)?, QuestionKind::Password(p) => p.ask(message, on_esc, answers, b, events)?, QuestionKind::Editor(e) => e.ask(message, on_esc, answers, b, events)?, QuestionKind::Custom(mut o) => o.ask(message, answers, b, events)?, diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs new file mode 100644 index 0000000..469e00c --- /dev/null +++ b/src/question/order_select/builder.rs @@ -0,0 +1,222 @@ +use ui::widgets::Text; +use ui::backend::Backend; + +use crate::{question::{Choice, Options}, ListItem}; + +use super::OrderSelect; + +// TODO : make desc +/// +#[derive(Debug)] +pub struct OrderSelectBuilder<'a> { + opts: Options<'a>, + order_select: OrderSelect<'a> +} + +impl<'a> OrderSelectBuilder<'a> { + // TODO : make desc + pub(crate) fn new(name: String) -> Self { + Self { + opts: Options::new(name), + order_select: Default::default() + } + } + + crate::impl_options_builder! { + message + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("cheese") + /// .message("What cheese do you want?") + /// .build(); + /// ``` + + when + /// # Examples + /// + /// ``` + /// use requestty::{Answers, Question}; + /// + /// let multi_select = Question::multi_select("cheese") + /// .when(|previous_answers: &Answers| match previous_answers.get("vegan") { + /// Some(ans) => ans.as_bool().unwrap(), + /// None => true, + /// }) + /// .build(); + /// ``` + + ask_if_answered + /// # Examples + /// + /// ``` + /// use requestty::{Answers, Question}; + /// + /// let multi_select = Question::multi_select("cheese") + /// .ask_if_answered(true) + /// .build(); + /// ``` + + on_esc + /// # Examples + /// + /// ``` + /// use requestty::{Answers, Question, OnEsc}; + /// + /// let multi_select = Question::multi_select("cheese") + /// .on_esc(OnEsc::Terminate) + /// .build(); + /// ``` + } + + crate::impl_filter_builder! { + /// NOTE: The boolean [`Vec`] contains a boolean value for each index even if it is a separator. + /// However it is guaranteed that all the separator indices will be false. + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("evil-cheese") + /// .filter(|mut cheeses, previous_answers| { + /// cheeses.iter_mut().for_each(|checked| *checked = !*checked); + /// cheeses + /// }) + /// .build(); + /// ``` + Vec; order_select + } + + crate::impl_validate_builder! { + /// NOTE: The boolean [`slice`] contains a boolean value for each index even if it is a + /// separator. However it is guaranteed that all the separator indices will be false. + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("cheese") + /// .validate(|cheeses, previous_answers| { + /// if cheeses.iter().filter(|&&a| a).count() < 1 { + /// Err("You must choose at least one cheese.".into()) + /// } else { + /// Ok(()) + /// } + /// }) + /// .build(); + /// ``` + [usize]; order_select + } + + crate::impl_transform_builder! { + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("cheese") + /// .transform(|cheeses, previous_answers, backend| { + /// for cheese in cheeses { + /// write!(backend, "({}) {}, ", cheese.index, cheese.text)?; + /// } + /// Ok(()) + /// }) + /// .build(); + /// ``` + [ListItem]; order_select + } + + /// The maximum height that can be taken by the list + /// + /// If the total height exceeds the page size, the list will be scrollable. + /// + /// The `page_size` must be a minimum of 5. If `page_size` is not set, it will default to 15. + /// + /// # Panics + /// + /// It will panic if the `page_size` is less than 5. + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("cheese") + /// .page_size(10) + /// .build(); + /// ``` + pub fn page_size(mut self, page_size: usize) -> Self { + assert!(page_size >= 5, "page size can be a minimum of 5"); + + self.order_select.choices.set_page_size(page_size); + self + } + + /// Whether to wrap around when user gets to the last element. + /// + /// If `should_loop` is not set, it will default to `true`. + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let multi_select = Question::multi_select("cheese") + /// .should_loop(false) + /// .build(); + /// ``` + pub fn should_loop(mut self, should_loop: bool) -> Self { + self.order_select.choices.set_should_loop(should_loop); + self + } + + // TODO : add docs + /// + pub fn choices(mut self, choices: I) -> Self + where + T: Into>, + I: IntoIterator, + { + self.order_select + .choices + .choices + .extend( + choices.into_iter() + .filter_map(|c| { + if let Choice::Choice(txt) = c.into() { + Some(txt) + } else { + None + } + }) + .map(|c| Choice::Choice(c).map(Text::new)) + ); + self + } + + /// Consumes the builder returning a [`Question`] + /// + /// [`Question`]: crate::question::Question + pub fn build(mut self) -> crate::question::Question<'a> { + self.order_select.order = (0..self.order_select.choices.len()) + .collect(); + + crate::question::Question::new( + self.opts, + crate::question::QuestionKind::OrderSelect(self.order_select), + ) + } +} + +impl<'a> From> for crate::question::Question<'a> { + /// Consumes the builder returning a [`Question`] + /// + /// [`Question`]: crate::question::Question + fn from(builder: OrderSelectBuilder<'a>) -> Self { + builder.build() + } +} \ No newline at end of file diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs new file mode 100644 index 0000000..9e07e92 --- /dev/null +++ b/src/question/order_select/mod.rs @@ -0,0 +1,242 @@ +mod builder; + +use std::io; + +use ui::{widgets::{Text, self, List}, Widget, Prompt, backend::Backend, events::EventIterator, style::Color}; + +use crate::{Answers, ListItem, Answer}; + +use super::{handler::{Transform, Validate, Filter}, Choice}; + +pub use builder::OrderSelectBuilder; + +// ============================================================================= +// +// ============================================================================= + +#[derive(Debug, Default)] +pub(super) struct OrderSelect<'a> { + choices: super::ChoiceList>, + order: Vec, + moving: bool, + + transform: Transform<'a, [ListItem]>, + validate: Validate<'a, [usize]>, + filter: Filter<'a, Vec> +} + +impl widgets::List for OrderSelect<'_> { + fn render_item( + &mut self, + index: usize, + hovered: bool, + mut layout: ui::layout::Layout, + b: &mut B, + ) -> std::io::Result<()> { + let symbol_set = ui::symbols::current(); + + if hovered { + if self.moving { + b.set_bg(Color::Cyan)?; + b.set_fg(Color::Black)?; + } else { + b.set_fg(Color::Cyan)?; + } + + write!(b, "{} ", symbol_set.pointer)?; + } else { + b.write_all(b" ")?; + } + + layout.offset_x += 4; + + write!(b, "{} ", index + 1)?; + + layout.offset_x += 2; + + self.choices[self.order[index]].render(&mut layout, b)?; + + b.set_fg(Color::Reset)?; + b.set_bg(Color::Reset) + } + + fn is_selectable(&self, _index: usize) -> bool { + true + } + + fn page_size(&self) -> usize { + self.choices.page_size() + } + + fn should_loop(&self) -> bool { + self.choices.should_loop() + } + + fn height_at(&mut self, index: usize, mut layout: ui::layout::Layout) -> u16 { + layout.offset_x += 4; + self.choices[index].height(&mut layout) + } + + fn len(&self) -> usize { + self.choices.len() + } +} + +impl<'c> OrderSelect<'c> { + fn into_multi_select_prompt<'a>( + self, + message: &'a str, + answers: &'a Answers + ) -> OrderSelectPrompt<'a, 'c> { + OrderSelectPrompt { + prompt: widgets::Prompt::new(message) + .with_hint("Press to take and place an option, and and to move"), + select: widgets::Select::new(self), + answers + } + } + + pub(crate) fn ask( + mut self, + message: String, + on_esc: ui::OnEsc, + answers: &Answers, + b: &mut B, + events: &mut E, + ) -> ui::Result> { + let transform = self.transform.take(); + + let ans = ui::Input::new(self.into_multi_select_prompt(&message, answers), b) + .hide_cursor() + .on_esc(on_esc) + .run(events)?; + + crate::write_final!(transform, message, ans [ref], answers, b, |ans| { + b.set_fg(Color::Cyan)?; + print_comma_separated( + ans.iter().map(|item| { + item.text + .lines() + .next() + .expect("There must be at least one line in a `str`") + }), + b, + )?; + b.set_fg(Color::Reset)?; + }) + } +} + +fn print_comma_separated<'a, B: Backend>( + iter: impl Iterator, + b: &mut B, +) -> io::Result<()> { + let mut iter = iter.peekable(); + + while let Some(item) = iter.next() { + b.write_all(item.as_bytes())?; + if iter.peek().is_some() { + b.write_all(b", ")?; + } + } + + Ok(()) +} + +// ============================================================================= +// +// ============================================================================= + +struct OrderSelectPrompt<'a, 'c> { + prompt: widgets::Prompt<&'a str>, + select: widgets::Select>, + answers: &'a Answers, +} + +impl Prompt for OrderSelectPrompt<'_, '_> { + type ValidateErr = widgets::Text; + type Output = Vec; + + fn finish(self) -> Self::Output { + let OrderSelect { + choices, + mut order, + filter, + .. + } = self.select.into_inner(); + + if let Filter::Sync(filter) = filter { + order = filter(order, self.answers); + } + + order.into_iter() + .filter_map(|i| match &choices.choices[i] { + Choice::Choice(text) => Some(ListItem { + index: i, + text: text.text.clone() + }), + _ => None + }) + .collect() + } + + fn validate(&mut self) -> Result { + if let Validate::Sync(ref mut validate) = self.select.list.validate { + validate(&self.select.list.order, self.answers)?; + } + Ok(ui::Validation::Finish) + } +} + +macro_rules! key_swap { + ($self: expr, $key: expr, $go_back_if: expr, $go_back_val: expr, $op: tt) => { + { + if $self.select.list.moving { + let mut should_swap = true; + let p1 = $self.select.get_at(); + let p2 = if p1 == $go_back_if { + if $self.select.list.should_loop() { + $go_back_val + } else { + should_swap = false; + p1 + } + } else { + p1 $op 1 + }; + + if should_swap { + $self.select.list.order.swap(p1, p2); + } + } + $self.select.handle_key($key); + } + }; +} + +impl Widget for OrderSelectPrompt<'_, '_> { + fn render(&mut self, layout: &mut ui::layout::Layout, backend: &mut B) -> io::Result<()> { + self.prompt.render(layout, backend)?; + self.select.render(layout, backend) + } + + fn height(&mut self, layout: &mut ui::layout::Layout) -> u16 { + self.prompt.height(layout) + self.select.height(layout) - 1 + } + + fn cursor_pos(&mut self, layout: ui::layout::Layout) -> (u16, u16) { + self.select.cursor_pos(layout) + } + + fn handle_key(&mut self, key: ui::events::KeyEvent) -> bool { + match key.code { + ui::events::KeyCode::Up => key_swap!(self, key, 0, self.select.list.choices.len() - 1, -), + ui::events::KeyCode::Down => key_swap!(self, key, self.select.list.choices.len() - 1, 0, +), + + ui::events::KeyCode::Char(' ') => self.select.list.moving = !self.select.list.moving, + _ => return self.select.handle_key(key) + } + + true + } +} From 44738898f2f202e0fa5ca7115b200ec0e7863140 Mon Sep 17 00:00:00 2001 From: NovaliX Date: Sun, 14 Aug 2022 00:19:17 +0200 Subject: [PATCH 02/31] Added docs --- src/question/mod.rs | 21 ++++---- src/question/order_select/builder.rs | 81 +++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/question/mod.rs b/src/question/mod.rs index a5a4697..3dbcef8 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -435,13 +435,12 @@ impl Question<'static> { } // TODO : update desc - /// Prompt that allows the user to select multiple items from a list of options - /// - /// Unlike the other list based prompts, this has a per choice boolean default. + /// Prompt that allows the user to organize a list of options. /// - /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line, - /// but [`Choice::Separator`]s can only be single line. + /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. + /// but [`Choice::Separator`]s will be ignored. /// + /// // TODO : add a gif for OrderSelect /// { /// ``` /// use requestty::{Question, DefaultSeparator}; /// - /// let multi_select = Question::multi_select("cheese") - /// .message("What cheese do you want?") - /// .choice_with_default("Mozzarella", true) + /// let multi_select = Question::order_select("tasks") + /// .message("Please organize the tasks") /// .choices(vec![ - /// "Cheddar", - /// "Parmesan", + /// "Task 1", + /// "Task 2", + /// "Task 3", /// ]) /// .build(); /// ``` /// - /// [`builder`]: MultiSelectBuilder + /// [`builder`]: OrderSelectBuilder pub fn order_select>(name: N) -> OrderSelectBuilder<'static> { OrderSelectBuilder::new(name.into()) } diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 469e00c..45b0ed5 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -5,8 +5,34 @@ use crate::{question::{Choice, Options}, ListItem}; use super::OrderSelect; -// TODO : make desc + /// Prompt that allows the user to organize a list of options. + /// + /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. + /// but [`Choice::Separator`]s will be ignored. +/// +/// // TODO : add gif +/// +/// +/// See the various methods for more details on each available option. +/// +/// # Examples /// +/// ``` +/// let order_select = Question::order_select("tasks") +/// .message("Please organize the tasks") +/// .choices(vec![ +/// "Task 1", +/// "Task 2", +/// "Task 3", +/// ]) +/// .build(); +/// ``` +/// +/// +/// [`order_select`]: crate::question::Question::order_select #[derive(Debug)] pub struct OrderSelectBuilder<'a> { opts: Options<'a>, @@ -14,7 +40,6 @@ pub struct OrderSelectBuilder<'a> { } impl<'a> OrderSelectBuilder<'a> { - // TODO : make desc pub(crate) fn new(name: String) -> Self { Self { opts: Options::new(name), @@ -29,8 +54,9 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("cheese") - /// .message("What cheese do you want?") + /// let order_select = Question::order_select("cheese") + /// .message("Organize the cheeses") + /// ... /// .build(); /// ``` @@ -40,11 +66,13 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question}; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") + /// ... /// .when(|previous_answers: &Answers| match previous_answers.get("vegan") { /// Some(ans) => ans.as_bool().unwrap(), /// None => true, /// }) + /// ... /// .build(); /// ``` @@ -54,8 +82,10 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question}; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") + /// ... /// .ask_if_answered(true) + /// ... /// .build(); /// ``` @@ -65,8 +95,10 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question, OnEsc}; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") + /// ... /// .on_esc(OnEsc::Terminate) + /// ... /// .build(); /// ``` } @@ -80,11 +112,13 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("evil-cheese") + /// let order_select = Question::order_select("evil-cheese") + /// ... /// .filter(|mut cheeses, previous_answers| { /// cheeses.iter_mut().for_each(|checked| *checked = !*checked); /// cheeses /// }) + /// ... /// .build(); /// ``` Vec; order_select @@ -99,7 +133,8 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") + /// ... /// .validate(|cheeses, previous_answers| { /// if cheeses.iter().filter(|&&a| a).count() < 1 { /// Err("You must choose at least one cheese.".into()) @@ -107,6 +142,7 @@ impl<'a> OrderSelectBuilder<'a> { /// Ok(()) /// } /// }) + /// ... /// .build(); /// ``` [usize]; order_select @@ -118,7 +154,7 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") /// .transform(|cheeses, previous_answers, backend| { /// for cheese in cheeses { /// write!(backend, "({}) {}, ", cheese.index, cheese.text)?; @@ -145,7 +181,7 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") /// .page_size(10) /// .build(); /// ``` @@ -165,7 +201,7 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let multi_select = Question::multi_select("cheese") + /// let order_select = Question::order_select("cheese") /// .should_loop(false) /// .build(); /// ``` @@ -175,7 +211,28 @@ impl<'a> OrderSelectBuilder<'a> { } // TODO : add docs + /// Extends the given iterator of [`Choice`]s + /// + /// All separators will be ignored. + /// + /// See [`order_select`] for more information. /// + /// [`Choice`]: crate::question::Choice + /// [`order_select`]: crate::question::Question::order_select + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let order_select = Question::order_select("cheese") + /// .choices(vec![ + /// "Mozzarella", + /// "Cheddar", + /// "Parmesan", + /// ]) + /// .build(); + /// ``` pub fn choices(mut self, choices: I) -> Self where T: Into>, From be019a65e87681c40324740d5ffd879e32ce7bc4 Mon Sep 17 00:00:00 2001 From: NovaliX Date: Sun, 14 Aug 2022 00:33:36 +0200 Subject: [PATCH 03/31] minor fixe --- src/question/order_select/builder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 45b0ed5..f5d5bc1 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -5,10 +5,10 @@ use crate::{question::{Choice, Options}, ListItem}; use super::OrderSelect; - /// Prompt that allows the user to organize a list of options. - /// - /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. - /// but [`Choice::Separator`]s will be ignored. +/// Prompt that allows the user to organize a list of options. +/// +/// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. +/// but [`Choice::Separator`]s will be ignored. /// /// // TODO : add gif /// Date: Sun, 14 Aug 2022 00:34:53 +0200 Subject: [PATCH 04/31] minor fixe --- src/question/order_select/builder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 45b0ed5..f5d5bc1 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -5,10 +5,10 @@ use crate::{question::{Choice, Options}, ListItem}; use super::OrderSelect; - /// Prompt that allows the user to organize a list of options. - /// - /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. - /// but [`Choice::Separator`]s will be ignored. +/// Prompt that allows the user to organize a list of options. +/// +/// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. +/// but [`Choice::Separator`]s will be ignored. /// /// // TODO : add gif /// Date: Sun, 14 Aug 2022 00:35:25 +0200 Subject: [PATCH 05/31] minor fixes and reformatting --- src/question/mod.rs | 5 +-- src/question/order_select/builder.rs | 44 ++++++++++----------- src/question/order_select/mod.rs | 57 ++++++++++++++++++---------- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/question/mod.rs b/src/question/mod.rs index 3dbcef8..462e2b8 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -9,8 +9,8 @@ mod handler; mod impl_macros; mod input; mod multi_select; -mod order_select; mod number; +mod order_select; #[macro_use] mod options; mod custom_prompt; @@ -25,8 +25,8 @@ pub use editor::EditorBuilder; pub use expand::ExpandBuilder; pub use input::InputBuilder; pub use multi_select::MultiSelectBuilder; -pub use order_select::OrderSelectBuilder; pub use number::{FloatBuilder, IntBuilder}; +pub use order_select::OrderSelectBuilder; pub use password::PasswordBuilder; pub use raw_select::RawSelectBuilder; pub use select::SelectBuilder; @@ -434,7 +434,6 @@ impl Question<'static> { MultiSelectBuilder::new(name.into()) } - // TODO : update desc /// Prompt that allows the user to organize a list of options. /// /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index f5d5bc1..a809104 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -1,7 +1,10 @@ -use ui::widgets::Text; use ui::backend::Backend; +use ui::widgets::Text; -use crate::{question::{Choice, Options}, ListItem}; +use crate::{ + question::{Choice, Options}, + ListItem, +}; use super::OrderSelect; @@ -36,14 +39,14 @@ use super::OrderSelect; #[derive(Debug)] pub struct OrderSelectBuilder<'a> { opts: Options<'a>, - order_select: OrderSelect<'a> + order_select: OrderSelect<'a>, } impl<'a> OrderSelectBuilder<'a> { pub(crate) fn new(name: String) -> Self { - Self { + Self { opts: Options::new(name), - order_select: Default::default() + order_select: Default::default(), } } @@ -238,20 +241,18 @@ impl<'a> OrderSelectBuilder<'a> { T: Into>, I: IntoIterator, { - self.order_select - .choices - .choices - .extend( - choices.into_iter() - .filter_map(|c| { - if let Choice::Choice(txt) = c.into() { - Some(txt) - } else { - None - } - }) - .map(|c| Choice::Choice(c).map(Text::new)) - ); + self.order_select.choices.choices.extend( + choices + .into_iter() + .filter_map(|c| { + if let Choice::Choice(txt) = c.into() { + Some(txt) + } else { + None + } + }) + .map(|c| Choice::Choice(c).map(Text::new)), + ); self } @@ -259,8 +260,7 @@ impl<'a> OrderSelectBuilder<'a> { /// /// [`Question`]: crate::question::Question pub fn build(mut self) -> crate::question::Question<'a> { - self.order_select.order = (0..self.order_select.choices.len()) - .collect(); + self.order_select.order = (0..self.order_select.choices.len()).collect(); crate::question::Question::new( self.opts, @@ -276,4 +276,4 @@ impl<'a> From> for crate::question::Question<'a> { fn from(builder: OrderSelectBuilder<'a>) -> Self { builder.build() } -} \ No newline at end of file +} diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 9e07e92..55532cb 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -2,16 +2,25 @@ mod builder; use std::io; -use ui::{widgets::{Text, self, List}, Widget, Prompt, backend::Backend, events::EventIterator, style::Color}; +use ui::{ + backend::Backend, + events::EventIterator, + style::Color, + widgets::{self, List, Text}, + Prompt, Widget, +}; -use crate::{Answers, ListItem, Answer}; +use crate::{Answer, Answers, ListItem}; -use super::{handler::{Transform, Validate, Filter}, Choice}; +use super::{ + handler::{Filter, Transform, Validate}, + Choice, +}; pub use builder::OrderSelectBuilder; // ============================================================================= -// +// // ============================================================================= #[derive(Debug, Default)] @@ -22,7 +31,7 @@ pub(super) struct OrderSelect<'a> { transform: Transform<'a, [ListItem]>, validate: Validate<'a, [usize]>, - filter: Filter<'a, Vec> + filter: Filter<'a, Vec>, } impl widgets::List for OrderSelect<'_> { @@ -86,13 +95,14 @@ impl<'c> OrderSelect<'c> { fn into_multi_select_prompt<'a>( self, message: &'a str, - answers: &'a Answers + answers: &'a Answers, ) -> OrderSelectPrompt<'a, 'c> { OrderSelectPrompt { - prompt: widgets::Prompt::new(message) - .with_hint("Press to take and place an option, and and to move"), + prompt: widgets::Prompt::new(message).with_hint( + "Press to take and place an option, and and to move", + ), select: widgets::Select::new(self), - answers + answers, } } @@ -144,7 +154,7 @@ fn print_comma_separated<'a, B: Backend>( } // ============================================================================= -// +// // ============================================================================= struct OrderSelectPrompt<'a, 'c> { @@ -158,8 +168,8 @@ impl Prompt for OrderSelectPrompt<'_, '_> { type Output = Vec; fn finish(self) -> Self::Output { - let OrderSelect { - choices, + let OrderSelect { + choices, mut order, filter, .. @@ -169,13 +179,14 @@ impl Prompt for OrderSelectPrompt<'_, '_> { order = filter(order, self.answers); } - order.into_iter() + order + .into_iter() .filter_map(|i| match &choices.choices[i] { Choice::Choice(text) => Some(ListItem { index: i, - text: text.text.clone() + text: text.text.clone(), }), - _ => None + _ => None, }) .collect() } @@ -215,7 +226,11 @@ macro_rules! key_swap { } impl Widget for OrderSelectPrompt<'_, '_> { - fn render(&mut self, layout: &mut ui::layout::Layout, backend: &mut B) -> io::Result<()> { + fn render( + &mut self, + layout: &mut ui::layout::Layout, + backend: &mut B, + ) -> io::Result<()> { self.prompt.render(layout, backend)?; self.select.render(layout, backend) } @@ -230,11 +245,15 @@ impl Widget for OrderSelectPrompt<'_, '_> { fn handle_key(&mut self, key: ui::events::KeyEvent) -> bool { match key.code { - ui::events::KeyCode::Up => key_swap!(self, key, 0, self.select.list.choices.len() - 1, -), - ui::events::KeyCode::Down => key_swap!(self, key, self.select.list.choices.len() - 1, 0, +), + ui::events::KeyCode::Up => { + key_swap!(self, key, 0, self.select.list.choices.len() - 1, -) + } + ui::events::KeyCode::Down => { + key_swap!(self, key, self.select.list.choices.len() - 1, 0, +) + } ui::events::KeyCode::Char(' ') => self.select.list.moving = !self.select.list.moving, - _ => return self.select.handle_key(key) + _ => return self.select.handle_key(key), } true From 2eed5072cbe117a0dd0bdef84e3ff0ffa56ee3c4 Mon Sep 17 00:00:00 2001 From: NovaliX Date: Sun, 14 Aug 2022 00:40:20 +0200 Subject: [PATCH 06/31] Added example --- examples/order-select.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 examples/order-select.rs diff --git a/examples/order-select.rs b/examples/order-select.rs new file mode 100644 index 0000000..c595f83 --- /dev/null +++ b/examples/order-select.rs @@ -0,0 +1,21 @@ +use requestty::Question; + +fn main() { + let order_select = Question::order_select("tasks") + .message("Please organize the tasks") + .choices(vec![ + "Task 1", + "Task 2", + "Task 3", + ]) + .validate(|o, _| { + if o[0] == 0 { + Ok(()) + } else { + Err("Task 1 needs to be done first.".to_string()) + } + }) + .build(); + + println!("{:#?}", requestty::prompt_one(order_select)); +} \ No newline at end of file From ec9e97db7bf278c0ee1999badb2a19ca19da60db Mon Sep 17 00:00:00 2001 From: NovaliX Date: Sun, 14 Aug 2022 23:17:53 +0200 Subject: [PATCH 07/31] Added index formatting --- src/question/order_select/builder.rs | 1 + src/question/order_select/mod.rs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index a809104..d25b920 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -261,6 +261,7 @@ impl<'a> OrderSelectBuilder<'a> { /// [`Question`]: crate::question::Question pub fn build(mut self) -> crate::question::Question<'a> { self.order_select.order = (0..self.order_select.choices.len()).collect(); + self.order_select.max_number_len = (self.order_select.order.len() + 1).to_string().len(); crate::question::Question::new( self.opts, diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 55532cb..162fdd3 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -26,6 +26,7 @@ pub use builder::OrderSelectBuilder; #[derive(Debug, Default)] pub(super) struct OrderSelect<'a> { choices: super::ChoiceList>, + max_number_len: usize, order: Vec, moving: bool, @@ -59,7 +60,14 @@ impl widgets::List for OrderSelect<'_> { layout.offset_x += 4; - write!(b, "{} ", index + 1)?; + let mut index_str = (index + 1).to_string(); + index_str.extend( + ' '.to_string() + .repeat(self.max_number_len - index_str.len()) + .chars() + ); + + write!(b, "{} ", index_str)?; layout.offset_x += 2; @@ -92,7 +100,7 @@ impl widgets::List for OrderSelect<'_> { } impl<'c> OrderSelect<'c> { - fn into_multi_select_prompt<'a>( + fn into_order_select_prompt<'a>( self, message: &'a str, answers: &'a Answers, @@ -116,7 +124,7 @@ impl<'c> OrderSelect<'c> { ) -> ui::Result> { let transform = self.transform.take(); - let ans = ui::Input::new(self.into_multi_select_prompt(&message, answers), b) + let ans = ui::Input::new(self.into_order_select_prompt(&message, answers), b) .hide_cursor() .on_esc(on_esc) .run(events)?; From cb0293d46025f4350c47fb8b8e01d3df5d9f7d41 Mon Sep 17 00:00:00 2001 From: NovaliX Date: Mon, 15 Aug 2022 16:25:29 +0200 Subject: [PATCH 08/31] added automatic testing --- src/question/order_select/mod.rs | 3 + src/question/order_select/tests.rs | 151 +++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/question/order_select/tests.rs diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 162fdd3..7251687 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -19,6 +19,9 @@ use super::{ pub use builder::OrderSelectBuilder; +#[cfg(test)] +mod tests; + // ============================================================================= // // ============================================================================= diff --git a/src/question/order_select/tests.rs b/src/question/order_select/tests.rs new file mode 100644 index 0000000..0c68afe --- /dev/null +++ b/src/question/order_select/tests.rs @@ -0,0 +1,151 @@ +use rand::prelude::*; +use rand_chacha::ChaCha12Rng; +use ui::{backend::TestBackend, layout::Layout, events::{KeyCode, KeyEvent}}; + +use crate::question::{Question, QuestionKind}; + +use super::*; + +const SEED: u64 = 9828123; +// separators are ignored +const SEP_RATIO: f32 = 0.0; +const DEFAULT_SEP_RATIO: f32 = 0.0; + +fn choices_with_default(len: usize) -> impl Iterator> { + let mut rng = ChaCha12Rng::seed_from_u64(SEED); + + (0..len).map(move |i| { + let rand: f32 = rng.gen(); + if rand < DEFAULT_SEP_RATIO { + Choice::DefaultSeparator + } else if rand < SEP_RATIO { + Choice::Separator(format!("Separator {}", i)) + } else { + Choice::Choice((format!("Choice {}", i), rand > 0.7)) + } + }) +} + +fn choices(len: usize) -> impl Iterator> { + choices_with_default(len).map(|choice| choice.map(|(c, _)| c)) +} + +fn unwrap_order_select<'a>(question: impl Into>) -> OrderSelect<'a> { + match question.into().kind { + QuestionKind::OrderSelect(c) => c, + _ => unreachable!(), + } +} + +macro_rules! test_order_select { + ($mod_name:ident { order_select = $order_select:expr; height = $height:expr $(;)? }) => { + test_order_select!($mod_name { + order_select = $order_select; + height = $height; + events = [ + KeyEvent::from(KeyCode::Char(' ')), + KeyCode::Up.into(), + KeyCode::Down.into(), + KeyCode::Char(' ').into(), + ]; + answers = Answers::default() + }); + }; + + ($mod_name:ident { order_select = $order_select:expr; height = $height:expr; events = $events:expr $(;)? }) => { + test_order_select!($mod_name { + order_select = $order_select; + height = $height; + events = $events; + answers = Answers::default() + }); + }; + + ($mod_name:ident { order_select = $order_select:expr; height = $height:expr; events = $events:expr; answers = $answers:expr $(;)? }) => { + mod $mod_name { + use super::*; + + #[test] + fn test_height() { + let size = (50, 20).into(); + let base_layout = Layout::new(5, size); + let answers = $answers; + let mut order_select = $order_select.into_order_select_prompt("message", &answers); + + let events = $events; + + for &key in events.iter() { + let mut layout = base_layout; + + assert_eq!(order_select.height(&mut layout), $height); + assert_eq!( + layout, + base_layout.with_offset(0, $height).with_line_offset(0) + ); + + assert!(order_select.handle_key(key)) + } + + let mut layout = base_layout; + + assert_eq!(order_select.height(&mut layout), $height); + assert_eq!( + layout, + base_layout.with_offset(0, $height).with_line_offset(0) + ); + } + + #[test] + fn test_render() { + let size = (50, 20).into(); + let base_layout = Layout::new(5, size); + let answers = $answers; + let mut order_select = $order_select.into_order_select_prompt("message", &answers); + + let mut backend = TestBackend::new(size); + + let events = $events; + + for &key in events.iter() { + let mut layout = base_layout; + backend.reset_with_layout(layout); + + assert!(order_select.render(&mut layout, &mut backend).is_ok()); + assert_eq!( + layout, + base_layout.with_offset(0, $height).with_line_offset(0) + ); + // key events (Up and down) will change the view, triggering an error + // ui::assert_backend_snapshot!(backend); + + assert!(order_select.handle_key(key)) + } + + let mut layout = base_layout; + backend.reset_with_layout(layout); + + assert!(order_select.render(&mut layout, &mut backend).is_ok()); + assert_eq!( + layout, + base_layout.with_offset(0, $height).with_line_offset(0) + ); + // key events (Up and down) will change the view, triggering an error + // ui::assert_backend_snapshot!(backend); + } + } + }; +} + +test_order_select!(basic { + order_select = unwrap_order_select( + OrderSelectBuilder::new("name".into()).choices(choices(10)), + ); + height = 12; +}); + +test_order_select!(pagination { + order_select = unwrap_order_select( + OrderSelectBuilder::new("name".into()).choices(choices(20)), + ); + height = 17; +}); From 1b03b980dafe55a721c99a5c6e46ada45b6635fb Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 16:15:51 +0200 Subject: [PATCH 09/31] Updated docs about choices type --- src/question/mod.rs | 3 +-- src/question/order_select/builder.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/question/mod.rs b/src/question/mod.rs index 462e2b8..230a9ec 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -436,8 +436,7 @@ impl Question<'static> { /// Prompt that allows the user to organize a list of options. /// - /// The choices are represented with the [`Choice`] enum. [`Choice::Choice`] can be multi-line. - /// but [`Choice::Separator`]s will be ignored. + /// The choices are [`String`]s and can be multiline. /// /// // TODO : add a gif for OrderSelect /// Date: Sat, 27 Aug 2022 16:35:47 +0200 Subject: [PATCH 10/31] Optimized index display --- src/question/order_select/builder.rs | 2 +- src/question/order_select/mod.rs | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index bb1dd44..8ff9574 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -260,7 +260,7 @@ impl<'a> OrderSelectBuilder<'a> { /// [`Question`]: crate::question::Question pub fn build(mut self) -> crate::question::Question<'a> { self.order_select.order = (0..self.order_select.choices.len()).collect(); - self.order_select.max_number_len = (self.order_select.order.len() + 1).to_string().len(); + self.order_select.max_index_width = (self.order_select.order.len() as f64 + 1.0).log10() as usize + 1; crate::question::Question::new( self.opts, diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 7251687..a9cea56 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -29,7 +29,7 @@ mod tests; #[derive(Debug, Default)] pub(super) struct OrderSelect<'a> { choices: super::ChoiceList>, - max_number_len: usize, + max_index_width: usize, order: Vec, moving: bool, @@ -61,18 +61,14 @@ impl widgets::List for OrderSelect<'_> { b.write_all(b" ")?; } - layout.offset_x += 4; + write!( + b, + "{:>width$}. ", + index, + width = self.max_index_width as usize + )?; - let mut index_str = (index + 1).to_string(); - index_str.extend( - ' '.to_string() - .repeat(self.max_number_len - index_str.len()) - .chars() - ); - - write!(b, "{} ", index_str)?; - - layout.offset_x += 2; + layout.offset_x += self.max_index_width as u16 + 4; self.choices[self.order[index]].render(&mut layout, b)?; @@ -93,7 +89,7 @@ impl widgets::List for OrderSelect<'_> { } fn height_at(&mut self, index: usize, mut layout: ui::layout::Layout) -> u16 { - layout.offset_x += 4; + layout.offset_x += self.max_index_width as u16 + 4; self.choices[index].height(&mut layout) } From b4033ae0f1f813ad9429182ba38c47b230ba6332 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 16:37:38 +0200 Subject: [PATCH 11/31] Updated key handling algorithm and key docs --- src/question/order_select/mod.rs | 56 ++++++++++---------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index a9cea56..84d7b02 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -6,7 +6,7 @@ use ui::{ backend::Backend, events::EventIterator, style::Color, - widgets::{self, List, Text}, + widgets::{self, Text}, Prompt, Widget, }; @@ -106,7 +106,7 @@ impl<'c> OrderSelect<'c> { ) -> OrderSelectPrompt<'a, 'c> { OrderSelectPrompt { prompt: widgets::Prompt::new(message).with_hint( - "Press to take and place an option, and and to move", + "Press to take and place an option", ), select: widgets::Select::new(self), answers, @@ -206,32 +206,6 @@ impl Prompt for OrderSelectPrompt<'_, '_> { } } -macro_rules! key_swap { - ($self: expr, $key: expr, $go_back_if: expr, $go_back_val: expr, $op: tt) => { - { - if $self.select.list.moving { - let mut should_swap = true; - let p1 = $self.select.get_at(); - let p2 = if p1 == $go_back_if { - if $self.select.list.should_loop() { - $go_back_val - } else { - should_swap = false; - p1 - } - } else { - p1 $op 1 - }; - - if should_swap { - $self.select.list.order.swap(p1, p2); - } - } - $self.select.handle_key($key); - } - }; -} - impl Widget for OrderSelectPrompt<'_, '_> { fn render( &mut self, @@ -251,18 +225,24 @@ impl Widget for OrderSelectPrompt<'_, '_> { } fn handle_key(&mut self, key: ui::events::KeyEvent) -> bool { - match key.code { - ui::events::KeyCode::Up => { - key_swap!(self, key, 0, self.select.list.choices.len() - 1, -) - } - ui::events::KeyCode::Down => { - key_swap!(self, key, self.select.list.choices.len() - 1, 0, +) + let prev_at = self.select.get_at(); + + if let ui::events::KeyCode::Char(' ') = key.code { + self.select.list.moving = !self.select.list.moving; + } else if self.select.handle_key(key) { + if self.select.list.moving { + let new_at = self.select.get_at(); + + if prev_at < new_at { + self.select.list.order[prev_at..=new_at].rotate_left(1); + } else { + self.select.list.order[new_at..=prev_at].rotate_right(1); + } } - - ui::events::KeyCode::Char(' ') => self.select.list.moving = !self.select.list.moving, - _ => return self.select.handle_key(key), + } else { + return false; } - + true } } From 7bd6d819f1f27e52e0c50fa01559397d3e60f450 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 16:59:00 +0200 Subject: [PATCH 12/31] Updated choice input type as separators aren't allowed --- src/question/order_select/builder.rs | 11 ++--------- src/question/order_select/tests.rs | 26 ++------------------------ 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 8ff9574..00e7905 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -237,20 +237,13 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` pub fn choices(mut self, choices: I) -> Self where - T: Into>, + T: Into, I: IntoIterator, { self.order_select.choices.choices.extend( choices .into_iter() - .filter_map(|c| { - if let Choice::Choice(txt) = c.into() { - Some(txt) - } else { - None - } - }) - .map(|c| Choice::Choice(c).map(Text::new)), + .map(|c| Choice::Choice(Text::new(c.into()))), ); self } diff --git a/src/question/order_select/tests.rs b/src/question/order_select/tests.rs index 0c68afe..7248ffe 100644 --- a/src/question/order_select/tests.rs +++ b/src/question/order_select/tests.rs @@ -1,33 +1,11 @@ -use rand::prelude::*; -use rand_chacha::ChaCha12Rng; use ui::{backend::TestBackend, layout::Layout, events::{KeyCode, KeyEvent}}; use crate::question::{Question, QuestionKind}; use super::*; -const SEED: u64 = 9828123; -// separators are ignored -const SEP_RATIO: f32 = 0.0; -const DEFAULT_SEP_RATIO: f32 = 0.0; - -fn choices_with_default(len: usize) -> impl Iterator> { - let mut rng = ChaCha12Rng::seed_from_u64(SEED); - - (0..len).map(move |i| { - let rand: f32 = rng.gen(); - if rand < DEFAULT_SEP_RATIO { - Choice::DefaultSeparator - } else if rand < SEP_RATIO { - Choice::Separator(format!("Separator {}", i)) - } else { - Choice::Choice((format!("Choice {}", i), rand > 0.7)) - } - }) -} - -fn choices(len: usize) -> impl Iterator> { - choices_with_default(len).map(|choice| choice.map(|(c, _)| c)) +fn choices(len: usize) -> impl Iterator { + (0..len).map(|choice| choice.to_string()) } fn unwrap_order_select<'a>(question: impl Into>) -> OrderSelect<'a> { From 78369365f7ca97cf5f376f58ee891720a316171a Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 16:59:34 +0200 Subject: [PATCH 13/31] put insta tests backs --- ...er_select__tests__basic__render-2.snap.new | 28 +++++++++++++++++++ ...er_select__tests__basic__render-3.snap.new | 28 +++++++++++++++++++ ...er_select__tests__basic__render-4.snap.new | 28 +++++++++++++++++++ ...er_select__tests__basic__render-5.snap.new | 28 +++++++++++++++++++ ...rder_select__tests__basic__render.snap.new | 28 +++++++++++++++++++ ...lect__tests__pagination__render-2.snap.new | 28 +++++++++++++++++++ ...lect__tests__pagination__render-3.snap.new | 28 +++++++++++++++++++ ...lect__tests__pagination__render-4.snap.new | 28 +++++++++++++++++++ ...lect__tests__pagination__render-5.snap.new | 28 +++++++++++++++++++ ...select__tests__pagination__render.snap.new | 28 +++++++++++++++++++ src/question/order_select/tests.rs | 6 ++-- 11 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap.new create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap.new diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap.new new file mode 100644 index 0000000..9f8f332 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 117 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap.new new file mode 100644 index 0000000..e52d02b --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 117 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 0. 1 │ +│ 1. 2 │ +│ 2. 3 │ +│ 3. 4 │ +│ 4. 5 │ +│ 5. 6 │ +│ 6. 7 │ +│ 7. 8 │ +│ 8. 9 │ +│❯ 9. 0 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap.new new file mode 100644 index 0000000..9f8f332 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 117 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap.new new file mode 100644 index 0000000..6ae9a69 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 117 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap.new new file mode 100644 index 0000000..6ae9a69 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 117 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap.new new file mode 100644 index 0000000..9f8f1be --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 124 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│ 12. 12 │ +│ 13. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap.new new file mode 100644 index 0000000..3393669 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 124 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 18. 19 │ +│❯ 19. 0 │ +│ 0. 1 │ +│ 1. 2 │ +│ 2. 3 │ +│ 3. 4 │ +│ 4. 5 │ +│ 5. 6 │ +│ 6. 7 │ +│ 7. 8 │ +│ 8. 9 │ +│ 9. 10 │ +│ 10. 11 │ +│ 11. 12 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap.new new file mode 100644 index 0000000..eb4dc9e --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 124 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 18. 18 │ +│ 19. 19 │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap.new new file mode 100644 index 0000000..29ebb27 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 124 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 18. 18 │ +│ 19. 19 │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap.new b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap.new new file mode 100644 index 0000000..172fd92 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap.new @@ -0,0 +1,28 @@ +--- +source: src/question/order_select/tests.rs +assertion_line: 124 +expression: backend + +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 0. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│ 12. 12 │ +│ 13. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/src/question/order_select/tests.rs b/src/question/order_select/tests.rs index 7248ffe..dcf0e9f 100644 --- a/src/question/order_select/tests.rs +++ b/src/question/order_select/tests.rs @@ -93,8 +93,7 @@ macro_rules! test_order_select { layout, base_layout.with_offset(0, $height).with_line_offset(0) ); - // key events (Up and down) will change the view, triggering an error - // ui::assert_backend_snapshot!(backend); + ui::assert_backend_snapshot!(backend); assert!(order_select.handle_key(key)) } @@ -107,8 +106,7 @@ macro_rules! test_order_select { layout, base_layout.with_offset(0, $height).with_line_offset(0) ); - // key events (Up and down) will change the view, triggering an error - // ui::assert_backend_snapshot!(backend); + ui::assert_backend_snapshot!(backend); } } }; From b300600202bc67e07b2b2ef826008ad057564f8b Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 17:14:25 +0200 Subject: [PATCH 14/31] Updated docs and added more concrete examples --- examples/order-select.rs | 10 ++++---- src/question/mod.rs | 8 +++---- src/question/order_select/builder.rs | 35 +++++++++++++--------------- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/examples/order-select.rs b/examples/order-select.rs index c595f83..d79fd49 100644 --- a/examples/order-select.rs +++ b/examples/order-select.rs @@ -1,12 +1,12 @@ use requestty::Question; fn main() { - let order_select = Question::order_select("tasks") - .message("Please organize the tasks") + let order_select = Question::order_select("home_tasks") + .message("Please organize the tasks to be done at home") .choices(vec![ - "Task 1", - "Task 2", - "Task 3", + "Make the bed", + "Clean the dishes", + "Mow the lawn", ]) .validate(|o, _| { if o[0] == 0 { diff --git a/src/question/mod.rs b/src/question/mod.rs index 230a9ec..6748592 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -452,11 +452,11 @@ impl Question<'static> { /// use requestty::{Question, DefaultSeparator}; /// /// let multi_select = Question::order_select("tasks") - /// .message("Please organize the tasks") + /// .message("Please organize the tasks to be done at home") /// .choices(vec![ - /// "Task 1", - /// "Task 2", - /// "Task 3", + /// "Make the bed", + /// "Clean the dishes", + /// "Mow the lawn", /// ]) /// .build(); /// ``` diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 00e7905..f58267c 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -23,12 +23,12 @@ use super::OrderSelect; /// # Examples /// /// ``` -/// let order_select = Question::order_select("tasks") -/// .message("Please organize the tasks") +/// let order_select = Question::order_select("home_tasks") +/// .message("Please organize the tasks to be done at home") /// .choices(vec![ -/// "Task 1", -/// "Task 2", -/// "Task 3", +/// "Make the bed", +/// "Clean the dishes", +/// "Mow the lawn", /// ]) /// .build(); /// ``` @@ -56,8 +56,8 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let order_select = Question::order_select("cheese") - /// .message("Organize the cheeses") + /// let order_select = Question::order_select("home_tasks") + /// .message("Organize the tasks to be done at home") /// ... /// .build(); /// ``` @@ -68,9 +68,9 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question}; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("home_tasks") /// ... - /// .when(|previous_answers: &Answers| match previous_answers.get("vegan") { + /// .when(|previous_answers: &Answers| match previous_answers.get("home_tasks_left") { /// Some(ans) => ans.as_bool().unwrap(), /// None => true, /// }) @@ -84,7 +84,7 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question}; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("home_tasks") /// ... /// .ask_if_answered(true) /// ... @@ -97,7 +97,7 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::{Answers, Question, OnEsc}; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("home_tasks") /// ... /// .on_esc(OnEsc::Terminate) /// ... @@ -106,9 +106,6 @@ impl<'a> OrderSelectBuilder<'a> { } crate::impl_filter_builder! { - /// NOTE: The boolean [`Vec`] contains a boolean value for each index even if it is a separator. - /// However it is guaranteed that all the separator indices will be false. - /// /// # Examples /// /// ``` @@ -212,10 +209,9 @@ impl<'a> OrderSelectBuilder<'a> { self } - // TODO : add docs /// Extends the given iterator of [`Choice`]s /// - /// All separators will be ignored. + /// The choices are [`String`]s and can be multiline. /// /// See [`order_select`] for more information. /// @@ -227,11 +223,12 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("hamburger") + /// ... /// .choices(vec![ - /// "Mozzarella", + /// "Salad", /// "Cheddar", - /// "Parmesan", + /// "Cheese", /// ]) /// .build(); /// ``` From 74558144c34415a84c9f0f19aa0de2b949245c6b Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sat, 27 Aug 2022 17:15:17 +0200 Subject: [PATCH 15/31] Added comments to the dots that were making the doctests fails --- src/question/order_select/builder.rs | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index f58267c..10fdcc1 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -23,6 +23,8 @@ use super::OrderSelect; /// # Examples /// /// ``` +/// use requestty::Question; +/// /// let order_select = Question::order_select("home_tasks") /// .message("Please organize the tasks to be done at home") /// .choices(vec![ @@ -58,7 +60,7 @@ impl<'a> OrderSelectBuilder<'a> { /// /// let order_select = Question::order_select("home_tasks") /// .message("Organize the tasks to be done at home") - /// ... + /// //... /// .build(); /// ``` @@ -69,12 +71,12 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::{Answers, Question}; /// /// let order_select = Question::order_select("home_tasks") - /// ... + /// //... /// .when(|previous_answers: &Answers| match previous_answers.get("home_tasks_left") { /// Some(ans) => ans.as_bool().unwrap(), /// None => true, /// }) - /// ... + /// //... /// .build(); /// ``` @@ -85,9 +87,9 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::{Answers, Question}; /// /// let order_select = Question::order_select("home_tasks") - /// ... + /// //... /// .ask_if_answered(true) - /// ... + /// //... /// .build(); /// ``` @@ -98,9 +100,9 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::{Answers, Question, OnEsc}; /// /// let order_select = Question::order_select("home_tasks") - /// ... + /// //... /// .on_esc(OnEsc::Terminate) - /// ... + /// //... /// .build(); /// ``` } @@ -112,12 +114,12 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::Question; /// /// let order_select = Question::order_select("evil-cheese") - /// ... + /// //... /// .filter(|mut cheeses, previous_answers| { /// cheeses.iter_mut().for_each(|checked| *checked = !*checked); /// cheeses /// }) - /// ... + /// //... /// .build(); /// ``` Vec; order_select @@ -133,7 +135,7 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::Question; /// /// let order_select = Question::order_select("cheese") - /// ... + /// //... /// .validate(|cheeses, previous_answers| { /// if cheeses.iter().filter(|&&a| a).count() < 1 { /// Err("You must choose at least one cheese.".into()) @@ -141,7 +143,7 @@ impl<'a> OrderSelectBuilder<'a> { /// Ok(()) /// } /// }) - /// ... + /// //... /// .build(); /// ``` [usize]; order_select @@ -154,12 +156,14 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::Question; /// /// let order_select = Question::order_select("cheese") + /// //... /// .transform(|cheeses, previous_answers, backend| { /// for cheese in cheeses { /// write!(backend, "({}) {}, ", cheese.index, cheese.text)?; /// } /// Ok(()) /// }) + /// //... /// .build(); /// ``` [ListItem]; order_select @@ -224,12 +228,13 @@ impl<'a> OrderSelectBuilder<'a> { /// use requestty::Question; /// /// let order_select = Question::order_select("hamburger") - /// ... + /// //... /// .choices(vec![ /// "Salad", /// "Cheddar", /// "Cheese", /// ]) + /// //... /// .build(); /// ``` pub fn choices(mut self, choices: I) -> Self From abf651deb50aaa6f297505bf24d6cb82a6e7353e Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sun, 28 Aug 2022 15:17:33 +0200 Subject: [PATCH 16/31] Updated argument type for filter, validate and transform function as well as for example --- examples/order-select.rs | 8 +- src/answer.rs | 21 ++++- src/question/choice.rs | 2 +- src/question/mod.rs | 2 +- src/question/order_select/builder.rs | 42 +++++----- src/question/order_select/mod.rs | 117 ++++++++++++++++++++------- 6 files changed, 137 insertions(+), 55 deletions(-) diff --git a/examples/order-select.rs b/examples/order-select.rs index d79fd49..591e818 100644 --- a/examples/order-select.rs +++ b/examples/order-select.rs @@ -8,11 +8,11 @@ fn main() { "Clean the dishes", "Mow the lawn", ]) - .validate(|o, _| { - if o[0] == 0 { - Ok(()) + .validate(|c, _| { + if c[0].text() == "Make the bed" { + Err("You have to make the bed first".to_string()) } else { - Err("Task 1 needs to be done first.".to_string()) + Ok(()) } }) .build(); diff --git a/src/answer.rs b/src/answer.rs index c30e2a4..e084d18 100644 --- a/src/answer.rs +++ b/src/answer.rs @@ -5,6 +5,8 @@ use std::{ ops::{Deref, DerefMut}, }; +use crate::question::OrderSelectItem; + /// The different answer types that can be returned by the [`Question`]s /// /// [`Question`]: crate::question::Question @@ -37,9 +39,10 @@ pub enum Answer { /// /// [`confirm`]: crate::question::Question::confirm Bool(bool), - /// ListItems will be returned by [`multi_select`]. + /// ListItems will be returned by [`multi_select`] and [`order_select`]. /// /// [`multi_select`]: crate::question::Question::multi_select + /// [`multi_select`]: crate::question::Question::order_select ListItems(Vec), } @@ -210,6 +213,16 @@ impl_from!(ExpandItem => ExpandItem); impl_from!(ListItem => ListItem); impl_from!(Vec => ListItems); +impl From> for Answer { + fn from(v: Vec) -> Self { + Answer::ListItems( + v.into_iter() + .map(|o| o.into()) + .collect() + ) + } +} + /// A representation of a [`Choice`] at a particular index. /// /// It will be returned by [`select`] and [`raw_select`]. @@ -234,6 +247,12 @@ impl> From<(usize, I)> for ListItem { } } +impl AsRef for ListItem { + fn as_ref(&self) -> &str { + &self.text + } +} + /// A representation of a [`Choice`] for a particular key. /// /// It will be returned by [`expand`]. diff --git a/src/question/choice.rs b/src/question/choice.rs index 12da11c..f28e967 100644 --- a/src/question/choice.rs +++ b/src/question/choice.rs @@ -31,7 +31,7 @@ impl std::fmt::Debug for SelectList { } impl SelectList { - fn new(f: fn(&T) -> bool) -> Self { + pub(crate) fn new(f: fn(&T) -> bool) -> Self { Self { choices: Vec::new(), page_size: 15, diff --git a/src/question/mod.rs b/src/question/mod.rs index 6748592..9a268c4 100644 --- a/src/question/mod.rs +++ b/src/question/mod.rs @@ -26,7 +26,7 @@ pub use expand::ExpandBuilder; pub use input::InputBuilder; pub use multi_select::MultiSelectBuilder; pub use number::{FloatBuilder, IntBuilder}; -pub use order_select::OrderSelectBuilder; +pub use order_select::{OrderSelectBuilder, OrderSelectItem}; pub use password::PasswordBuilder; pub use raw_select::RawSelectBuilder; pub use select::SelectBuilder; diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 10fdcc1..7519982 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -2,11 +2,10 @@ use ui::backend::Backend; use ui::widgets::Text; use crate::{ - question::{Choice, Options}, - ListItem, + question::{Options}, }; -use super::OrderSelect; +use super::{OrderSelect, OrderSelectItem}; /// Prompt that allows the user to organize a list of options. /// @@ -113,16 +112,16 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let order_select = Question::order_select("evil-cheese") + /// let order_select = Question::order_select("evil_home_tasks") /// //... - /// .filter(|mut cheeses, previous_answers| { - /// cheeses.iter_mut().for_each(|checked| *checked = !*checked); - /// cheeses + /// .filter(|mut tasks, previous_answers| { + /// tasks.rotate_left(1); + /// tasks /// }) /// //... /// .build(); /// ``` - Vec; order_select + Vec; order_select } crate::impl_validate_builder! { @@ -134,11 +133,11 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("home_tasks") /// //... - /// .validate(|cheeses, previous_answers| { - /// if cheeses.iter().filter(|&&a| a).count() < 1 { - /// Err("You must choose at least one cheese.".into()) + /// .validate(|tasks, previous_answers| { + /// if tasks[0].text() == "Make the bed" { + /// Err("You have to make the bed first".to_string()) /// } else { /// Ok(()) /// } @@ -146,7 +145,7 @@ impl<'a> OrderSelectBuilder<'a> { /// //... /// .build(); /// ``` - [usize]; order_select + [OrderSelectItem]; order_select } crate::impl_transform_builder! { @@ -159,14 +158,14 @@ impl<'a> OrderSelectBuilder<'a> { /// //... /// .transform(|cheeses, previous_answers, backend| { /// for cheese in cheeses { - /// write!(backend, "({}) {}, ", cheese.index, cheese.text)?; + /// write!(backend, "({}) {}, ", cheese.index(), cheese.text())?; /// } /// Ok(()) /// }) /// //... /// .build(); /// ``` - [ListItem]; order_select + [OrderSelectItem]; order_select } /// The maximum height that can be taken by the list @@ -242,10 +241,18 @@ impl<'a> OrderSelectBuilder<'a> { T: Into, I: IntoIterator, { + let len = self.order_select.choices.choices.len(); + self.order_select.choices.choices.extend( choices .into_iter() - .map(|c| Choice::Choice(Text::new(c.into()))), + .enumerate() + .map(|(i, c)| + OrderSelectItem { + index:len + i, + text: Text::new(c.into()) + } + ), ); self } @@ -254,8 +261,7 @@ impl<'a> OrderSelectBuilder<'a> { /// /// [`Question`]: crate::question::Question pub fn build(mut self) -> crate::question::Question<'a> { - self.order_select.order = (0..self.order_select.choices.len()).collect(); - self.order_select.max_index_width = (self.order_select.order.len() as f64 + 1.0).log10() as usize + 1; + self.order_select.max_index_width = (self.order_select.choices.len() as f64 + 1.0).log10() as usize + 1; crate::question::Question::new( self.opts, diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 84d7b02..834b2cc 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -4,7 +4,7 @@ use std::io; use ui::{ backend::Backend, - events::EventIterator, + events::{EventIterator, KeyEvent}, style::Color, widgets::{self, Text}, Prompt, Widget, @@ -13,8 +13,7 @@ use ui::{ use crate::{Answer, Answers, ListItem}; use super::{ - handler::{Filter, Transform, Validate}, - Choice, + handler::{Filter, Transform, Validate}, choice::SelectList, }; pub use builder::OrderSelectBuilder; @@ -26,18 +25,34 @@ mod tests; // // ============================================================================= -#[derive(Debug, Default)] +#[derive(Debug)] pub(super) struct OrderSelect<'a> { - choices: super::ChoiceList>, + choices: SelectList, max_index_width: usize, - order: Vec, moving: bool, - transform: Transform<'a, [ListItem]>, - validate: Validate<'a, [usize]>, - filter: Filter<'a, Vec>, + transform: Transform<'a, [OrderSelectItem]>, + validate: Validate<'a, [OrderSelectItem]>, + filter: Filter<'a, Vec>, } +impl<'a> Default for OrderSelect<'a> { + fn default() -> Self { + Self { + choices: SelectList::new(|_| true), + + // can't put + // `..Default::default()` + // because of recursion + max_index_width: Default::default(), + moving: Default::default(), + transform: Default::default(), + validate: Default::default(), + filter: Default::default(), + } + } +} + impl widgets::List for OrderSelect<'_> { fn render_item( &mut self, @@ -70,7 +85,7 @@ impl widgets::List for OrderSelect<'_> { layout.offset_x += self.max_index_width as u16 + 4; - self.choices[self.order[index]].render(&mut layout, b)?; + self.choices[index].render(&mut layout, b)?; b.set_fg(Color::Reset)?; b.set_bg(Color::Reset) @@ -132,10 +147,7 @@ impl<'c> OrderSelect<'c> { b.set_fg(Color::Cyan)?; print_comma_separated( ans.iter().map(|item| { - item.text - .lines() - .next() - .expect("There must be at least one line in a `str`") + item.text() }), b, )?; @@ -172,35 +184,27 @@ struct OrderSelectPrompt<'a, 'c> { impl Prompt for OrderSelectPrompt<'_, '_> { type ValidateErr = widgets::Text; - type Output = Vec; + type Output = Vec; fn finish(self) -> Self::Output { let OrderSelect { choices, - mut order, filter, .. } = self.select.into_inner(); + let mut c = choices.choices; + if let Filter::Sync(filter) = filter { - order = filter(order, self.answers); + c = filter(c, self.answers); } - order - .into_iter() - .filter_map(|i| match &choices.choices[i] { - Choice::Choice(text) => Some(ListItem { - index: i, - text: text.text.clone(), - }), - _ => None, - }) - .collect() + c } fn validate(&mut self) -> Result { if let Validate::Sync(ref mut validate) = self.select.list.validate { - validate(&self.select.list.order, self.answers)?; + validate(&self.select.list.choices.choices, self.answers)?; } Ok(ui::Validation::Finish) } @@ -234,9 +238,9 @@ impl Widget for OrderSelectPrompt<'_, '_> { let new_at = self.select.get_at(); if prev_at < new_at { - self.select.list.order[prev_at..=new_at].rotate_left(1); + self.select.list.choices.choices[prev_at..=new_at].rotate_left(1); } else { - self.select.list.order[new_at..=prev_at].rotate_right(1); + self.select.list.choices.choices[new_at..=prev_at].rotate_right(1); } } } else { @@ -246,3 +250,56 @@ impl Widget for OrderSelectPrompt<'_, '_> { true } } + +// ============================================================================= +// +// ============================================================================= + +/// The representation of each choice in an [`OrderSelect`]. +/// +/// It is different from [`ListItem`](crate::answer::ListItem) due to an implementation detail. +#[derive(Debug, Clone, PartialEq)] +pub struct OrderSelectItem { + index: usize, + text: Text, +} + +impl OrderSelectItem { + /// The index of the choice + pub fn index(&self) -> usize { + self.index + } + + /// The content of the choice -- it is what is displayed to the user + pub fn text(&self) -> &str { + &self.text.text + } +} + +impl Widget for OrderSelectItem { + fn render( + &mut self, + layout: &mut ui::layout::Layout, + backend: &mut B, + ) -> io::Result<()> { + self.text.render(layout, backend) + } + + fn height(&mut self, layout: &mut ui::layout::Layout) -> u16 { + self.text.height(layout) + } + + fn cursor_pos(&mut self, layout: ui::layout::Layout) -> (u16, u16) { + self.text.cursor_pos(layout) + } + + fn handle_key(&mut self, key: KeyEvent) -> bool { + self.text.handle_key(key) + } +} + +impl Into for OrderSelectItem { + fn into(self) -> ListItem { + ListItem { index: self.index, text: self.text.text } + } +} From 743c266f185c2d8c728369f155fef03f1dbefabb Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Sun, 28 Aug 2022 15:20:12 +0200 Subject: [PATCH 17/31] Put the filter, validate and transform functions implementation just before build --- src/question/order_select/builder.rs | 124 +++++++++++++-------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 7519982..5f6ba79 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -106,68 +106,6 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` } - crate::impl_filter_builder! { - /// # Examples - /// - /// ``` - /// use requestty::Question; - /// - /// let order_select = Question::order_select("evil_home_tasks") - /// //... - /// .filter(|mut tasks, previous_answers| { - /// tasks.rotate_left(1); - /// tasks - /// }) - /// //... - /// .build(); - /// ``` - Vec; order_select - } - - crate::impl_validate_builder! { - /// NOTE: The boolean [`slice`] contains a boolean value for each index even if it is a - /// separator. However it is guaranteed that all the separator indices will be false. - /// - /// # Examples - /// - /// ``` - /// use requestty::Question; - /// - /// let order_select = Question::order_select("home_tasks") - /// //... - /// .validate(|tasks, previous_answers| { - /// if tasks[0].text() == "Make the bed" { - /// Err("You have to make the bed first".to_string()) - /// } else { - /// Ok(()) - /// } - /// }) - /// //... - /// .build(); - /// ``` - [OrderSelectItem]; order_select - } - - crate::impl_transform_builder! { - /// # Examples - /// - /// ``` - /// use requestty::Question; - /// - /// let order_select = Question::order_select("cheese") - /// //... - /// .transform(|cheeses, previous_answers, backend| { - /// for cheese in cheeses { - /// write!(backend, "({}) {}, ", cheese.index(), cheese.text())?; - /// } - /// Ok(()) - /// }) - /// //... - /// .build(); - /// ``` - [OrderSelectItem]; order_select - } - /// The maximum height that can be taken by the list /// /// If the total height exceeds the page size, the list will be scrollable. @@ -257,6 +195,68 @@ impl<'a> OrderSelectBuilder<'a> { self } + crate::impl_filter_builder! { + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let order_select = Question::order_select("evil_home_tasks") + /// //... + /// .filter(|mut tasks, previous_answers| { + /// tasks.rotate_left(1); + /// tasks + /// }) + /// //... + /// .build(); + /// ``` + Vec; order_select + } + + crate::impl_validate_builder! { + /// NOTE: The boolean [`slice`] contains a boolean value for each index even if it is a + /// separator. However it is guaranteed that all the separator indices will be false. + /// + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let order_select = Question::order_select("home_tasks") + /// //... + /// .validate(|tasks, previous_answers| { + /// if tasks[0].text() == "Make the bed" { + /// Err("You have to make the bed first".to_string()) + /// } else { + /// Ok(()) + /// } + /// }) + /// //... + /// .build(); + /// ``` + [OrderSelectItem]; order_select + } + + crate::impl_transform_builder! { + /// # Examples + /// + /// ``` + /// use requestty::Question; + /// + /// let order_select = Question::order_select("cheese") + /// //... + /// .transform(|cheeses, previous_answers, backend| { + /// for cheese in cheeses { + /// write!(backend, "({}) {}, ", cheese.index(), cheese.text())?; + /// } + /// Ok(()) + /// }) + /// //... + /// .build(); + /// ``` + [OrderSelectItem]; order_select + } + /// Consumes the builder returning a [`Question`] /// /// [`Question`]: crate::question::Question From 36596860e684acdac3c59c01b8a75e9f23ba6a57 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Mon, 29 Aug 2022 08:27:00 +0200 Subject: [PATCH 18/31] implemented implementation tests --- tests/order_select.rs | 149 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 tests/order_select.rs diff --git a/tests/order_select.rs b/tests/order_select.rs new file mode 100644 index 0000000..ae7a047 --- /dev/null +++ b/tests/order_select.rs @@ -0,0 +1,149 @@ +use ui::events::{KeyCode, TestEvents}; + +mod helpers; + +fn choices(len: usize) -> impl Iterator { + (0..len).map(|choice| choice.to_string()) +} + +#[test] +fn test_validate() { + let order_select = requestty::Question::order_select("name") + .validate(|c, _| { + if c[0].text() == "1" { + Err("You have to make the bed first".to_string()) + } else { + Ok(()) + } + }) + .message("order select") + .choices(choices(10)); + + let size = (50, 20).into(); + let mut backend = helpers::SnapshotOnFlushBackend::new(size); + let mut events = TestEvents::new(vec![ + KeyCode::Char(' ').into(), + KeyCode::Down.into(), + KeyCode::Char(' ').into(), + KeyCode::Enter.into(), + ]); + + let ans: Vec<_> = requestty::prompt_one_with(order_select, &mut backend, &mut events) + .unwrap() + .try_into_list_items() + .unwrap() + .into_iter() + .map(|item| item.index) + .collect(); + + assert_eq!(ans, [3, 9]); +} + +#[test] +fn test_filter() { + let order_select = requestty::Question::order_select("name") + .filter(|mut checked, _| { + checked.rotate_left(1); + checked + }) + .message("multi select") + .choices(choices(10)); + + let size = (50, 20).into(); + let mut backend = helpers::SnapshotOnFlushBackend::new(size); + let mut events = TestEvents::new(vec![ + KeyCode::Char(' ').into(), + KeyCode::Down.into(), + KeyCode::Char(' ').into(), + KeyCode::Enter.into(), + ]); + + let ans = requestty::prompt_one_with(order_select, &mut backend, &mut events) + .unwrap() + .try_into_list_items() + .unwrap() + .into_iter() + .map(|a| a.text) + .collect::>(); + + // compute the expected answer + let choices = choices(10).collect::>(); + + assert_eq!(ans, choices); +} + +#[test] +fn test_transform() { + let order_select = requestty::Question::order_select("name") + .transform(|items, _, b| { + b.set_fg(ui::style::Color::Magenta)?; + for (i, item) in items.iter().enumerate() { + write!(b, "{}: {}", item.index(), item.text())?; + if i + 1 != items.len() { + write!(b, ", ")?; + } + } + b.set_fg(ui::style::Color::Reset) + }) + .message("multi select") + .choices(choices(10)); + + let size = (50, 20).into(); + let mut backend = helpers::SnapshotOnFlushBackend::new(size); + let mut events = TestEvents::new(vec![ + KeyCode::Char(' ').into(), + KeyCode::Down.into(), + KeyCode::Char(' ').into(), + KeyCode::Enter.into(), + ]); + + let ans = requestty::prompt_one_with(order_select, &mut backend, &mut events) + .unwrap() + .try_into_list_items() + .unwrap() + .into_iter() + .map(|a| a.text) + .collect::>(); + + // compute the expected answer + let choices = choices(10).collect::>(); + + assert_eq!(ans, choices); +} + +#[test] +fn test_on_esc() { + let size = (50, 20).into(); + let mut backend = helpers::SnapshotOnFlushBackend::new(size); + let mut events = TestEvents::new(Some(KeyCode::Esc.into())); + + let res = requestty::prompt_one_with( + requestty::Question::order_select("name") + .message("message") + .choices(choices(10)) + .on_esc(requestty::OnEsc::Terminate), + &mut backend, + &mut events, + ); + + assert!(matches!(res, Err(requestty::ErrorKind::Aborted))); + + let size = (50, 20).into(); + let mut backend = helpers::SnapshotOnFlushBackend::new(size); + let mut events = TestEvents::new(Some(KeyCode::Esc.into())); + + let res = requestty::prompt_with( + Some( + requestty::Question::order_select("name") + .message("message") + .choices(choices(10)) + .on_esc(requestty::OnEsc::SkipQuestion) + .build(), + ), + &mut backend, + &mut events, + ) + .unwrap(); + + assert!(res.is_empty()); +} From 4faaee44dc62f5e40810dce806f946a5b531942a Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 13:34:52 +0200 Subject: [PATCH 19/31] added a more concrete example on when function --- src/question/order_select/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 5f6ba79..464cd3a 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -71,8 +71,8 @@ impl<'a> OrderSelectBuilder<'a> { /// /// let order_select = Question::order_select("home_tasks") /// //... - /// .when(|previous_answers: &Answers| match previous_answers.get("home_tasks_left") { - /// Some(ans) => ans.as_bool().unwrap(), + /// .when(|previous_answers: &Answers| match previous_answers.get("on_vacation") { + /// Some(ans) => !ans.as_bool().unwrap(), /// None => true, /// }) /// //... From b49b93eb9b09c5edd20675b2ed5db234ca4882db Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 16:43:47 +0200 Subject: [PATCH 20/31] Fix validate test always failing because validation failed --- tests/order_select.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/order_select.rs b/tests/order_select.rs index ae7a047..9bde02c 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -26,6 +26,11 @@ fn test_validate() { KeyCode::Down.into(), KeyCode::Char(' ').into(), KeyCode::Enter.into(), + KeyCode::Up.into(), + KeyCode::Char(' ').into(), + KeyCode::Down.into(), + KeyCode::Char(' ').into(), + KeyCode::Enter.into(), ]); let ans: Vec<_> = requestty::prompt_one_with(order_select, &mut backend, &mut events) From 4e02352f95e5248307157ff6e33a700c449802b7 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 16:58:44 +0200 Subject: [PATCH 21/31] made integration tests better --- tests/order_select.rs | 46 +++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/tests/order_select.rs b/tests/order_select.rs index 9bde02c..cfd65e7 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -33,15 +33,20 @@ fn test_validate() { KeyCode::Enter.into(), ]); - let ans: Vec<_> = requestty::prompt_one_with(order_select, &mut backend, &mut events) + let indexes_a = choices(10) + .enumerate() + .map(|(i, _)| i) + .collect::>(); + + let indexes_b = requestty::prompt_one_with(order_select, &mut backend, &mut events) .unwrap() .try_into_list_items() .unwrap() .into_iter() - .map(|item| item.index) - .collect(); + .map(|a| a.index) + .collect::>(); - assert_eq!(ans, [3, 9]); + assert_eq!(indexes_a, indexes_b) } #[test] @@ -63,18 +68,22 @@ fn test_filter() { KeyCode::Enter.into(), ]); - let ans = requestty::prompt_one_with(order_select, &mut backend, &mut events) + let mut indexes_a = choices(10) + .enumerate() + .map(|(i, _)| i) + .collect::>(); + indexes_a.swap(0, 1); + indexes_a.rotate_left(1); + + let indexes_b = requestty::prompt_one_with(order_select, &mut backend, &mut events) .unwrap() .try_into_list_items() .unwrap() .into_iter() - .map(|a| a.text) + .map(|a| a.index) .collect::>(); - // compute the expected answer - let choices = choices(10).collect::>(); - - assert_eq!(ans, choices); + assert_eq!(indexes_a, indexes_b) } #[test] @@ -99,21 +108,24 @@ fn test_transform() { KeyCode::Char(' ').into(), KeyCode::Down.into(), KeyCode::Char(' ').into(), - KeyCode::Enter.into(), + KeyCode::Enter.into() ]); - let ans = requestty::prompt_one_with(order_select, &mut backend, &mut events) + let mut indexes_a = choices(10) + .enumerate() + .map(|(i, _)| i) + .collect::>(); + indexes_a.swap(0, 1); + + let indexes_b = requestty::prompt_one_with(order_select, &mut backend, &mut events) .unwrap() .try_into_list_items() .unwrap() .into_iter() - .map(|a| a.text) + .map(|a| a.index) .collect::>(); - // compute the expected answer - let choices = choices(10).collect::>(); - - assert_eq!(ans, choices); + assert_eq!(indexes_a, indexes_b) } #[test] From 620aee1872d3aa3e73e42708271e412ff51d6828 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 16:59:58 +0200 Subject: [PATCH 22/31] removed unused implementation on ListItem --- src/answer.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/answer.rs b/src/answer.rs index e084d18..bcb9cdf 100644 --- a/src/answer.rs +++ b/src/answer.rs @@ -247,12 +247,6 @@ impl> From<(usize, I)> for ListItem { } } -impl AsRef for ListItem { - fn as_ref(&self) -> &str { - &self.text - } -} - /// A representation of a [`Choice`] for a particular key. /// /// It will be returned by [`expand`]. From 2c30a53dda32f50d3d8dd38f49446fa848c647bf Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 17:02:48 +0200 Subject: [PATCH 23/31] Removed unnecessary documentation --- src/question/order_select/builder.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 464cd3a..499ef59 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -154,10 +154,7 @@ impl<'a> OrderSelectBuilder<'a> { /// /// The choices are [`String`]s and can be multiline. /// - /// See [`order_select`] for more information. - /// /// [`Choice`]: crate::question::Choice - /// [`order_select`]: crate::question::Question::order_select /// /// # Examples /// From 79825ad342a907289d7ff9a4a4536d6e2b276c61 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 17:05:11 +0200 Subject: [PATCH 24/31] Updated names to more concrete one in test_filter --- tests/order_select.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/order_select.rs b/tests/order_select.rs index cfd65e7..84020bb 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -52,11 +52,11 @@ fn test_validate() { #[test] fn test_filter() { let order_select = requestty::Question::order_select("name") - .filter(|mut checked, _| { - checked.rotate_left(1); - checked + .filter(|mut items, _| { + items.rotate_left(1); + items }) - .message("multi select") + .message("order select") .choices(choices(10)); let size = (50, 20).into(); From 6c177bc9971b712d305f9dc6352af10422e690b5 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 17:13:49 +0200 Subject: [PATCH 25/31] Updated item name to be more explicit --- src/question/order_select/builder.rs | 4 ++-- src/question/order_select/mod.rs | 11 ++++++----- tests/order_select.rs | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 499ef59..7170606 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -184,7 +184,7 @@ impl<'a> OrderSelectBuilder<'a> { .enumerate() .map(|(i, c)| OrderSelectItem { - index:len + i, + initial_index:len + i, text: Text::new(c.into()) } ), @@ -244,7 +244,7 @@ impl<'a> OrderSelectBuilder<'a> { /// //... /// .transform(|cheeses, previous_answers, backend| { /// for cheese in cheeses { - /// write!(backend, "({}) {}, ", cheese.index(), cheese.text())?; + /// write!(backend, "({}) {}, ", cheese.initial_index(), cheese.text())?; /// } /// Ok(()) /// }) diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 834b2cc..8506f86 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -260,14 +260,15 @@ impl Widget for OrderSelectPrompt<'_, '_> { /// It is different from [`ListItem`](crate::answer::ListItem) due to an implementation detail. #[derive(Debug, Clone, PartialEq)] pub struct OrderSelectItem { - index: usize, + initial_index: usize, text: Text, } impl OrderSelectItem { - /// The index of the choice - pub fn index(&self) -> usize { - self.index + /// The index of the choice in the initial list. + /// This is not the index rendered aside on the screen. + pub fn initial_index(&self) -> usize { + self.initial_index } /// The content of the choice -- it is what is displayed to the user @@ -300,6 +301,6 @@ impl Widget for OrderSelectItem { impl Into for OrderSelectItem { fn into(self) -> ListItem { - ListItem { index: self.index, text: self.text.text } + ListItem { index: self.initial_index, text: self.text.text } } } diff --git a/tests/order_select.rs b/tests/order_select.rs index 84020bb..eb375fa 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -92,7 +92,7 @@ fn test_transform() { .transform(|items, _, b| { b.set_fg(ui::style::Color::Magenta)?; for (i, item) in items.iter().enumerate() { - write!(b, "{}: {}", item.index(), item.text())?; + write!(b, "{}: {}", item.initial_index(), item.text())?; if i + 1 != items.len() { write!(b, ", ")?; } From b51b074dd4db54363aaec330f822c460d42b283e Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Tue, 30 Aug 2022 17:14:18 +0200 Subject: [PATCH 26/31] updated some docs --- src/question/order_select/builder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 7170606..4a00873 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -240,11 +240,11 @@ impl<'a> OrderSelectBuilder<'a> { /// ``` /// use requestty::Question; /// - /// let order_select = Question::order_select("cheese") + /// let order_select = Question::order_select("items") /// //... - /// .transform(|cheeses, previous_answers, backend| { - /// for cheese in cheeses { - /// write!(backend, "({}) {}, ", cheese.initial_index(), cheese.text())?; + /// .transform(|items, previous_answers, backend| { + /// for item in items { + /// write!(backend, "({}) {}, ", item.initial_index(), item.text())?; /// } /// Ok(()) /// }) From f3581d900febd39d906d0bc880cb637973d82888 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Wed, 31 Aug 2022 07:30:38 +0200 Subject: [PATCH 27/31] Fix the check example --- examples/order-select.rs | 4 ++-- src/question/order_select/builder.rs | 7 ++----- tests/order_select.rs | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/order-select.rs b/examples/order-select.rs index 591e818..cb756ec 100644 --- a/examples/order-select.rs +++ b/examples/order-select.rs @@ -10,9 +10,9 @@ fn main() { ]) .validate(|c, _| { if c[0].text() == "Make the bed" { - Err("You have to make the bed first".to_string()) - } else { Ok(()) + } else { + Err("You have to make the bed first".to_string()) } }) .build(); diff --git a/src/question/order_select/builder.rs b/src/question/order_select/builder.rs index 4a00873..9734c82 100644 --- a/src/question/order_select/builder.rs +++ b/src/question/order_select/builder.rs @@ -211,9 +211,6 @@ impl<'a> OrderSelectBuilder<'a> { } crate::impl_validate_builder! { - /// NOTE: The boolean [`slice`] contains a boolean value for each index even if it is a - /// separator. However it is guaranteed that all the separator indices will be false. - /// /// # Examples /// /// ``` @@ -223,9 +220,9 @@ impl<'a> OrderSelectBuilder<'a> { /// //... /// .validate(|tasks, previous_answers| { /// if tasks[0].text() == "Make the bed" { - /// Err("You have to make the bed first".to_string()) - /// } else { /// Ok(()) + /// } else { + /// Err("You have to make the bed first".to_string()) /// } /// }) /// //... diff --git a/tests/order_select.rs b/tests/order_select.rs index eb375fa..136f120 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -10,8 +10,8 @@ fn choices(len: usize) -> impl Iterator { fn test_validate() { let order_select = requestty::Question::order_select("name") .validate(|c, _| { - if c[0].text() == "1" { - Err("You have to make the bed first".to_string()) + if c[0].text() != "1" { + Err("Error".to_string()) } else { Ok(()) } From 378f506bbb2f74600d1fcd0a6009b3c8508f9807 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Thu, 1 Sep 2022 08:06:53 +0200 Subject: [PATCH 28/31] Updated index so they increment from 1 instead of 0 --- src/question/order_select/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index 8506f86..bdb2de4 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -79,7 +79,7 @@ impl widgets::List for OrderSelect<'_> { write!( b, "{:>width$}. ", - index, + index + 1, width = self.max_index_width as usize )?; From 684e71d06c28294f0ebc6162f725161407eab154 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Thu, 1 Sep 2022 13:00:14 +0200 Subject: [PATCH 29/31] moved conversion trait from OrderSelectItem to ListItem --- src/answer.rs | 6 ++++++ src/question/order_select/mod.rs | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/answer.rs b/src/answer.rs index bcb9cdf..bb171ad 100644 --- a/src/answer.rs +++ b/src/answer.rs @@ -247,6 +247,12 @@ impl> From<(usize, I)> for ListItem { } } +impl From for ListItem { + fn from(o: OrderSelectItem) -> Self { + Self { index: o.initial_index(), text: o.text().to_string() } + } +} + /// A representation of a [`Choice`] for a particular key. /// /// It will be returned by [`expand`]. diff --git a/src/question/order_select/mod.rs b/src/question/order_select/mod.rs index bdb2de4..47e3799 100644 --- a/src/question/order_select/mod.rs +++ b/src/question/order_select/mod.rs @@ -298,9 +298,3 @@ impl Widget for OrderSelectItem { self.text.handle_key(key) } } - -impl Into for OrderSelectItem { - fn into(self) -> ListItem { - ListItem { index: self.initial_index, text: self.text.text } - } -} From 7a413c30219553a49e9a274bc365d16af981cc04 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Thu, 1 Sep 2022 13:01:12 +0200 Subject: [PATCH 30/31] small name fix --- tests/order_select.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/order_select.rs b/tests/order_select.rs index 136f120..dc48703 100644 --- a/tests/order_select.rs +++ b/tests/order_select.rs @@ -99,7 +99,7 @@ fn test_transform() { } b.set_fg(ui::style::Color::Reset) }) - .message("multi select") + .message("order select") .choices(choices(10)); let size = (50, 20).into(); From 09c9a0b7fc1614735b8a6b42aca8364cac6fdfb3 Mon Sep 17 00:00:00 2001 From: NovaliX-Dev Date: Thu, 1 Sep 2022 13:01:29 +0200 Subject: [PATCH 31/31] added snapshots --- ..._order_select__tests__basic__render-2.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-3.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-4.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-5.snap | 26 +++++++++++++++++++ ...n__order_select__tests__basic__render.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-2.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-3.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-4.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-5.snap | 26 +++++++++++++++++++ ...der_select__tests__pagination__render.snap | 26 +++++++++++++++++++ .../order_select__helpers__filter-2.snap | 26 +++++++++++++++++++ .../order_select__helpers__filter-3.snap | 26 +++++++++++++++++++ .../order_select__helpers__filter-4.snap | 26 +++++++++++++++++++ .../order_select__helpers__filter-5.snap | 26 +++++++++++++++++++ .../order_select__helpers__filter.snap | 26 +++++++++++++++++++ .../order_select__helpers__on_esc-2.snap | 26 +++++++++++++++++++ .../order_select__helpers__on_esc-3.snap | 26 +++++++++++++++++++ .../order_select__helpers__on_esc.snap | 26 +++++++++++++++++++ .../order_select__helpers__transform-2.snap | 26 +++++++++++++++++++ .../order_select__helpers__transform-3.snap | 26 +++++++++++++++++++ .../order_select__helpers__transform-4.snap | 26 +++++++++++++++++++ .../order_select__helpers__transform-5.snap | 26 +++++++++++++++++++ .../order_select__helpers__transform.snap | 26 +++++++++++++++++++ .../order_select__helpers__validate-2.snap | 26 +++++++++++++++++++ .../order_select__helpers__validate-3.snap | 26 +++++++++++++++++++ .../order_select__helpers__validate-4.snap | 26 +++++++++++++++++++ .../order_select__helpers__validate-5.snap | 26 +++++++++++++++++++ .../order_select__helpers__validate.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-2.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-3.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-4.snap | 26 +++++++++++++++++++ ..._order_select__tests__basic__render-5.snap | 26 +++++++++++++++++++ ...n__order_select__tests__basic__render.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-2.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-3.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-4.snap | 26 +++++++++++++++++++ ...r_select__tests__pagination__render-5.snap | 26 +++++++++++++++++++ ...der_select__tests__pagination__render.snap | 26 +++++++++++++++++++ 38 files changed, 988 insertions(+) create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap create mode 100644 crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap create mode 100644 termion-snapshots/order_select__helpers__filter-2.snap create mode 100644 termion-snapshots/order_select__helpers__filter-3.snap create mode 100644 termion-snapshots/order_select__helpers__filter-4.snap create mode 100644 termion-snapshots/order_select__helpers__filter-5.snap create mode 100644 termion-snapshots/order_select__helpers__filter.snap create mode 100644 termion-snapshots/order_select__helpers__on_esc-2.snap create mode 100644 termion-snapshots/order_select__helpers__on_esc-3.snap create mode 100644 termion-snapshots/order_select__helpers__on_esc.snap create mode 100644 termion-snapshots/order_select__helpers__transform-2.snap create mode 100644 termion-snapshots/order_select__helpers__transform-3.snap create mode 100644 termion-snapshots/order_select__helpers__transform-4.snap create mode 100644 termion-snapshots/order_select__helpers__transform-5.snap create mode 100644 termion-snapshots/order_select__helpers__transform.snap create mode 100644 termion-snapshots/order_select__helpers__validate-2.snap create mode 100644 termion-snapshots/order_select__helpers__validate-3.snap create mode 100644 termion-snapshots/order_select__helpers__validate-4.snap create mode 100644 termion-snapshots/order_select__helpers__validate-5.snap create mode 100644 termion-snapshots/order_select__helpers__validate.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__basic__render-2.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__basic__render-3.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__basic__render-4.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__basic__render-5.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__basic__render.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__pagination__render-2.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__pagination__render-3.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__pagination__render-4.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__pagination__render-5.snap create mode 100644 termion-snapshots/requestty__question__order_select__tests__pagination__render.snap diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap new file mode 100644 index 0000000..c65a2e0 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-2.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap new file mode 100644 index 0000000..b4d2717 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-3.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│❯ 10. 0 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap new file mode 100644 index 0000000..c65a2e0 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-4.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap new file mode 100644 index 0000000..321158e --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render-5.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap b/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap new file mode 100644 index 0000000..321158e --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__basic__render.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap new file mode 100644 index 0000000..651430f --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-2.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│ 13. 12 │ +│ 14. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap new file mode 100644 index 0000000..3be7a6e --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-3.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 19 │ +│❯ 20. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│ 12. 12 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap new file mode 100644 index 0000000..4609cac --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-4.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 18 │ +│ 20. 19 │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap new file mode 100644 index 0000000..a9f880f --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render-5.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 18 │ +│ 20. 19 │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap new file mode 100644 index 0000000..67a87f2 --- /dev/null +++ b/crossterm-snapshots/requestty__question__order_select__tests__pagination__render.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│ 13. 12 │ +│ 14. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__filter-2.snap b/termion-snapshots/order_select__helpers__filter-2.snap new file mode 100644 index 0000000..a8ef5f0 --- /dev/null +++ b/termion-snapshots/order_select__helpers__filter-2.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__filter-3.snap b/termion-snapshots/order_select__helpers__filter-3.snap new file mode 100644 index 0000000..b3cbb30 --- /dev/null +++ b/termion-snapshots/order_select__helpers__filter-3.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__filter-4.snap b/termion-snapshots/order_select__helpers__filter-4.snap new file mode 100644 index 0000000..4fbd716 --- /dev/null +++ b/termion-snapshots/order_select__helpers__filter-4.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__filter-5.snap b/termion-snapshots/order_select__helpers__filter-5.snap new file mode 100644 index 0000000..f4f05e0 --- /dev/null +++ b/termion-snapshots/order_select__helpers__filter-5.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│✔ order select · 0, 2, 3, 4, 5, 6, 7, 8, 9, 1 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__filter.snap b/termion-snapshots/order_select__helpers__filter.snap new file mode 100644 index 0000000..446f03d --- /dev/null +++ b/termion-snapshots/order_select__helpers__filter.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__on_esc-2.snap b/termion-snapshots/order_select__helpers__on_esc-2.snap new file mode 100644 index 0000000..eb5a4b0 --- /dev/null +++ b/termion-snapshots/order_select__helpers__on_esc-2.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? message (Press to take and place an opti│ +│on) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__on_esc-3.snap b/termion-snapshots/order_select__helpers__on_esc-3.snap new file mode 100644 index 0000000..bc8b2d1 --- /dev/null +++ b/termion-snapshots/order_select__helpers__on_esc-3.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│✖ message · Skipped │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__on_esc.snap b/termion-snapshots/order_select__helpers__on_esc.snap new file mode 100644 index 0000000..eb5a4b0 --- /dev/null +++ b/termion-snapshots/order_select__helpers__on_esc.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? message (Press to take and place an opti│ +│on) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__transform-2.snap b/termion-snapshots/order_select__helpers__transform-2.snap new file mode 100644 index 0000000..e16576a --- /dev/null +++ b/termion-snapshots/order_select__helpers__transform-2.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? multi select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__transform-3.snap b/termion-snapshots/order_select__helpers__transform-3.snap new file mode 100644 index 0000000..22b1bb3 --- /dev/null +++ b/termion-snapshots/order_select__helpers__transform-3.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? multi select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__transform-4.snap b/termion-snapshots/order_select__helpers__transform-4.snap new file mode 100644 index 0000000..99d7b65 --- /dev/null +++ b/termion-snapshots/order_select__helpers__transform-4.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? multi select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__transform-5.snap b/termion-snapshots/order_select__helpers__transform-5.snap new file mode 100644 index 0000000..314eee8 --- /dev/null +++ b/termion-snapshots/order_select__helpers__transform-5.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│✔ multi select · 1: 1, 0: 0, 2: 2, 3: 3, 4: 4, 5: │ +│5, 6: 6, 7: 7, 8: 8, 9: 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__transform.snap b/termion-snapshots/order_select__helpers__transform.snap new file mode 100644 index 0000000..001500b --- /dev/null +++ b/termion-snapshots/order_select__helpers__transform.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? multi select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__validate-2.snap b/termion-snapshots/order_select__helpers__validate-2.snap new file mode 100644 index 0000000..a8ef5f0 --- /dev/null +++ b/termion-snapshots/order_select__helpers__validate-2.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__validate-3.snap b/termion-snapshots/order_select__helpers__validate-3.snap new file mode 100644 index 0000000..b3cbb30 --- /dev/null +++ b/termion-snapshots/order_select__helpers__validate-3.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__validate-4.snap b/termion-snapshots/order_select__helpers__validate-4.snap new file mode 100644 index 0000000..4fbd716 --- /dev/null +++ b/termion-snapshots/order_select__helpers__validate-4.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│❯ 2. 0 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__validate-5.snap b/termion-snapshots/order_select__helpers__validate-5.snap new file mode 100644 index 0000000..c0326ee --- /dev/null +++ b/termion-snapshots/order_select__helpers__validate-5.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│✔ order select · 1, 0, 2, 3, 4, 5, 6, 7, 8, 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/order_select__helpers__validate.snap b/termion-snapshots/order_select__helpers__validate.snap new file mode 100644 index 0000000..446f03d --- /dev/null +++ b/termion-snapshots/order_select__helpers__validate.snap @@ -0,0 +1,26 @@ +--- +source: tests/helpers/mod.rs +expression: self.backend +--- +┌──────────────────────────────────────────────────┐ +│? order select (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__basic__render-2.snap b/termion-snapshots/requestty__question__order_select__tests__basic__render-2.snap new file mode 100644 index 0000000..c65a2e0 --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__basic__render-2.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__basic__render-3.snap b/termion-snapshots/requestty__question__order_select__tests__basic__render-3.snap new file mode 100644 index 0000000..b4d2717 --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__basic__render-3.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│❯ 10. 0 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__basic__render-4.snap b/termion-snapshots/requestty__question__order_select__tests__basic__render-4.snap new file mode 100644 index 0000000..c65a2e0 --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__basic__render-4.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__basic__render-5.snap b/termion-snapshots/requestty__question__order_select__tests__basic__render-5.snap new file mode 100644 index 0000000..321158e --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__basic__render-5.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__basic__render.snap b/termion-snapshots/requestty__question__order_select__tests__basic__render.snap new file mode 100644 index 0000000..321158e --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__basic__render.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│  │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__pagination__render-2.snap b/termion-snapshots/requestty__question__order_select__tests__pagination__render-2.snap new file mode 100644 index 0000000..651430f --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__pagination__render-2.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│ 13. 12 │ +│ 14. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__pagination__render-3.snap b/termion-snapshots/requestty__question__order_select__tests__pagination__render-3.snap new file mode 100644 index 0000000..3be7a6e --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__pagination__render-3.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 19 │ +│❯ 20. 0 │ +│ 1. 1 │ +│ 2. 2 │ +│ 3. 3 │ +│ 4. 4 │ +│ 5. 5 │ +│ 6. 6 │ +│ 7. 7 │ +│ 8. 8 │ +│ 9. 9 │ +│ 10. 10 │ +│ 11. 11 │ +│ 12. 12 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__pagination__render-4.snap b/termion-snapshots/requestty__question__order_select__tests__pagination__render-4.snap new file mode 100644 index 0000000..4609cac --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__pagination__render-4.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 18 │ +│ 20. 19 │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__pagination__render-5.snap b/termion-snapshots/requestty__question__order_select__tests__pagination__render-5.snap new file mode 100644 index 0000000..a9f880f --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__pagination__render-5.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│ 19. 18 │ +│ 20. 19 │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘ diff --git a/termion-snapshots/requestty__question__order_select__tests__pagination__render.snap b/termion-snapshots/requestty__question__order_select__tests__pagination__render.snap new file mode 100644 index 0000000..67a87f2 --- /dev/null +++ b/termion-snapshots/requestty__question__order_select__tests__pagination__render.snap @@ -0,0 +1,26 @@ +--- +source: src/question/order_select/tests.rs +expression: backend +--- +┌──────────────────────────────────────────────────┐ +│ ? message (Press to take and place an│ +│ option) │ +│❯ 1. 0 │ +│ 2. 1 │ +│ 3. 2 │ +│ 4. 3 │ +│ 5. 4 │ +│ 6. 5 │ +│ 7. 6 │ +│ 8. 7 │ +│ 9. 8 │ +│ 10. 9 │ +│ 11. 10 │ +│ 12. 11 │ +│ 13. 12 │ +│ 14. 13 │ +│(Move up and down to reveal more choices) │ +│  │ +│ │ +│ │ +└──────────────────────────────────────────────────┘