In case of an unexpected events, I would love to display a warning to the user, which simply needs to be "confirmed" for the programm to move on.
The workaround I use is a selection with "OK" as single option, but this is a bit hacky.
I kindly request to add alert as a new interaction option to dialoguer. One can use the patch I attached, but I probably messed the return types up ...
diff --git a/examples/alert.rs b/examples/alert.rs
new file mode 100644
index 0000000..b8a9188
--- /dev/null
+++ b/examples/alert.rs
@@ -0,0 +1,16 @@
+use dialoguer::{theme::ColorfulTheme, Alert};
+
+fn main() {
+ let _ = Alert::with_theme(&ColorfulTheme::default())
+ .with_prompt("Something went wrong! Press enter to continue.")
+ .interact();
+
+ let _ = Alert::with_theme(&ColorfulTheme::default())
+ .with_alert_text("This is an alert, press enter to continue.")
+ .interact();
+
+ let _ = Alert::with_theme(&ColorfulTheme::default())
+ .with_alert_text("Strange things happened: <spooky error message>.")
+ .with_prompt("Press enter to continue.")
+ .interact();
+}
diff --git a/src/lib.rs b/src/lib.rs
index 46bf30c..a76967d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -48,7 +48,8 @@ pub use prompts::fuzzy_select::FuzzySelect;
#[cfg(feature = "password")]
pub use prompts::password::Password;
pub use prompts::{
- confirm::Confirm, input::Input, multi_select::MultiSelect, select::Select, sort::Sort,
+ alert::Alert, confirm::Confirm, input::Input, multi_select::MultiSelect, select::Select,
+ sort::Sort,
};
#[cfg(feature = "completion")]
diff --git a/src/prompts/alert.rs b/src/prompts/alert.rs
new file mode 100644
index 0000000..ed45b98
--- /dev/null
+++ b/src/prompts/alert.rs
@@ -0,0 +1,148 @@
+use std::io;
+
+use console::{Key, Term};
+
+use crate::{
+ theme::{render::TermThemeRenderer, SimpleTheme, Theme},
+ Result,
+};
+
+/// Renders an alert prompt.
+///
+/// ## Example
+///
+/// ```rust,no_run
+/// use dialoguer::{theme::ColorfulTheme, Alert};
+///
+/// fn main() {
+/// let _ = Alert::with_theme(&ColorfulTheme::default())
+/// .with_prompt("Something went wrong! Press enter to continue.")
+/// .interact();
+///
+/// let _ = Alert::with_theme(&ColorfulTheme::default())
+/// .with_alert_text("This is an alert, press enter to continue.")
+/// .interact();
+///
+/// let _ = Alert::with_theme(&ColorfulTheme::default())
+/// .with_alert_text("Strange things happened: <spooky error message>.")
+/// .with_prompt("Press enter to continue.")
+/// .interact();
+/// }
+/// ```
+#[derive(Clone)]
+pub struct Alert<'a> {
+ alert_text: String,
+ prompt: String,
+ theme: &'a dyn Theme,
+}
+
+impl Default for Alert<'static> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Alert<'static> {
+ /// Creates a alert prompt with default theme.
+ pub fn new() -> Self {
+ Self::with_theme(&SimpleTheme)
+ }
+}
+
+impl Alert<'_> {
+ /// Sets the alert content message.
+ pub fn with_alert_text<S: Into<String>>(mut self, alert_text: S) -> Self {
+ self.alert_text = alert_text.into();
+ self
+ }
+
+ /// Sets the alert prompt.
+ pub fn with_prompt<S: Into<String>>(mut self, prompt: S) -> Self {
+ self.prompt = prompt.into();
+ self
+ }
+
+ /// Enables user interaction.
+ ///
+ /// The dialog is rendered on stderr.
+ #[inline]
+ pub fn interact(self) -> Result<Option<()>> {
+ self.interact_on(&Term::stderr())
+ }
+
+ /// Like [`interact`](Self::interact) but allows a specific terminal to be set.
+ #[inline]
+ pub fn interact_on(self, term: &Term) -> Result<Option<()>> {
+ Ok(Some(self._interact_on(term)?.ok_or_else(|| {
+ io::Error::new(io::ErrorKind::Other, "Quit not allowed in this case")
+ })?))
+ }
+
+ fn _interact_on(self, term: &Term) -> Result<Option<()>> {
+ if !term.is_term() {
+ return Err(io::Error::new(io::ErrorKind::NotConnected, "not a terminal").into());
+ }
+
+ let mut render = TermThemeRenderer::new(term, self.theme);
+
+ render.alert_prompt(&self.alert_text, &self.prompt)?;
+
+ term.hide_cursor()?;
+ term.flush()?;
+
+ // Default behavior: wait for user to hit the Enter key.
+ loop {
+ let input = term.read_key()?;
+ match input {
+ Key::Enter => (),
+ _ => {
+ continue;
+ }
+ };
+
+ break;
+ }
+
+ term.write_line("")?;
+ term.show_cursor()?;
+ term.flush()?;
+
+ Ok(Some(()))
+ }
+}
+
+impl<'a> Alert<'a> {
+ /// Creates an alert prompt with a specific theme.
+ ///
+ /// ## Example
+ ///
+ /// ```rust,no_run
+ /// use dialoguer::{theme::ColorfulTheme, Alert};
+ ///
+ /// fn main() {
+ /// let alert = Alert::with_theme(&ColorfulTheme::default())
+ /// .interact();
+ /// }
+ /// ```
+ pub fn with_theme(theme: &'a dyn Theme) -> Self {
+ Self {
+ alert_text: "".into(),
+ prompt: "".into(),
+ theme,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_clone() {
+ let alert = Alert::new()
+ .with_alert_text("FYI: ground gets wet if it rains.")
+ .with_prompt("Press enter continue");
+
+ let _ = alert.clone();
+ }
+}
diff --git a/src/prompts/mod.rs b/src/prompts/mod.rs
index 1c13185..2842ce5 100644
--- a/src/prompts/mod.rs
+++ b/src/prompts/mod.rs
@@ -1,5 +1,6 @@
#![allow(clippy::needless_doctest_main)]
+pub mod alert;
pub mod confirm;
pub mod input;
pub mod multi_select;
diff --git a/src/theme/mod.rs b/src/theme/mod.rs
index d22001c..c1f462f 100644
--- a/src/theme/mod.rs
+++ b/src/theme/mod.rs
@@ -27,6 +27,25 @@ pub trait Theme {
write!(f, "error: {}", err)
}
+ /// Formats an alert prompt.
+ fn format_alert_prompt(
+ &self,
+ f: &mut dyn fmt::Write,
+ alert_text: &str,
+ prompt: &str,
+ ) -> fmt::Result {
+ if !alert_text.is_empty() {
+ write!(f, "⚠ {}", &alert_text)?;
+ }
+ if !prompt.is_empty() {
+ if !alert_text.is_empty() {
+ writeln!(f, "")?;
+ }
+ write!(f, "{}", &prompt)?;
+ }
+ Ok(())
+ }
+
/// Formats a confirm prompt.
fn format_confirm_prompt(
&self,
diff --git a/src/theme/render.rs b/src/theme/render.rs
index e6f3add..06d076a 100644
--- a/src/theme/render.rs
+++ b/src/theme/render.rs
@@ -87,6 +87,12 @@ impl<'a> TermThemeRenderer<'a> {
self.write_formatted_line(|this, buf| this.theme.format_error(buf, err))
}
+ pub fn alert_prompt(&mut self, alert_text: &str, prompt: &str) -> Result<usize> {
+ self.write_formatted_str(|this, buf| {
+ this.theme.format_alert_prompt(buf, alert_text, prompt)
+ })
+ }
+
pub fn confirm_prompt(&mut self, prompt: &str, default: Option<bool>) -> Result<usize> {
self.write_formatted_str(|this, buf| this.theme.format_confirm_prompt(buf, prompt, default))
}
In case of an unexpected events, I would love to display a warning to the user, which simply needs to be "confirmed" for the programm to move on.
The workaround I use is a selection with "OK" as single option, but this is a bit hacky.
I kindly request to add alert as a new interaction option to dialoguer. One can use the patch I attached, but I probably messed the return types up ...