gdbc 0.1.0

comprehensive terminal-based GDB client
Documentation
use clap::Parser;
use gdbc::{Command, Error, GdbClient};
use rustyline::history::History;
use rustyline::{DefaultEditor, error::ReadlineError};
use std::path::PathBuf;
use std::str::FromStr;

#[derive(Parser, Debug)]
#[command(name = "gdbc")]
#[command(author = "Your Name <your.email@example.com>")]
#[command(version = "0.1.0")]
#[command(about = "A GDB client for terminal", long_about = None)]
struct Cli {
    /// Host to connect to
    #[arg(short = 'H', long, default_value = "localhost")]
    host: String,

    /// Port to connect to
    #[arg(short, long, default_value_t = 55555)]
    port: u16,

    /// Single instruction to execute
    #[arg(short, long)]
    instruction: Option<String>,

    /// Disable colored output
    #[arg(long, default_value_t = false)]
    no_color: bool,

    /// Enable debug output
    #[arg(short, long, default_value_t = false)]
    debug: bool,
}

fn main() -> Result<(), Error> {
    // Parse command line arguments
    let cli = Cli::parse();

    // Initialize logger
    if cli.debug {
        env_logger::init();
    }

    // Initialize GDB client
    let mut client = GdbClient::new();
    let use_colors = !cli.no_color;

    // Single instruction mode
    if let Some(instruction) = cli.instruction {
        let cmd = Command::from_str(&instruction)?;

        // Connect first if needed
        if !matches!(cmd, Command::Connect(_, _)) {
            // Try to connect with the provided host/port
            let addr = format!("{}:{}", cli.host, cli.port);
            match client.connect(addr) {
                Ok(_) => println!("Connected to GDB server at {}:{}", cli.host, cli.port),
                Err(e) => {
                    eprintln!("Failed to connect to GDB server: {}", e);
                    return Err(e);
                }
            }
        }

        // Execute single instruction
        gdbc::commands::execute_command(cmd, &mut client, use_colors)?;

        // Disconnect if still connected
        if client.is_connected() {
            client.disconnect()?;
        }

        return Ok(());
    }

    // Interactive mode
    println!("GDB Client (gdbc) v0.1.0");
    println!("Type 'help' for available commands, 'quit' to exit");

    // Try to connect if host/port provided
    if cli.host != "localhost" || cli.port != 55555 {
        let addr = format!("{}:{}", cli.host, cli.port);
        match client.connect(addr) {
            Ok(_) => println!("Connected to GDB server at {}:{}", cli.host, cli.port),
            Err(e) => eprintln!("Failed to connect to GDB server: {}", e),
        }
    }

    // Initialize readline
    let mut rl = DefaultEditor::new().map_err(|e| Error::Unknown(e.to_string()))?;

    let history_file = PathBuf::from(dirs::home_dir().unwrap_or_default()).join(".gdbc_history");

    if history_file.exists() {
        let _ = rl.history_mut().load(&history_file);
    }

    // Main loop
    loop {
        let prompt = if client.is_connected() {
            "gdb> "
        } else {
            "gdb (not connected)> "
        };

        match rl.readline(prompt) {
            Ok(line) => {
                let line = line.trim();
                if !line.is_empty() {
                    rl.add_history_entry(line)
                        .map_err(|e| Error::Unknown(e.to_string()))?;

                    match Command::from_str(line) {
                        Ok(cmd) => {
                            if let Err(e) =
                                gdbc::commands::execute_command(cmd, &mut client, use_colors)
                            {
                                eprintln!("Error: {}", e);
                            }
                        }
                        Err(e) => {
                            eprintln!("Parse error: {}", e);
                        }
                    }
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("Press Ctrl+D or type 'quit' to exit");
            }
            Err(ReadlineError::Eof) => {
                println!("Exiting...");
                if client.is_connected() {
                    let _ = client.disconnect();
                }
                break;
            }
            Err(e) => {
                eprintln!("Error: {}", e);
                break;
            }
        }
    }

    // Save history
    let _ = rl.save_history(&history_file);

    Ok(())
}