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}