ilm 0.1.6

A fun programming language with Islamic terminology.
use clap::{Arg, Command};
use std::fs;
use std::time::Instant;
use std::path::PathBuf;
use ilm_core::{parser::Parser, interpreter::Interpreter, highlighter};

fn main() {
    println!("\x1B[32m> ilm\x1B[0m");
    
    let matches = define_cli().get_matches();

    // Manually handle -v/--version
    if matches.get_flag("version") {
        println!("{}", env!("CARGO_PKG_VERSION"));
        std::process::exit(0);
    }

    if let Some(enable_value) = matches.get_one::<String>("enable") {
        handle_enable(enable_value, matches.get_flag("force"));
    } else if let Some(sub_matches) = matches.subcommand_matches("run") {
        run_ilm_file(sub_matches);
    }
}

fn define_cli() -> Command {
    Command::new("milaf")
        .about("A command-line tool for running ilm programs")
        // .version(env!("CARGO_PKG_VERSION"))
        .arg_required_else_help(true)
        .arg(
            Arg::new("enable")
                .short('e')
                .long("enable")
                .value_name("FEATURE")
                .help("Enable a feature (e.g., 'language' for VS Code support)")
                .num_args(1),
        ).arg(
            Arg::new("force")
                .short('f')
                .long("force")
                .help("Force enablement of the feature, overwriting existing configurations")
                .action(clap::ArgAction::SetTrue)
                .requires("enable"),  // Only valid with --enable
        )
        .arg(
            Arg::new("version")
                .short('v')
                .long("version")
                .help("Print version information and exit")
                .action(clap::ArgAction::SetTrue),
        )
        .subcommand(
            Command::new("run")
                .about("Run an ilm program")
                .arg(
                    Arg::new("file")
                        .help("The .ilm file to run")
                        .required(true)
                        .index(1),
                ),
        )
}

fn run_ilm_file(matches: &clap::ArgMatches) {
    let file_path = matches.get_one::<String>("file").unwrap();
    let start_time = Instant::now();

    if !is_extension_installed() {
        println!("Warning: ilm VS Code extension not detected. Run 'milaf -enable language' to install it.");
    }

    let code = fs::read_to_string(file_path)
        .unwrap_or_else(|_| panic!("Failed to read file: {}", file_path));
    
    let tokens = ilm_core::lexer::Lexer::new(&code).tokenize();
    let mut parser = Parser::new(tokens, &code);
    
    match parser.parse() {
        Ok(ast) => {
            let mut interp = Interpreter::new();
            if let Err(e) = interp.run(ast) {
                println!("{}", e.to_string());
            } else {
                let duration = start_time.elapsed();
                println!(
                    "\n\x1B[94m+---------------------------------+\n| Masha'Allah! Aiktamal altanfidh |\n+---------------------------------+\x1B[0m\n\x1B[35m{:?}\x1B[0m",
                    duration
                );
            }
        }
        Err(e) => println!("{}", e.to_string()),
    }
}

fn handle_enable(feature: &str, force: bool) {
    match feature {
        "language" => {
            let ext_dir = get_extension_dir();
            if ext_dir.exists() && !force {
                println!("ilm extension already installed at {:?}. Use 'milaf -e language --force' to reinstall.", ext_dir);
            } else {
                if force && ext_dir.exists() {
                    std::fs::remove_dir_all(&ext_dir).unwrap_or_else(|e| eprintln!("Failed to remove existing extension: {}", e));
                }
                match highlighter::initialize_highlighting() {
                    Ok(()) => println!("ilm language support enabled successfully! Restart VS Code to apply."),
                    Err(e) => eprintln!("Failed to enable language support: {}", e),
                }
            }
        }
        other => eprintln!("Unknown feature '{}'. Supported: 'language'", other),
    }
}

fn is_extension_installed() -> bool {
    get_extension_dir().exists()
}

fn get_extension_dir() -> PathBuf {
    let mut ext_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
    ext_dir.push(".vscode");
    ext_dir.push("extensions");
    ext_dir.push(format!("besaoct.ilm-{}", env!("CARGO_PKG_VERSION")));
    ext_dir
}