openscript_cli 0.1.0

Command-line interface for OpenScript
//! OpenScript CLI - AI-Powered Scripting Language

use clap::{Parser, Subcommand};
use colored::*;
use std::fs;
use std::path::PathBuf;
use std::io::{self, Write};
use anyhow::Result;
use openscript_sdk::plugin::PluginManager;
use openscript_sdk::ai_plugin::AiPlugin;
use openscript_sdk::filesystem_plugin::FilesystemPlugin;
use openscript_sdk::http_plugin::HttpPlugin;
use openscript_sdk::system_plugin::SystemPlugin;
use openscript_sdk::utils_plugin::UtilsPlugin;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(name = "openscript")]
#[command(about = "OpenScript - AI-Powered Scripting Language")]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
    /// Run a script file
    Run {
        /// Script file to execute
        file: PathBuf,
        
        /// Enable verbose output
        #[arg(short, long)]
        verbose: bool,
        
        /// Pass arguments to the script
        #[arg(trailing_var_arg = true)]
        args: Vec<String>,
    },
    
    /// Start interactive REPL
    Repl {
        /// Enable AI assistance in REPL
        #[arg(long)]
        ai: bool,
        
        /// Load a script file before starting REPL
        #[arg(short, long)]
        load: Option<PathBuf>,
    },
    
    /// Execute inline script
    Eval {
        /// Script to execute
        script: String,
        
        /// Enable verbose output
        #[arg(short, long)]
        verbose: bool,
    },
    
    /// Show examples
    Examples,
    
    /// Check syntax of a script file
    Check {
        /// Script file to check
        file: PathBuf,
    },
    
    /// Format a script file
    Format {
        /// Script file to format
        file: PathBuf,
        
        /// Write formatted output to file
        #[arg(short, long)]
        write: bool,
    },
    
    /// Show version and build information
    Version,
}

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();
    
    // Initialize logging
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
    
    let mut plugin_manager = PluginManager::new();
    plugin_manager.load_plugin(Box::new(AiPlugin::new())).await.map_err(|e| anyhow::anyhow!(e))?;
    plugin_manager.load_plugin(Box::new(FilesystemPlugin::new())).await.map_err(|e| anyhow::anyhow!(e))?;
    plugin_manager.load_plugin(Box::new(HttpPlugin::new())).await.map_err(|e| anyhow::anyhow!(e))?;
    plugin_manager.load_plugin(Box::new(SystemPlugin::new())).await.map_err(|e| anyhow::anyhow!(e))?;
    plugin_manager.load_plugin(Box::new(UtilsPlugin::new())).await.map_err(|e| anyhow::anyhow!(e))?;
    
    match cli.command.unwrap_or(Commands::Repl { ai: false, load: None }) {
        Commands::Run { file, verbose, args } => {
            run_file(file, verbose, args, &plugin_manager).await?;
        }
        Commands::Repl { ai, load } => {
            run_repl(ai, load, &plugin_manager).await?;
        }
        Commands::Eval { script, verbose } => {
            run_script(&script, verbose, &plugin_manager).await?;
        }
        Commands::Examples => {
            show_examples();
        }
        Commands::Check { file } => {
            check_syntax(file).await?;
        }
        Commands::Format { file, write } => {
            format_file(file, write).await?;
        }
        Commands::Version => {
            show_version();
        }
    }
    
    Ok(())
}

async fn run_file(path: PathBuf, verbose: bool, _args: Vec<String>, plugin_manager: &PluginManager) -> Result<()> {
    if verbose {
        println!("{}", " OpenScript v1.0.0".bright_blue().bold());
        println!("{}", format!(" Running: {}", path.display()).yellow());
    }
    
    let script = fs::read_to_string(&path)?;
    
    run_script(&script, verbose, plugin_manager).await
}

async fn run_script(script: &str, verbose: bool, plugin_manager: &PluginManager) -> Result<()> {
    if verbose {
        println!("{}", " OpenScript v1.0.0".bright_blue().bold());
    }
    
    for line in script.lines() {
        let parts: Vec<String> = line.split_whitespace().map(|s| s.to_string()).collect();
        if parts.is_empty() {
            continue;
        }

        let command_name = &parts[0];
        let args = &parts[1..];

        if let Some(command) = plugin_manager.get_command(command_name) {
            match command.execute(args).await {
                Ok(result) => {
                    if !result.is_empty() {
                        println!("{}", result);
                    }
                }
                Err(e) => {
                    eprintln!("{}", format!("Error: {}", e).red());
                }
            }
        } else {
            eprintln!("{}", format!("Unknown command: {}", command_name).red());
        }
    }
    
    Ok(())
}

