Working on UI

This commit is contained in:
Thomas Forgione 2021-03-06 16:01:28 +01:00
parent 89838ae594
commit 1d3c6c83e4
2 changed files with 74 additions and 47 deletions

View File

@ -7,3 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dialoguer = "0.7.1"

View File

@ -4,6 +4,8 @@ use std::fs::{metadata, symlink_metadata};
use std::path::PathBuf;
use std::process::Command;
use dialoguer::{theme::SimpleTheme, Confirm, MultiSelect};
macro_rules! unwrap_or_false {
($expr: expr) => {
match $expr {
@ -171,22 +173,41 @@ impl Component {
Component::Git => &[Component::Sudo],
Component::Zsh => &[Component::Sudo],
Component::Dotfiles => &[Component::Git],
Component::Zshrc => &[Component::Zsh, Component::Dotfiles],
Component::Zshrc => &[Component::Zsh, Component::Dotfiles, Component::OhMyZsh],
Component::OhMyZsh => &[Component::Git],
}
}
/// Returns the str representation of the command.
pub fn to_str(self) -> &'static str {
match self {
Component::Sudo => "sudo",
Component::Git => "git",
Component::Zsh => "zsh",
Component::Dotfiles => "dotfiles",
Component::Zshrc => "zshrc",
Component::OhMyZsh => "ohmyzsh",
}
}
}
impl fmt::Display for Component {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Component::Sudo => write!(fmt, "sudo"),
Component::Git => write!(fmt, "git"),
Component::Zsh => write!(fmt, "zsh"),
Component::Dotfiles => write!(fmt, "dotfiles"),
Component::Zshrc => write!(fmt, "zshrc"),
Component::OhMyZsh => write!(fmt, "ohmyzsh"),
}
write!(
fmt,
"{} (requires {}{})",
self.to_str(),
self.dependencies()
.into_iter()
.map(|x| x.to_str())
.collect::<Vec<_>>()
.join(", "),
if self.is_installed() {
", already installed"
} else {
""
}
)
}
}
@ -194,23 +215,52 @@ impl fmt::Display for Component {
pub struct Installer {
/// All the components to install, and whether the users want to install them.
components: Vec<(Component, bool)>,
/// Where the users cursor is.
cursor: usize,
}
impl Installer {
/// Creates a new installer.
pub fn new() -> Installer {
Installer {
components: Component::all().into_iter().map(|x| (x, true)).collect(),
cursor: 0,
components: Component::all().into_iter().map(|x| (x, false)).collect(),
}
}
/// Prints the installer.
pub fn print(&self) {
print!("{}", self);
/// Asks interactively to the user which components to install.
pub fn interact(&mut self) -> bool {
let multiselected = self
.components
.iter()
.map(|(component, _)| format!("{}", component))
.collect::<Vec<_>>();
let defaults = self
.components
.iter()
.map(|(_, active)| *active)
.collect::<Vec<_>>();
let selections = MultiSelect::with_theme(&SimpleTheme)
.items(&multiselected[..])
.defaults(&defaults[..])
.interact()
.unwrap();
for i in selections {
self.components[i].1 = true;
}
println!("The following components will be installed:");
for (comp, to_install) in &self.components {
if *to_install {
println!(" - {}", comp.to_str());
}
}
let message = "Is this correct?";
Confirm::with_theme(&SimpleTheme)
.with_prompt(message)
.interact()
.unwrap()
}
/// Runs the installer.
@ -228,7 +278,8 @@ impl Installer {
if component.is_installed() || component == Component::Sudo {
return Ok(());
}
println!("Install {}", component);
println!("Install {}", component.to_str());
for dep in component.dependencies() {
self.install_component(*dep)?;
@ -241,32 +292,6 @@ impl Installer {
}
}
impl fmt::Display for Installer {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
for (index, (component, to_install)) in self.components.iter().enumerate() {
writeln!(
fmt,
"{} [{}] {} (requires {}{})",
if self.cursor == index { ">" } else { " " },
if *to_install { "x" } else { " " },
component,
component
.dependencies()
.into_iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(", "),
if component.is_installed() {
", already installed"
} else {
""
}
)?;
}
Ok(())
}
}
/// The error type of this library.
pub enum Error {}
@ -281,8 +306,9 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Runs the installer
pub fn main() -> Result<()> {
let installer = Installer::new();
installer.print();
installer.start()?;
let mut installer = Installer::new();
if installer.interact() {
installer.start()?;
}
Ok(())
}