Repository: typst/typst
File: crates/typst-cli/src/args.rs (Rust)

Code before:

fn parse_input_pair(raw: &str) -> Result<(String, String), InputPairError> {
    let (key, val) = raw.split_once('=').ok_or(InputPairError::NoEqual)?;
    let key = key.trim().to_owned();
    if key.is_empty() {
        return Err(InputPairError::MissingKey);
    }
    let val = val.trim().to_owned();
    Ok((key, val))
}

/// An error that occurred while parsing an input argument
#[derive(Clone, Debug)]
enum InputPairError {
    /// Missing equal sign in the value
    NoEqual,
    // The key was missing or entirely blank
    MissingKey,
}

impl Display for InputPairError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Self::NoEqual => write!(
                f,
                "input arguments must be a key and a value separated by an equal sign"
            ),
            Self::MissingKey => write!(f, "the key was missing or empty"),
        }
    }
}

impl std::error::Error for InputPairError {}

/// Lists all discovered fonts in system and custom font paths
#[derive(Debug, Clone, Parser)]
pub struct FontsCommand {
    /// Adds additional directories to search for fonts
    #[clap(
        long = "font-path",
        env = "TYPST_FONT_PATHS",
        value_name = "DIR",
        value_delimiter = ENV_PATH_SEP,
    )]
    pub font_paths: Vec<PathBuf>,

    /// Also lists style variants of each font family
    #[arg(long)]
    pub variants: bool,
}


Review comment (suggestion):
```suggestion
                "input must be a key and a value separated by an equal sign"
```

Code after:
/// This function will return an error if the argument contains no equals sign
/// or contains the key (before the equals sign) is empty.
fn parse_input_pair(raw: &str) -> Result<(String, String), String> {
    let (key, val) = raw
        .split_once('=')
        .ok_or("input must be a key and a value separated by an equal sign")?;
    let key = key.trim().to_owned();
    if key.is_empty() {
        return Err("the key was missing or empty".to_owned());
    }
    let val = val.trim().to_owned();
    Ok((key, val))
}

/// Lists all discovered fonts in system and custom font paths
#[derive(Debug, Clone, Parser)]
pub struct FontsCommand {
    /// Adds additional directories to search for fonts
    #[clap(
        long = "font-path",
        env = "TYPST_FONT_PATHS",
        value_name = "DIR",
        value_delimiter = ENV_PATH_SEP,
    )]
    pub font_paths: Vec<PathBuf>,

    /// Also lists style variants of each font family
    #[arg(long)]
    pub variants: bool,
}

/// Which format to use for diagnostics.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ValueEnum)]
pub enum DiagnosticFormat {
    Human,
    Short,
}

impl Display for DiagnosticFormat {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.to_possible_value()
            .expect("no values are skipped")
            .get_name()
            .fmt(f)
    }
}

/// Update the CLI using a pre-compiled binary from a Typst GitHub release.
#[derive(Debug, Clone, Parser)]
pub struct UpdateCommand {
    /// Which version to update to (defaults to latest)