argc 1.24.0

A bash cli framework, also a bash-based command runner
Documentation
use crate::param::{EnvParam, FlagOptionParam, Param, PositionalParam};
use crate::parser::Position;

use anyhow::{bail, Result};
use std::collections::HashMap;

#[derive(Debug, Default, Clone)]
pub(crate) struct NamesChecker {
    pub(crate) flag_options: HashMap<String, (Position, String)>,
    pub(crate) envs: HashMap<String, Position>,
    pub(crate) positionals: HashMap<String, Position>,
}

impl NamesChecker {
    pub(crate) fn check_flag_option(
        &mut self,
        param: &FlagOptionParam,
        pos: Position,
    ) -> Result<()> {
        let tag_name = param.tag_name();
        let names = param.list_names();
        for name in names.iter() {
            if let Some((exist_pos, _)) = self.flag_options.get(name) {
                bail!("{}", Self::conflict_error(tag_name, pos, name, *exist_pos));
            }
            self.flag_options
                .insert(name.to_string(), (pos, format!("{tag_name} {name}")));
        }
        Ok(())
    }

    pub(crate) fn check_env(&mut self, param: &EnvParam, pos: Position) -> Result<()> {
        let name = param.id();
        if let Some(exist_pos) = self.envs.get(name) {
            bail!(
                "{}",
                Self::conflict_error(param.tag_name(), pos, name, *exist_pos)
            );
        }
        self.envs.insert(name.to_string(), pos);
        Ok(())
    }

    pub(crate) fn check_positional(
        &mut self,
        param: &PositionalParam,
        pos: Position,
    ) -> Result<()> {
        let name = param.id();
        if let Some(exist_pos) = self.positionals.get(name) {
            bail!(
                "{}",
                Self::conflict_error(param.tag_name(), pos, name, *exist_pos)
            );
        }
        self.positionals.insert(name.to_string(), pos);
        Ok(())
    }

    fn conflict_error(
        tag_name: &str,
        pos: Position,
        name_desc: &str,
        exist_pos: Position,
    ) -> String {
        format!("{tag_name}(line {pos}) has '{name_desc}' already exists at line {exist_pos}",)
    }
}