runmat-lsp 0.4.8

Language Server Protocol implementation for RunMat editors and tooling
use once_cell::sync::Lazy;
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::Mutex;

mod generated {
    include!(concat!(env!("OUT_DIR"), "/builtins_json_generated.rs"));
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocExample {
    pub description: String,
    pub input: String,
    pub output: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocFaq {
    pub question: String,
    pub answer: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocLink {
    pub label: String,
    pub url: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocGpuSupport {
    pub notes: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocJsonEncodeOption {
    pub name: String,
    #[serde(rename = "type")]
    pub type_name: String,
    pub default: String,
    pub description: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct BuiltinDocJson {
    pub title: Option<String>,
    pub category: Option<String>,
    #[allow(dead_code)]
    pub keywords: Option<Vec<String>>,
    pub summary: Option<String>,
    pub description: Option<String>,
    pub behaviors: Option<Vec<String>>,
    pub examples: Option<Vec<BuiltinDocExample>>,
    pub faqs: Option<Vec<BuiltinDocFaq>>,
    pub links: Option<Vec<BuiltinDocLink>>,
    pub gpu_support: Option<BuiltinDocGpuSupport>,
    pub gpu_residency: Option<String>,
    pub gpu_behavior: Option<Vec<String>>,
    pub options: Option<Vec<String>>,
    pub jsonencode_options: Option<Vec<BuiltinDocJsonEncodeOption>>,
}

static DOC_CACHE: Lazy<Mutex<HashMap<String, BuiltinDocJson>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

pub fn builtin_json_str(name: &str) -> Option<&'static str> {
    generated::builtin_json_by_name(name)
}

pub fn builtin_doc(name: &str) -> Option<BuiltinDocJson> {
    let key = name.to_ascii_lowercase();
    {
        let cache = DOC_CACHE.lock().ok()?;
        if let Some(doc) = cache.get(&key) {
            return Some(doc.clone());
        }
    }

    let json = builtin_json_str(&key)?;
    let parsed: BuiltinDocJson = serde_json::from_str(json).ok()?;

    if let Some(faqs) = &parsed.faqs {
        for faq in faqs {
            let _ = (&faq.question, &faq.answer);
        }
    }

    let mut cache = DOC_CACHE.lock().ok()?;
    cache.insert(key, parsed.clone());
    Some(parsed)
}