Working on UI
This commit is contained in:
parent
89838ae594
commit
1d3c6c83e4
|
@ -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"
|
||||
|
|
116
src/lib.rs
116
src/lib.rs
|
@ -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();
|
||||
let mut installer = Installer::new();
|
||||
if installer.interact() {
|
||||
installer.start()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue