model-rs 0.1.0

A Rust CLI tool for downloading HuggingFace models and running local LLM inference
use syntect::easy::HighlightLines;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::{SyntaxReference, SyntaxSet};
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};

pub struct CodeHighlighter<'a> {
    syntax_set: &'a SyntaxSet,
    highlighter: HighlightLines<'a>,
}

impl<'a> CodeHighlighter<'a> {
    pub fn new(
        syntax_set: &'a SyntaxSet,
        syntax: &'a SyntaxReference,
        theme: &'a syntect::highlighting::Theme,
    ) -> Self {
        Self {
            syntax_set,
            highlighter: HighlightLines::new(syntax, theme),
        }
    }

    pub fn write(&mut self, code: &str) {
        for line in LinesWithEndings::from(code) {
            let ranges: Vec<(Style, &str)> = self
                .highlighter
                .highlight_line(line, self.syntax_set)
                .unwrap_or_default();
            let escaped = as_24_bit_terminal_escaped(&ranges[..], true);
            print!("{}", escaped);
        }
        print!("\x1b[0m");
    }

    pub fn finish_line(&mut self) {
        println!();
    }
}

pub fn resolve_syntax<'a>(syntax_set: &'a SyntaxSet, language: &str) -> &'a SyntaxReference {
    let lang = language.trim();
    if lang.is_empty() {
        return syntax_set.find_syntax_plain_text();
    }

    let lang_lc = lang.to_ascii_lowercase();
    let ext = match lang_lc.as_str() {
        "py" | "python" => "py",
        "rs" | "rust" => "rs",
        "js" | "javascript" => "js",
        "ts" | "typescript" => "ts",
        "sh" | "bash" | "shell" => "sh",
        "yml" | "yaml" => "yml",
        "md" | "markdown" => "md",
        "json" => "json",
        "toml" => "toml",
        _ => lang_lc.as_str(),
    };

    syntax_set
        .find_syntax_by_extension(ext)
        .or_else(|| syntax_set.find_syntax_by_extension(&lang_lc))
        .or_else(|| {
            syntax_set
                .syntaxes()
                .iter()
                .find(|s| s.name.to_ascii_lowercase() == lang_lc)
        })
        .unwrap_or_else(|| syntax_set.find_syntax_plain_text())
}

pub fn resolve_theme(theme_set: &ThemeSet) -> &syntect::highlighting::Theme {
    let theme_name = if theme_set.themes.contains_key("Dark+ (default dark)") {
        "Dark+ (default dark)"
    } else if theme_set.themes.contains_key("Monokai Extended") {
        "Monokai Extended"
    } else if theme_set.themes.contains_key("base16-ocean.dark") {
        "base16-ocean.dark"
    } else {
        theme_set
            .themes
            .keys()
            .next()
            .map(|s| s.as_str())
            .unwrap_or("base16-ocean.dark")
    };

    theme_set
        .themes
        .get(theme_name)
        .unwrap_or_else(|| &theme_set.themes["base16-ocean.dark"])
}