aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fancyfmt.rs55
-rw-r--r--src/install.rs13
-rw-r--r--src/main.rs9
-rw-r--r--src/uiutil.rs20
4 files changed, 74 insertions, 23 deletions
diff --git a/src/fancyfmt.rs b/src/fancyfmt.rs
new file mode 100644
index 0000000..6c631b3
--- /dev/null
+++ b/src/fancyfmt.rs
@@ -0,0 +1,55 @@
+//! This module provides some methods for "fancily" formatting data.
+//!
+//! This mainly exists so that we can have a version of [`std::fmt::Display`] that can use the
+//! colors provided by [`termcolor`].
+use std::io::Write;
+
+use anyhow::Result;
+use modderbaas::{contentdb::ContentMeta, World};
+use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
+
+/// A trait for objects to output them to a (possibly) colored stream.
+pub trait ColoredDisplay {
+ /// Output the object to the colored stream.
+ fn fmt(&self, output: &mut StandardStream) -> Result<()>;
+}
+
+impl<T: ColoredDisplay> ColoredDisplay for &T {
+ fn fmt(&self, output: &mut StandardStream) -> Result<()> {
+ (*self).fmt(output)
+ }
+}
+
+impl ColoredDisplay for &str {
+ fn fmt(&self, output: &mut StandardStream) -> Result<()> {
+ write!(output, "{}", *self)?;
+ Ok(())
+ }
+}
+
+impl ColoredDisplay for String {
+ fn fmt(&self, output: &mut StandardStream) -> Result<()> {
+ (self as &str).fmt(output)
+ }
+}
+
+impl ColoredDisplay for World {
+ fn fmt(&self, output: &mut StandardStream) -> Result<()> {
+ write!(output, "{}", self)?;
+ Ok(())
+ }
+}
+
+impl ColoredDisplay for ContentMeta {
+ fn fmt(&self, output: &mut StandardStream) -> Result<()> {
+ output.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?;
+ write!(output, "{}", self.title)?;
+ output.reset()?;
+ write!(output, " by ")?;
+ output.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)))?;
+ write!(output, "{}", self.author)?;
+ output.reset()?;
+ write!(output, " - {}", self.short_description)?;
+ Ok(())
+ }
+}
diff --git a/src/install.rs b/src/install.rs
index 56754d3..e34ffc3 100644
--- a/src/install.rs
+++ b/src/install.rs
@@ -69,21 +69,12 @@ impl<'o, 'p> Installer for InteractiveInstaller<'o, 'p> {
} else if candidates.len() == 1 {
Ok(Source::Http(candidates.into_iter().next().unwrap().url))
} else {
- let items = candidates
- .into_iter()
- .map(|c| {
- (
- format!("{} by {} - {}", c.title, c.author, c.short_description),
- c,
- )
- })
- .collect::<Vec<_>>();
writeln!(
&mut self.output,
"{} candidates found, please select one:",
- items.len()
+ candidates.len()
)?;
- let candidate = user_choice(&items, self.output)?;
+ let candidate = user_choice(&candidates, self.output)?;
Ok(Source::Http(candidate.url.clone()))
}
}
diff --git a/src/main.rs b/src/main.rs
index 5390479..20e8653 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,6 +8,8 @@ use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use modderbaas::{baas::Baas, MineMod, Snapshot, World};
+mod fancyfmt;
+
mod uiutil;
use uiutil::{ask_continue, user_choice};
@@ -137,8 +139,11 @@ fn select_world(
}
// Here, we cannot do an automatic selection, so ask the user:
- let mut worlds = worlds.iter().collect::<Vec<_>>();
- worlds.sort_by_key(|i| i.0);
+ let worlds = worlds
+ .iter()
+ .sorted_by_key(|i| i.0)
+ .map(|i| i.1)
+ .collect::<Vec<_>>();
writeln!(
output,
"The following worlds were found, please select one:"
diff --git a/src/uiutil.rs b/src/uiutil.rs
index 188e20c..0cc88a9 100644
--- a/src/uiutil.rs
+++ b/src/uiutil.rs
@@ -1,22 +1,22 @@
//! Utility functions for user interaction.
-use std::{
- fmt::Display,
- io::{self, Write},
-};
+use std::io::{self, Write};
use anyhow::{bail, Result};
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
+use super::fancyfmt::ColoredDisplay;
+
/// Presents the user with a choice of items and awaits a selection.
-pub fn user_choice<'i, L: Display, I>(
- items: &'i [(L, I)],
+pub fn user_choice<'i, I: ColoredDisplay>(
+ items: &'i [I],
output: &mut StandardStream,
) -> Result<&'i I> {
- for (i, (label, _)) in items.iter().enumerate() {
+ for (i, item) in items.iter().enumerate() {
output.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?;
- write!(output, "[{}]", i)?;
+ write!(output, "[{}] ", i)?;
output.reset()?;
- writeln!(output, " {}", label)?;
+ item.fmt(output)?;
+ writeln!(output)?;
}
let stdin = io::stdin();
@@ -27,7 +27,7 @@ pub fn user_choice<'i, L: Display, I>(
stdin.read_line(&mut buffer)?;
if let Ok(number) = buffer.trim().parse::<usize>() {
if number < items.len() {
- return Ok(&items[number].1);
+ return Ok(&items[number]);
}
}
}