6 releases (breaking)
new 0.5.0 | May 1, 2025 |
---|---|
0.4.0 | Apr 30, 2025 |
0.3.8 | Apr 30, 2025 |
0.2.1 | Apr 10, 2025 |
0.1.0 | Apr 10, 2025 |
#302 in Asynchronous
672 downloads per month
82KB
1.5K
SLoC
ModCLI is a lightweight, modular CLI framework for Rust. A fully customizable and feature-rich system for registering commands, styling output, and running interactive shells with zero bloat. Built to speed up CLI development and get powerful tools running fast—without rewriting the basics.
Key Features
Installation
Add the library to your Cargo.toml
:
[dependencies]
mod-cli = "0.5.0"
Add the library to your Cargo.toml
with features:
[dependencies]
mod-cli = { version = "0.5.0", features = ["plugins"] }
Feature Flags
Feature | Description |
---|---|
internal-commands |
Enables built-in test/dev commands like ping , hello |
custom-commands |
Enables CLI custom command creation. |
json-loader |
Enables external command loading from JSON config |
plugins |
Enables plugin support for dynamic runtime command injection |
Usage
Basic Usage
use modcli::ModCli;
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let mut cli = ModCli::new();
cli.run(args);
}
Set a custom prefix
use modcli::ModCli;
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let mut cli = ModCli::new();
// Set a custom prefix
cli.set_prefix("myCLI");
cli.run(args);
}
Using named colors
let teal = colors::get("teal"); // always returns a Color (or fallback)
let demo = build()
.part("Color Demo:").space()
.part("Teal").color(teal).bold().get();
print::line(&demo, 0);
Using Gradients
Two-color gradient:
use modcli::output::{
gradient,
print,
RED, ORANGE
};
let gradient_text = gradient::two_color("Two color gradient", RED, ORANGE);
print::line(&gradient_text);
Three-color gradient:
use modcli::output::{
gradient,
print,
BLUE, GREEN, YELLOW
};
let gradient_text = gradient::three_color("Three color gradient", BLUE, GREEN, YELLOW);
print::line(&gradient_text);
Multi-color gradient:
use modcli::output::{
gradient,
print,
RED, ORANGE, YELLOW, GREEN, BLUE
};
let gradient_text = gradient::multi_color("Multi-color gradient", vec![RED, ORANGE, YELLOW, GREEN, BLUE]);
print::line(&gradient_text);
Using RGB with gradients:
use modcli::output::{
gradient,
print
};
let gradient_text = gradient::two_color(
"Gradient Output",
Color::Rgb { r: 255, g: 0, b: 0 },
Color::Rgb { r: 0, g: 0, b: 255 },
);
print::line(&gradient_text);
Output Styles
use modcli::output::{
print,
build,
BLUE
};
// 📦 Progress Bar Demo
let testing = build()
.part("Testing")
.color(BLUE)
.bold()
.get();
print::line(&testing);
// Outputs "Testing" in bold/blue.
Multiple Styles:
use modcli::output::{
gradient,
print,
build,
BLUE, LIGHT_BLUE
};
// 📦 Progress Bar Demo
let testing = build()
.part("Label:").color(BLUE).bold().space()
.part("This content has").space()
.part("multiple").color(LIGHT_BLUE).bold().space()
.part("styles").underline().space()
.part("and").italic().space()
.part("colors").underline().space()
.part("!")
.get();
print::line(&testing);
Style + Gradients:
use modcli::output::{
print,
build,
BLUE, GREEN
};
let gradient_text = gradient::two_color("Gradient Output", BLUE, GREEN);
let testing = build()
.part(&gradient_text).bold().space()
.part("+ Styled!")
.get();
print::line(&testing);
Progress Bar & Animated Loaders
Auto Progress:
use modcli::output::{
progress::{
show_progress_bar,
}
};
show_progress_bar("Testing", 45, 1500);
Displays
Label [#############################################] 100% Done!
Manual control:
use modcli::output::{
build,
progress::{
ProgressBar,
ProgressStyle,
},
LIGHT_BLUE
};
// Progress Bar Demo
let label = build()
.part("Loading")
.color(LIGHT_BLUE)
.bold()
.get();
let mut bar = ProgressBar::new(30, ProgressStyle {
fill: '■',
done_label: "Complete!",
color: Some(LIGHT_BLUE),
..Default::default()
});
bar.set_label(&label);
bar.start_auto(2000); // auto-fill in 2 seconds
Manual .tick() control (like during a loop):
use std::time::Duration;
use modcli::output::{
progress::{
ProgressBar,
ProgressStyle
},
ORANGE
};
use modcli::output::input::console::run_interactive_console;
let mut bar = ProgressBar::new(10, ProgressStyle {
fill: '■',
done_label: "Done!",
color: Some(ORANGE),
..Default::default()
});
bar.set_label("Syncing");
for _ in 0..10 {
bar.tick();
std::thread::sleep(Duration::from_millis(200));
}
println!(" {}", bar.style.done_label);
Animated Spinner (Loading/Waiting):
use modcli::output::{
progress::{
show_spinner
}
};
show_spinner("Loading", 20, 100);
Animated Percentage Loader:
use std::thread::sleep;
use std::time::Duration;
use modcli::output::{
progress::{
show_percent_progress
}
};
for i in (0..=100).step_by(10) {
show_percent_progress("Loading", i);
sleep(Duration::from_millis(100));
}
println!();
Tables
Table Example: Flex Width, Heavy Borders
use crate::output::table::{render_table, TableMode, TableStyle};
let headers = ["Name", "Age", "Role"];
let rows = vec![
vec!["Alice", "29", "Engineer"],
vec!["Bob", "35", "Manager"],
vec!["Charlie", "41", "CTO"],
];
render_table(&headers, &rows, TableMode::Flex, TableStyle::Heavy);
Outputs
┏━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃Name ┃Age ┃Role ┃
┣━━━━━━━━╋━━━━━━━━╋━━━━━━━━┫
┃Alice ┃29 ┃Engineer┃
┃Bob ┃35 ┃Manager ┃
┃Charlie ┃41 ┃CTO ┃
┗━━━━━━━━┻━━━━━━━━┻━━━━━━━━┛
Table Example: Fixed Width, Rounded Borders
use crate::output::table::{render_table, TableMode, TableStyle};
let headers = ["Name", "Age", "Role"];
let rows = vec![
vec!["Alice", "29", "Engineer"],
vec!["Bob", "35", "Manager"],
vec!["Charlie", "41", "CTO"],
];
render_table(&headers, &rows, TableMode::Fixed(15), TableStyle::Rounded);
Outputs
╭───────────────┬───────────────┬───────────────╮
│Name │Age │Role │
├───────────────┼───────────────┼───────────────┤
│Alice │29 │Engineer │
│Bob │35 │Manager │
│Charlie │41 │CTO │
╰───────────────┴───────────────┴───────────────╯
Table Example: Fixed Width, Ascii Borders
use crate::output::table::{render_table, TableMode, TableStyle};
let headers = ["Name", "Age", "Role"];
let rows = vec![
vec!["Alice", "29", "Engineer"],
vec!["Bob", "35", "Manager"],
vec!["Charlie", "41", "CTO"],
];
render_table(&headers, &rows, TableMode::Fixed(15), TableStyle::Ascii);
Outputs
+---------------+---------------+---------------+
|Name |Age |Role |
+---------------+---------------+---------------+
|Alice |29 |Engineer |
|Bob |35 |Manager |
|Charlie |41 |CTO |
+---------------+---------------+---------------+
Creating Custom Commands
File Structure
my_project/
├── src/
│ ├── commands/
│ │ └── greet.rs ← define `GreetCommand` here
Create a commands folder in src/, then put the command in its own file:
Custom Command File
use modcli::command::Command;
pub struct GreetCommand;
impl Command for GreetCommand {
fn name(&self) -> &str {
"greet"
}
fn aliases(&self) -> &[&str] {
&["hi"]
}
fn help(&self) -> Option<&str> {
Some("Greets the user.")
}
fn validate(&self, _args: &[String]) -> Result<(), String> {
Ok(())
}
fn execute(&self, _args: &[String]) {
println!("Greetings!");
}
}
greet.rs
Register your command in main.rs
, tool.rs
, etc.
mod commands;
use modcli::ModCli;
use commands::greet::GreetCommand;
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let mut cli = ModCli::new();
// Register function
cli.registry.register(Box::new(GreetCommand));
cli.run(args);
}
Test Command
$ myCLI greet
Greetings!
$ myCLI help
List of available commands...
Interactive Shell
ModCLI supports an interactive console mode (like a REPL):
use modcli::config::CliConfig;
use modcli::console::run_shell;
fn main() {
let config = CliConfig::load(None);
run_shell(&config);
}
Adding a custom console command for shell
:
use modcli::ModCli;
use modcli::shell_commands::{register, ShellCommand};
fn greet_handler(_input: &str) -> bool {
println!("👋 Hello from shell command!");
true
}
fn main() {
register(ShellCommand {
name: "greet",
aliases: &["hi", "wave"],
help: "Greets the user with a friendly hello",
handler: greet_handler,
});
}
Config File Example (config.json)
{
"modcli": {
"name" : "mod-cli",
"prefix": "mod",
"banner": "Welcome to ModCLI",
"delay" : 0,
"theme" : "default",
"strict": false,
"force_shell": false,
"shell": {
"prompt": "Tool >",
"welcome": ["Welcome to the console."],
"goodbye": ["Bye!"]
},
"messages": {
"no_command": "No command provided.",
"not_found": "Command not found."
}
}
}
Default location:
project_root/config.json
Manually set the config path (if not project root)
use modcli::config;
fn main() {
config::set_path(("my/custom/config.json");
[!WARNING] Pre-release: This project is in active development. The core is stable but features are evolving. Production use is possible, but interfaces may still evolve until 1.0.
📌 License
Licensed under the Apache License, version 2.0 (the "License"); you may not use this software, including, but not limited to the source code, media files, ideas, techniques, or any other associated property or concept belonging to, associated with, or otherwise packaged with this software except in compliance with the License.
You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the LICENSE file included with this project for the specific language governing permissions and limitations under the License.
COPYRIGHT © 2025 JAMES GOBER.
Dependencies
~6–16MB
~180K SLoC