3 releases
Uses new Rust 2024
new 0.1.2 | May 12, 2025 |
---|---|
0.1.1 | May 12, 2025 |
0.1.0 | May 12, 2025 |
#461 in FFI
310 downloads per month
31KB
716 lines
Hackshell
Hackshell is a lightweight, customizable shell framework built in Rust. It provides an interactive command-line interface that can be easily extended with custom commands and integrated into your applications.
Features
- Async Command Processing: Built on Tokio for efficient async operations
- Task Management: Background task spawning, monitoring, and killing
- Environment Variables: Built-in environment variable storage and manipulation
- Rich Command Set: Comes with essential built-in commands like
help
,set
,get
,env
, etc. - Command History: Persistent command history between sessions
- Custom Context: Bring your own application context for deep integration
Built-in Commands
Hackshell comes with several built-in commands:
env
- List all environment variablesget <name>
- Get the value of an environment variableset <name> <value>
- Set an environment variableunset <name>
- Remove an environment variablehelp
- Show available commands and their descriptionssleep <seconds>
- Sleep for the specified durationexit
- Exit the shelltask
- Manage background tasks
Usage
You can find complete examples in the examples
directory. The following are quick examples.
Basic Example
use std::path::Path;
use hackshell::Hackshell;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a new shell with a custom context (in this case just ())
let shell = Hackshell::new((), "hackshell> ", Some(Path::new("history.txt"))).await?;
// Enter the shell loop
loop {
match shell.run().await {
Ok(_) => {}
Err(e) => {
if e == "EOF" || e == "CTRLC" || e == "exit" {
break;
}
eprintln!("Error: {}", e);
}
}
}
Ok(())
}
Adding Custom Commands
You can extend Hackshell with your own commands:
use std::path::Path;
use hackshell::{Hackshell, Command};
struct MyCommand;
#[async_trait::async_trait]
impl Command<()> for MyCommand {
fn commands(&self) -> &'static [&'static str] {
&["mycmd"]
}
fn help(&self) -> &'static str {
"mycmd - My custom command"
}
async fn run(&self, shell: &Hackshell<()>, args: &[String], _ctx: &()) -> Result<(), String> {
println!("My custom command was called with args: {:?}", &args[1..]);
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let shell = Hackshell::new((), "hackshell> ", Some(Path::new("history.txt"))).await?;
// Add your custom command
shell.add_command(MyCommand {}).await;
// Run shell loop
// ...
Ok(())
}
Advanced Context Example
struct AppState {
config: RwLock<HashMap<String, String>>,
client: Mutex<DatabaseClient>,
}
// Your custom commands can now access the AppState
struct ConfigCommand;
#[async_trait::async_trait]
impl Command<AppState> for ConfigCommand {
// Implementation omitted for brevity
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app_state = AppState {
config: RwLock::new(HashMap::new()),
client: Mutex::new(DatabaseClient::connect("localhost:5432").await?),
};
let shell = Hackshell::new(app_state, "myapp> ", Some(Path::new("history.txt"))).await?;
// ...
}
Background Tasks
Hackshell allows you to spawn and manage background tasks:
// Spawn a background task
shell.spawn("my-task", async {
for i in 0..10 {
println!("Background task: {}\r", i);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
}).await;
// List active tasks
let tasks = shell.get_tasks().await;
for task in tasks {
println!("Task: {}, running for {}s", task.name, task.duration.as_secs());
}
// Kill a task
shell.kill("my-task").await?;
Installation
Add Hackshell to your Cargo.toml
:
[dependencies]
hackshell = "0.1.2"
tokio = { version = "1", features = ["full"] }
async-trait = "0.1"
License
This project is licensed under the MIT License - see the LICENSE file for details.
Dependencies
~7–18MB
~252K SLoC