async fn run_repl(ai_enabled: bool, load_file: Option<PathBuf>, plugin_manager: &PluginManager) -> Result<()> {
    println!("{}", " OpenScript REPL v1.0.0".bright_blue().bold());
    
    if ai_enabled {
        if std::env::var("OPENAI_API_KEY").is_ok() {
            println!("{}", " AI assistance enabled".green());
        } else {
            println!("{}", "Warning: AI assistance requested but OPENAI_API_KEY not set".yellow());
        }
    }
    
    println!("{}", "Type 'help' for commands, 'exit' to quit\n".dimmed());
    
    // TODO: Implement once the openscript runtime API is finalized
    
    // Load file if specified
    if let Some(file_path) = load_file {
        let script = fs::read_to_string(&file_path)?;
        println!("{}", format!(" Loaded {}", file_path.display()).green());
        println!("Script content:");
        println!("{}", script.dimmed());
        println!();
    }
    
    let mut line_number = 1;
    
    loop {
        let prompt = format!("{} ", format!("[{}]►", line_number).green());
        
        print!("{}", prompt);
        io::stdout().flush()?;
        
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        let input = input.trim();
        
        // Handle special commands
        match input {
            "exit" | "quit" => break,
            "help" => {
                print_help();
                continue;
            }
            "clear" => {
                print!("\x1B[2J\x1B[1;1H");
                continue;
            }
            _ => {}
        }
        
        let parts: Vec<String> = input.split_whitespace().map(|s| s.to_string()).collect();
        if parts.is_empty() {
            line_number += 1;
            continue;
        }

        let command_name = &parts[0];
        let args = &parts[1..];

        if let Some(command) = plugin_manager.get_command(command_name) {
            match command.execute(args).await {
                Ok(result) => {
                    if !result.is_empty() {
                        println!("{}", result);
                    }
                }
                Err(e) => {
                    eprintln!("{}", format!("Error: {}", e).red());
                }
            }
        } else {
            eprintln!("{}", format!("Unknown command: {}", command_name).red());
        }

        line_number += 1;
    }
    
    println!("{}", "\nGoodbye!".bright_blue());
    Ok(())
}

fn print_help() {
    println!("{}", "\n OpenScript REPL Commands".bright_blue().bold());
    println!("{}", "".repeat(40).dimmed());
    println!("{}  {}", "help".bright_green(), "Show this help message");
    println!("{}  {}", "exit".bright_green(), "Exit the REPL");
    println!("{}  {}", "clear".bright_green(), "Clear the screen");
    println!("{}", "".repeat(40).dimmed());
    println!("{}", "\n OpenScript Language Features".bright_blue().bold());
    println!("{}", "".repeat(40).dimmed());
    println!("• Variables: {} = {}", "name".bright_yellow(), "\"value\"".bright_cyan());
    println!("• Functions: {} {} {{ ... }}", "fn".bright_magenta(), "myFunc()".bright_yellow());
    println!("• Control flow: {}, {}, {}", "if".bright_magenta(), "for".bright_magenta(), "while".bright_magenta());
    println!("• AI features: {}, {}", "ai_complete()".bright_yellow(), "ai_image()".bright_yellow());
    println!("{}", "".repeat(40).dimmed());
    println!();
}

fn show_examples() {
    println!("{}", "\n OpenScript Examples".bright_blue().bold());
    println!("{}", "".repeat(60).dimmed());
    
    println!("{}", "\n Basic Variables and Printing".bright_green().bold());
    println!("{}", r#"name = "OpenScript"
print("Hello from " + name + "!")
"#.dimmed());
    
    println!("{}", "\n Functions".bright_green().bold());
    println!("{}", r#"fn greet(name) {
    return "Hello, " + name + "!"
}
print(greet("World"))
"#.dimmed());
    
    println!("{}", "\n Loops and Control Flow".bright_green().bold());
    println!("{}", r#"for i in range(1, 5) {
    if i % 2 == 0 {
        print(i + " is even")
    }
}
"#.dimmed());
    
    println!("{}", "\n AI Integration".bright_green().bold());
    println!("{}", r#"// Text completion
response = ai_complete("Write a haiku about programming")
print(response)

// Image generation  
image_url = ai_image("futuristic city at sunset")
print("Generated image: " + image_url)
"#.dimmed());
    
    println!("{}", "\n File Operations".bright_green().bold());
    println!("{}", r#"// Write to file
write_file("output.txt", "Hello, OpenScript!")

// Read from file
content = read_file("output.txt")
print(content)
"#.dimmed());
    
    println!("{}", "".repeat(60).dimmed());
    println!();
}

async fn check_syntax(path: PathBuf) -> Result<()> {
    println!("{}", " Checking syntax...".yellow());
    
    let script = fs::read_to_string(&path)?;
    
    // TODO: Implement once the openscript parser API is finalized
    println!("{}", "Syntax checking not yet implemented".yellow());
    println!("Script loaded successfully:");
    println!("{} bytes", script.len());
    
    Ok(())
}

async fn format_file(path: PathBuf, write: bool) -> Result<()> {
    let script = fs::read_to_string(&path)?;
    
    // TODO: Implement once the openscript parser API is finalized
    println!("{}", "Code formatting not yet implemented".yellow());
    
    if write {
        println!("{}", format!("Would format {}", path.display()).dimmed());
    } else {
        println!("Script content:");
        println!("{}", script.dimmed());
    }
    
    Ok(())
}

fn show_version() {
    println!("{}", " OpenScript".bright_blue().bold());
    println!("{}", "".repeat(40).dimmed());
    println!("{} {}", "Version:".bright_green(), env!("CARGO_PKG_VERSION"));
    println!("{} {}", "License:".bright_green(), "MIT OR Apache-2.0");
    println!("{} {}", "Authors:".bright_green(), env!("CARGO_PKG_AUTHORS"));
    println!("{}", "".repeat(40).dimmed());
    println!();
    println!("{}", "Build Information".bright_blue().bold());
    println!("{}", "".repeat(40).dimmed());
    println!("{} {}", "Target:".bright_green(), std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string()));
    println!("{} {}", "Host:".bright_green(), std::env::var("HOST").unwrap_or_else(|_| "unknown".to_string()));
    println!("{} {}", "Profile:".bright_green(), if cfg!(debug_assertions) { "debug" } else { "release" });
    println!("{} {}", "Rustc:".bright_green(), std::env::var("RUSTC_VERSION").unwrap_or_else(|_| "unknown".to_string()));
    println!("{}", "".repeat(40).dimmed());
}