modcli/
lib.rs

1//! ModCLI — a lightweight, modular CLI framework for Rust.
2//!
3//! # Quick Start
4//! ```no_run
5//! use modcli::ModCli;
6//! let args: Vec<String> = std::env::args().skip(1).collect();
7//! let mut cli = ModCli::new();
8//! cli.run(args);
9//! ```
10//!
11//! # Features
12//! - Custom commands via the `Command` trait
13//! - Styled output, gradients, progress, tables
14//! - Interactive shell (via built-in `shell` command)
15//! - Optional JSON command loading (`json-loader`)
16//! - Optional plugin loading (`plugins`)
17//!
18//! ## JSON Loader (feature: `json-loader`)
19//! ```no_run
20//! use modcli::ModCli;
21//! #[cfg(feature = "json-loader")]
22//! use modcli::loader::sources::JsonFileSource;
23//! let mut cli = ModCli::new();
24//! #[cfg(feature = "json-loader")]
25//! {
26//!     let source = JsonFileSource::new("modcli/examples/commands.json");
27//!     cli.registry.load_from(Box::new(source));
28//! }
29//! let args: Vec<String> = std::env::args().skip(1).collect();
30//! cli.run(args);
31//! ```
32//!
33//! ## Plugins (feature: `plugins`)
34//! ```no_run
35//! use modcli::ModCli;
36//! let mut cli = ModCli::new();
37//! #[cfg(feature = "plugins")]
38//! {
39//!     cli.registry.load_plugins("./plugins");
40//! }
41//! let args: Vec<String> = std::env::args().skip(1).collect();
42//! cli.run(args);
43//! ```
44
45pub mod command;
46pub mod config;
47pub mod console;
48pub mod input;
49pub mod loader;
50pub mod output;
51pub mod parser;
52pub mod shell_commands;
53pub mod shell_extensions;
54
55pub use crate::command::Command as CliCustom;
56use crate::loader::CommandRegistry;
57
58#[cfg(feature = "internal-commands")]
59pub mod commands;
60
61#[cfg(feature = "custom-commands")]
62pub mod custom;
63
64/// Represents a CLI application and provides command registration and dispatch.
65///
66/// Typical usage:
67/// ```no_run
68/// use modcli::ModCli;
69/// let args: Vec<String> = std::env::args().skip(1).collect();
70/// let mut cli = ModCli::new();
71/// cli.run(args);
72/// ```
73pub struct ModCli {
74    pub registry: CommandRegistry,
75    config: Option<config::CliConfig>,
76}
77
78impl Default for ModCli {
79    fn default() -> Self {
80        Self::new()
81    }
82}
83
84impl ModCli {
85    /// Creates a new ModCli instance.
86    ///
87    /// # Example
88    /// ```
89    /// use modcli::ModCli;
90    /// let cli = ModCli::new();
91    /// ```
92    ///
93    /// # Arguments
94    /// * `args` - A vector of command-line arguments
95    ///
96    /// # Returns
97    /// A new instance of `ModCli`
98    pub fn new() -> Self {
99        Self {
100            registry: CommandRegistry::new(),
101            config: None,
102        }
103    }
104
105    /// Sets the command prefix used for prefix routing (e.g., `tool:hello`).
106    pub fn set_prefix(&mut self, prefix: &str) {
107        self.registry.set_prefix(prefix);
108    }
109
110    /// Gets the current command prefix.
111    pub fn get_prefix(&self) -> &str {
112        self.registry.get_prefix()
113    }
114
115    /// Preferred constructor: sets config path before CLI boot.
116    pub fn with_config(path: &str) -> Self {
117        config::set_path(path);
118        Self::new()
119    }
120
121    /// Construct with an owned configuration (non-global). Prefer this in library usage/tests.
122    pub fn with_owned_config(cfg: config::CliConfig) -> Self {
123        let mut s = Self::new();
124        s.apply_config(&cfg);
125        s.config = Some(cfg);
126        s
127    }
128
129    fn apply_config(&mut self, cfg: &config::CliConfig) {
130        if let Some(prefix) = cfg.modcli.prefix.as_deref() {
131            self.set_prefix(prefix);
132        }
133    }
134
135    /// Runs the CLI by dispatching the first arg as the command and the rest as arguments.
136    /// Prints an error if no command is provided.
137    pub fn run(&mut self, args: Vec<String>) {
138        if args.is_empty() {
139            eprintln!("No command provided.");
140            return;
141        }
142
143        let command = &args[0];
144        let rest = &args[1..];
145
146        self.registry.execute(command, rest);
147    }
148}
149
150/// Returns the version of the ModCLI framework (from `modcli/Cargo.toml`).
151///
152/// Useful for surfacing framework version from applications.
153pub fn modcli_version() -> &'static str {
154    env!("CARGO_PKG_VERSION")
155}