nargo-document 0.0.0

Nargo documentation tool
Documentation
//! Prism 代码高亮插件
//!
//! 提供对 Markdown 中代码块的 Prism 语法高亮支持

use crate::plugin::{DocumentPlugin, PluginContext, PluginMeta};
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    /// 匹配代码块的正则表达式,支持带语言标识
    static ref CODE_BLOCK_RE: Regex = Regex::new(r"```([a-zA-Z0-9_]*)\s*\n([\s\S]*?)\n```").unwrap();
}

/// Prism 代码高亮插件
pub struct PrismPlugin {
    /// 插件元数据
    meta: PluginMeta,
}

impl PrismPlugin {
    /// 创建新的 Prism 插件实例
    pub fn new() -> Self {
        Self { meta: PluginMeta::new("nargo-document-plugin-prism".to_string(), "0.1.0".to_string(), "Prism 代码高亮插件,提供代码块语法高亮功能".to_string()) }
    }

    /// 处理代码块,将 ```lang ... ``` 替换为 <pre class="language-lang"><code class="language-lang">...</code></pre>
    ///
    /// # Arguments
    ///
    /// * `content` - 包含代码块的文本内容
    ///
    /// # Returns
    ///
    /// 替换后的文本内容
    fn process_code_blocks(&self, content: &str) -> String {
        CODE_BLOCK_RE
            .replace_all(content, |caps: &regex::Captures| {
                let lang = caps.get(1).map_or("", |m| m.as_str());
                let code = &caps[2];
                if lang.is_empty() {
                    format!("<pre><code>{}</code></pre>", code.trim())
                }
                else {
                    format!("<pre class=\"language-{}\"><code class=\"language-{}\">{}</code></pre>", lang, lang, code.trim())
                }
            })
            .to_string()
    }
}

impl Default for PrismPlugin {
    fn default() -> Self {
        Self::new()
    }
}

impl DocumentPlugin for PrismPlugin {
    /// 获取插件元数据
    fn meta(&self) -> &PluginMeta {
        &self.meta
    }

    /// 渲染前钩子,在 Markdown 解析后、HTML 渲染前处理代码块
    ///
    /// # Arguments
    ///
    /// * `context` - 插件上下文,包含文档内容等信息
    ///
    /// # Returns
    ///
    /// 处理后的插件上下文
    fn before_render(&self, context: PluginContext) -> PluginContext {
        let content = self.process_code_blocks(&context.content);

        PluginContext { content, frontmatter: context.frontmatter, path: context.path }
    }
}