//! The commands that can be performed in the CLI pub mod edit; pub mod read; pub mod save; pub use edit::*; pub use read::*; pub use save::*; use crate::Editor; use std::ops::RangeInclusive; /// Errors that can occur when parsing a command. This is for syntax checking, the /// semantics are checked when trying to execute the command. #[allow(missing_docs)] #[derive(thiserror::Error, Debug)] pub enum CmdParseError { #[error("no command specified")] StringEmpty, #[error("the command {0} is unknown")] NoSuchCmd(String), #[error("wrong number of arguments. Expected in range {1:?}, but received {0}")] WrongNumberOfArgs(usize, RangeInclusive), #[error("{0} cannot be converted into a {1}, which is required")] InvalidArgType(String, &'static str), } /// Attempts to parse a command from the given string. If it is unsuccessful, it returns a /// [CmdParseError]. pub fn parse_command(string: &str) -> Result, CmdParseError> { if string.is_empty() { return Err(CmdParseError::StringEmpty); } let parts: Vec<&str> = string.split_whitespace().collect(); match parts[0] { "w" => Ok(Box::new(Save::from_args(&parts[1..])?)), "e" => Ok(Box::new(Edit::from_args(&parts[1..])?)), "r" => Ok(Box::new(Read::from_args(&parts[1..])?)), other => Err(CmdParseError::NoSuchCmd(other.to_owned())), } } /// Indicates that this entity (command) can be created from arguments. Make sure to check what is /// expected, to pass the arguments to the correct command. pub trait FromArgs: Sized { /// Creates a new instance from the arguments provided. If for whatever reason the syntax of the /// given arguments is correct an [ArgParseError] is returned. fn from_args(args: &[&str]) -> Result; } /// A common trait for all commands. pub trait Command { /// Process this command on the provided context. Returns either a string with the output of the /// command when everything went right with it, or an error string explaining what went wrong, /// which can be displayed to the user. fn process(&self, editor: &mut Editor) -> Result; }