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

Download history 310/week @ 2025-05-09

310 downloads per month

MIT license

31KB
716 lines

Hackshell

License: MIT

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 variables
  • get <name> - Get the value of an environment variable
  • set <name> <value> - Set an environment variable
  • unset <name> - Remove an environment variable
  • help - Show available commands and their descriptions
  • sleep <seconds> - Sleep for the specified duration
  • exit - Exit the shell
  • task - 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