From c5c43ade4bfb1c574c2ba3bfad94d0e968db7d44 Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 31 Mar 2021 16:50:28 +0530 Subject: begin work on command line interface --- Cargo.lock | 7 ++++ Cargo.toml | 1 + src/cli.rs | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 src/cli.rs diff --git a/Cargo.lock b/Cargo.lock index aa25765..5cd0345 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,6 +126,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "pico-args" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d70072c20945e1ab871c472a285fc772aefd4f5407723c206242f2c6f94595d6" + [[package]] name = "radium" version = "0.6.2" @@ -156,6 +162,7 @@ dependencies = [ "env_logger", "log", "obi", + "pico-args", "sdl2", ] diff --git a/Cargo.toml b/Cargo.toml index 277d6b0..ce5d614 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,4 @@ sdl2 = {version = "0.34", features = ["ttf"]} obi = { git = "https://github.com/nerdypepper/obi" } env_logger = "0.8.3" log = "0.4.0" +pico-args = "0.4.0" diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..1dbd098 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,128 @@ +use std::{ + default::Default, + fmt, + path::{Path, PathBuf}, +}; + +pub static HELP_TEXT: &'static str = " +Usage +----- + +slate new -d WIDTHxHEIGHT + +Options +------- + + -h, --help Prints help information + -d, Specify dimensions for new file (default: 200x200) +"; + +#[derive(Debug)] +pub enum CliError { + NoDimensions, + FileAlreadyExists, + FileDoesNotExist, + DimensionParseError, + NewRequiresFile, + InvalidSubCommand(String), + SubCommandParseError, +} + +impl fmt::Display for CliError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NoDimensions => write!(f, "no dimensions provided"), + Self::FileAlreadyExists => { + write!(f, "cannot initialize project, file already exists") + } + Self::FileDoesNotExist => { + write!(f, "cannot open existing project, file does not exist") + } + Self::DimensionParseError => write!(f, "invalid dimension string"), + Self::NewRequiresFile => write!(f, "new subcommand requires file name"), + Self::InvalidSubCommand(s) => write!(f, "invalid subcommand `{}`", s), + Self::SubCommandParseError => write!(f, "error parsing subcommand"), + } + } +} + +impl std::error::Error for CliError {} + +#[derive(Debug)] +pub enum Config { + NewProject { + file_name: Option, + dimensions: (u32, u32), + }, + ExistingProject { + file_name: PathBuf, + }, + Help, +} + +impl Default for Config { + fn default() -> Self { + Self::NewProject { + file_name: None, + dimensions: (200, 200), + } + } +} + +pub fn parse_args() -> Result { + let mut args = pico_args::Arguments::from_env(); + + if args.contains(["-h", "--help"]) { + return Ok(Config::Help); + } + + match args.subcommand() { + Ok(cmd) => match cmd.as_deref() { + Some("new") => new_project(&mut args), + Some(s) => { + if !Path::new(s).is_file() { + return Err(CliError::FileDoesNotExist); + } + return Ok(Config::ExistingProject { + file_name: PathBuf::from(s), + }); + } + None => return Ok(Config::Help), + }, + _ => Err(CliError::SubCommandParseError), + } +} + +fn new_project(args: &mut pico_args::Arguments) -> Result { + let file_name = args.free_from_str(); + if let Ok(f) = &file_name { + if Path::new(&f).is_file() { + return Err(CliError::FileAlreadyExists); + } + } + let dimensions = args + .opt_value_from_fn(["-d", "--dimensions"], parse_dimensions) + .map_err(|_| CliError::DimensionParseError)? + .unwrap_or((200, 200)); + return Ok(Config::NewProject { + file_name: file_name.ok(), + dimensions, + }); +} + +fn parse_dimensions(input: &str) -> Result<(u32, u32), CliError> { + let dimensions: Vec<&str> = input.split('x').collect(); + match &dimensions[..] { + [width, height] => { + return Ok(( + width + .parse::() + .map_err(|_| CliError::DimensionParseError)?, + height + .parse::() + .map_err(|_| CliError::DimensionParseError)?, + )) + } + _ => return Err(CliError::DimensionParseError), + } +} -- cgit v1.2.3