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 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dialoguer = "0.7.1"

View File

@ -4,6 +4,8 @@ use std::fs::{metadata, symlink_metadata};
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use dialoguer::{theme::SimpleTheme, Confirm, MultiSelect};
macro_rules! unwrap_or_false { macro_rules! unwrap_or_false {
($expr: expr) => { ($expr: expr) => {
match $expr { match $expr {
@ -171,22 +173,41 @@ impl Component {
Component::Git => &[Component::Sudo], Component::Git => &[Component::Sudo],
Component::Zsh => &[Component::Sudo], Component::Zsh => &[Component::Sudo],
Component::Dotfiles => &[Component::Git], Component::Dotfiles => &[Component::Git],
Component::Zshrc => &[Component::Zsh, Component::Dotfiles], Component::Zshrc => &[Component::Zsh, Component::Dotfiles, Component::OhMyZsh],
Component::OhMyZsh => &[Component::Git], 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 { impl fmt::Display for Component {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self { write!(
Component::Sudo => write!(fmt, "sudo"), fmt,
Component::Git => write!(fmt, "git"), "{} (requires {}{})",
Component::Zsh => write!(fmt, "zsh"), self.to_str(),
Component::Dotfiles => write!(fmt, "dotfiles"), self.dependencies()
Component::Zshrc => write!(fmt, "zshrc"), .into_iter()
Component::OhMyZsh => write!(fmt, "ohmyzsh"), .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 { pub struct Installer {
/// All the components to install, and whether the users want to install them. /// All the components to install, and whether the users want to install them.
components: Vec<(Component, bool)>, components: Vec<(Component, bool)>,
/// Where the users cursor is.
cursor: usize,
} }
impl Installer { impl Installer {
/// Creates a new installer. /// Creates a new installer.
pub fn new() -> Installer { pub fn new() -> Installer {
Installer { Installer {
components: Component::all().into_iter().map(|x| (x, true)).collect(), components: Component::all().into_iter().map(|x| (x, false)).collect(),
cursor: 0,
} }
} }
/// Prints the installer. /// Asks interactively to the user which components to install.
pub fn print(&self) { pub fn interact(&mut self) -> bool {
print!("{}", self); 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. /// Runs the installer.
@ -228,7 +278,8 @@ impl Installer {
if component.is_installed() || component == Component::Sudo { if component.is_installed() || component == Component::Sudo {
return Ok(()); return Ok(());
} }
println!("Install {}", component);
println!("Install {}", component.to_str());
for dep in component.dependencies() { for dep in component.dependencies() {
self.install_component(*dep)?; 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. /// The error type of this library.
pub enum Error {} pub enum Error {}
@ -281,8 +306,9 @@ pub type Result<T> = std::result::Result<T, Error>;
/// Runs the installer /// Runs the installer
pub fn main() -> Result<()> { pub fn main() -> Result<()> {
let installer = Installer::new(); let mut installer = Installer::new();
installer.print(); if installer.interact() {
installer.start()?; installer.start()?;
}
Ok(()) Ok(())
} }