aboutsummaryrefslogtreecommitdiff
path: root/src/cli/cmd/mod.rs
blob: 42e865af85ec71b54629b1cbbfdd72a97ce34e8e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//! 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<usize>),
    #[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<Box<dyn Command>, 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<Self, CmdParseError>;
}

/// 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<String, String>;
}