leetcli 0.1.6

A CLI tool that generates random LeetCode problems with skeleton code using AI
use anyhow::Result;
use std::fs;
use std::path::Path;
use regex::Regex;

pub fn extract_problem_name(content: &str) -> String {
    let comment_patterns = vec![
        Regex::new(r"^//\s*(.+)$").unwrap(),
        Regex::new(r"^#\s*(.+)$").unwrap(),
    ];
    
    for line in content.lines().take(5) {
        let trimmed = line.trim();
        if trimmed.is_empty() { continue; }
        
        for pattern in &comment_patterns {
            if let Some(captures) = pattern.captures(trimmed) {
                if let Some(title) = captures.get(1) {
                    let title_str = title.as_str().trim();
                    
                    if title_str.len() > 3 && title_str.len() < 60 {
                        return title_str
                            .to_lowercase()
                            .replace(" ", "_")
                            .replace("-", "_")
                            .chars()
                            .filter(|c| c.is_alphanumeric() || *c == '_')
                            .collect();
                    }
                }
            }
        }
    }
    
    "unknown_problem".to_string()
}

pub fn create_problem_file(content: &str, language: &str) -> Result<String> {
    let extension = match language {
        "Rust" => "rs",
        "Python" | "Python3" => "py",
        "JavaScript" => "js",
        "Java" => "java",
        "C++" => "cpp",
        "C" => "c",
        "Go" => "go",
        "TypeScript" => "ts",
        "C#" | "Csharp" => "cs",
        "PHP" => "php",
        "Ruby" => "rb",
        "Swift" => "swift",
        "Kotlin" => "kt",
        "Scala" => "scala",
        "Perl" => "pl",
        "R" => "r",
        "MATLAB" => "m",
        "Dart" => "dart",
        "Elixir" => "ex",
        "Erlang" => "erl",
        "Clojure" => "clj",
        "Haskell" => "hs",
        "OCaml" => "ml",
        "F#" => "fs",
        "Lua" => "lua",
        "Shell" | "Bash" => "sh",
        "PowerShell" => "ps1",
        "SQL" => "sql",
        "HTML" => "html",
        "CSS" => "css",
        "SCSS" => "scss",
        "SASS" => "sass",
        "LESS" => "less",
        "JSON" => "json",
        "XML" => "xml",
        "YAML" => "yml",
        "TOML" => "toml",
        "Vim script" => "vim",
        "Assembly" => "asm",
        "COBOL" => "cob",
        "Fortran" => "f90",
        "Pascal" => "pas",
        "Delphi" => "pas",
        "Ada" => "adb",
        "Lisp" => "lisp",
        "Scheme" => "scm",
        "Prolog" => "pro",
        "Groovy" => "groovy",
        "Visual Basic" => "vb",
        "Objective-C" => "m",
        "D" => "d",
        "Nim" => "nim",
        "Crystal" => "cr",
        "Zig" => "zig",
        "V" => "v",
        "Julia" => "jl",
        "Racket" => "rkt",
        "Smalltalk" => "st",
        "Tcl" => "tcl",
        "AWK" => "awk",
        "SED" => "sed",
        "Makefile" => "mk",
        "CMake" => "cmake",
        "Dockerfile" => "dockerfile",
        "LaTeX" => "tex",
        "Markdown" => "md",
        "ReStructuredText" => "rst",
        "AsciiDoc" => "adoc",
        "GraphQL" => "graphql",
        "Solidity" => "sol",
        "VHDL" => "vhd",
        "Verilog" => "ver",
        "SystemVerilog" => "sv",
        "CUDA" => "cu",
        "OpenCL" => "cl",
        "HLSL" => "hlsl",
        "GLSL" => "glsl",
        "CoffeeScript" => "coffee",
        "LiveScript" => "ls",
        "PureScript" => "purs",
        "Elm" => "elm",
        "Reason" => "re",
        "ReScript" => "res",
        "Idris" => "idr",
        "Agda" => "agda",
        "Coq" => "v",
        "Lean" => "lean",
        "APL" => "apl",
        "J" => "ijs",
        "K" => "k",
        "Q" => "q",
        "BrainF*ck" => "bf",
        "Whitespace" => "ws",
        "Malbolge" => "mal",
        "Befunge" => "bf",
        "INTERCAL" => "i",
        _ => "txt"
    };

    let problem_name = extract_problem_name(content);
    let filename = format!("{}.{}", problem_name, extension);
    
    if !Path::new("problems").exists() {
        fs::create_dir("problems")?;
    }
    
    let filepath = format!("problems/{}", filename);
    fs::write(&filepath, content)?;
    
    Ok(filepath)
}