From 4f6e6271844f02c11a4ea635fa5df6eead720055 Mon Sep 17 00:00:00 2001 From: tbergerd <139167029+tbergerd@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:08:50 +0200 Subject: [PATCH 1/5] Add 'interact_text_opt' and 'interact_text_on_opt' for 'Input' prompts --- src/prompts/input.rs | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/prompts/input.rs b/src/prompts/input.rs index 510aecf..f6d6c11 100644 --- a/src/prompts/input.rs +++ b/src/prompts/input.rs @@ -289,12 +289,38 @@ where /// while [`interact`](Self::interact) allows virtually any character to be used e.g arrow keys. /// /// The dialog is rendered on stderr. + /// This unlike [`interact_text_opt`](Self::interact_text_opt) does not allow to quit with 'Esc' pub fn interact_text(self) -> Result { self.interact_text_on(&Term::stderr()) } + /// Enables the user to enter a printable ascii sequence and returns the result. + /// + /// Its difference from [`interact_opt`](Self::interact_opt) is that it only allows ascii characters for string, + /// while [`interact_opt`](Self::interact_opt) allows virtually any character to be used e.g arrow keys. + /// + /// The dialog is rendered on stderr. + /// Result contains `Some(T)` if user hit 'Enter' or `None` if user cancelled with 'Esc' + #[inline] + pub fn interact_text_opt(self) -> Result> { + self.interact_text_on_opt(&Term::stderr()) + } + /// Like [`interact_text`](Self::interact_text) but allows a specific terminal to be set. - pub fn interact_text_on(mut self, term: &Term) -> Result { + #[inline] + pub fn interact_text_on(self, term: &Term) -> Result { + Ok(self + ._interact_text_on(term, false)? + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case"))?) + } + + /// Like [`interact_text_opt`](Self::interact_text_opt) but allows a specific terminal to be set. + #[inline] + pub fn interact_text_on_opt(self, term: &Term) -> Result> { + self._interact_text_on(term, true) + } + + fn _interact_text_on(mut self, term: &Term, allow_quit: bool) -> Result> { if !term.is_term() { return Err(io::Error::new(io::ErrorKind::NotConnected, "not a terminal").into()); } @@ -315,7 +341,7 @@ where // Read input by keystroke so that we can suppress ascii control characters if !term.features().is_attended() { - return Ok("".to_owned().parse::().unwrap()); + return Ok(Some("".to_owned().parse::().unwrap())); } let mut chars: Vec = Vec::new(); @@ -332,6 +358,12 @@ where loop { match term.read_key()? { + Key::Escape if allow_quit => { + render.clear()?; + term.flush()?; + term.show_cursor()?; + return Ok(None); + } Key::Backspace if position > 0 => { position -= 1; chars.remove(position); @@ -591,7 +623,7 @@ where render.input_prompt_selection(&self.prompt, &default.to_string())?; } term.flush()?; - return Ok(default.clone()); + return Ok(Some(default.clone())); } else if !self.permit_empty { continue; } @@ -620,7 +652,7 @@ where } term.flush()?; - return Ok(value); + return Ok(Some(value)); } Err(err) => { render.error(&err.to_string())?; From 05f6a3b127d16135e67d535c3eef6d2b1c367d32 Mon Sep 17 00:00:00 2001 From: tbergerd <139167029+tbergerd@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:12:21 +0200 Subject: [PATCH 2/5] Remove dead code and unnecessary 'Debug' trait bound on Input's 'interact_text*' methods --- src/prompts/input.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/prompts/input.rs b/src/prompts/input.rs index f6d6c11..12ea6ef 100644 --- a/src/prompts/input.rs +++ b/src/prompts/input.rs @@ -1,6 +1,5 @@ use std::{ cmp::Ordering, - fmt::Debug, io, iter, str::FromStr, sync::{Arc, Mutex}, @@ -281,7 +280,7 @@ where impl Input<'_, T> where T: Clone + ToString + FromStr, - ::Err: Debug + ToString, + ::Err: ToString, { /// Enables the user to enter a printable ascii sequence and returns the result. /// @@ -339,11 +338,6 @@ where }, )?; - // Read input by keystroke so that we can suppress ascii control characters - if !term.features().is_attended() { - return Ok(Some("".to_owned().parse::().unwrap())); - } - let mut chars: Vec = Vec::new(); let mut position = 0; #[cfg(feature = "history")] @@ -661,13 +655,7 @@ where } } } -} -impl Input<'_, T> -where - T: Clone + ToString + FromStr, - ::Err: ToString, -{ /// Enables user interaction and returns the result. /// /// Allows any characters as input, including e.g arrow keys. From 08630fc1d806960958f2095f1783c2a68e8a78fa Mon Sep 17 00:00:00 2001 From: tbergerd <139167029+tbergerd@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:20:10 +0200 Subject: [PATCH 3/5] Mark Input::interact_text as inline as well --- src/prompts/input.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prompts/input.rs b/src/prompts/input.rs index 12ea6ef..1e73eb0 100644 --- a/src/prompts/input.rs +++ b/src/prompts/input.rs @@ -289,6 +289,7 @@ where /// /// The dialog is rendered on stderr. /// This unlike [`interact_text_opt`](Self::interact_text_opt) does not allow to quit with 'Esc' + #[inline] pub fn interact_text(self) -> Result { self.interact_text_on(&Term::stderr()) } From 31549353e1ed3b5d951fb60d6287995d10feb8f1 Mon Sep 17 00:00:00 2001 From: tbergerd <139167029+tbergerd@users.noreply.github.com> Date: Sun, 10 Sep 2023 21:51:59 +0200 Subject: [PATCH 4/5] Fix small inaccuracies in documentation --- src/prompts/input.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/prompts/input.rs b/src/prompts/input.rs index 1e73eb0..478485d 100644 --- a/src/prompts/input.rs +++ b/src/prompts/input.rs @@ -288,7 +288,7 @@ where /// while [`interact`](Self::interact) allows virtually any character to be used e.g arrow keys. /// /// The dialog is rendered on stderr. - /// This unlike [`interact_text_opt`](Self::interact_text_opt) does not allow to quit with 'Esc' + /// This unlike [`interact_text_opt`](Self::interact_text_opt) does not allow to quit with 'Esc'. #[inline] pub fn interact_text(self) -> Result { self.interact_text_on(&Term::stderr()) @@ -296,11 +296,11 @@ where /// Enables the user to enter a printable ascii sequence and returns the result. /// - /// Its difference from [`interact_opt`](Self::interact_opt) is that it only allows ascii characters for string, - /// while [`interact_opt`](Self::interact_opt) allows virtually any character to be used e.g arrow keys. - /// + /// Unlike [`interact`](Self::interact) it only allows ascii characters for string, + /// and can be cancelled with 'Esc'. + /// /// The dialog is rendered on stderr. - /// Result contains `Some(T)` if user hit 'Enter' or `None` if user cancelled with 'Esc' + /// Result contains `Some(T)` if user hit 'Enter' or `None` if user cancelled with 'Esc'. #[inline] pub fn interact_text_opt(self) -> Result> { self.interact_text_on_opt(&Term::stderr()) @@ -663,7 +663,7 @@ where /// Some of the keys might have undesired behavior. /// For more limited version, see [`interact_text`](Self::interact_text). /// - /// If the user confirms the result is `true`, `false` otherwise. + /// Returns the parsed value once the user validates their input with 'Enter'. /// The dialog is rendered on stderr. pub fn interact(self) -> Result { self.interact_on(&Term::stderr()) From b8f842a7da35493dde7a8156a9561759584a5195 Mon Sep 17 00:00:00 2001 From: tbergerd <139167029+tbergerd@users.noreply.github.com> Date: Mon, 11 Sep 2023 14:18:31 +0200 Subject: [PATCH 5/5] Correctly clear 'Input' prompt on cancellation --- src/prompts/input.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prompts/input.rs b/src/prompts/input.rs index 478485d..223cf65 100644 --- a/src/prompts/input.rs +++ b/src/prompts/input.rs @@ -354,6 +354,7 @@ where loop { match term.read_key()? { Key::Escape if allow_quit => { + term.clear_line()?; render.clear()?; term.flush()?; term.show_cursor()?;