Skip to main content

nargo_document/plugin/
prism.rs

1//! Prism 代码高亮插件
2//!
3//! 提供对 Markdown 中代码块的 Prism 语法高亮支持
4
5use crate::plugin::{DocumentPlugin, PluginContext, PluginMeta};
6use lazy_static::lazy_static;
7use regex::Regex;
8
9lazy_static! {
10    /// 匹配代码块的正则表达式,支持带语言标识
11    static ref CODE_BLOCK_RE: Regex = Regex::new(r"```([a-zA-Z0-9_]*)\s*\n([\s\S]*?)\n```").unwrap();
12}
13
14/// Prism 代码高亮插件
15pub struct PrismPlugin {
16    /// 插件元数据
17    meta: PluginMeta,
18}
19
20impl PrismPlugin {
21    /// 创建新的 Prism 插件实例
22    pub fn new() -> Self {
23        Self { meta: PluginMeta::new("nargo-document-plugin-prism".to_string(), "0.1.0".to_string(), "Prism 代码高亮插件,提供代码块语法高亮功能".to_string()) }
24    }
25
26    /// 处理代码块,将 ```lang ... ``` 替换为 <pre class="language-lang"><code class="language-lang">...</code></pre>
27    ///
28    /// # Arguments
29    ///
30    /// * `content` - 包含代码块的文本内容
31    ///
32    /// # Returns
33    ///
34    /// 替换后的文本内容
35    fn process_code_blocks(&self, content: &str) -> String {
36        CODE_BLOCK_RE
37            .replace_all(content, |caps: &regex::Captures| {
38                let lang = caps.get(1).map_or("", |m| m.as_str());
39                let code = &caps[2];
40                if lang.is_empty() {
41                    format!("<pre><code>{}</code></pre>", code.trim())
42                }
43                else {
44                    format!("<pre class=\"language-{}\"><code class=\"language-{}\">{}</code></pre>", lang, lang, code.trim())
45                }
46            })
47            .to_string()
48    }
49}
50
51impl Default for PrismPlugin {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl DocumentPlugin for PrismPlugin {
58    /// 获取插件元数据
59    fn meta(&self) -> &PluginMeta {
60        &self.meta
61    }
62
63    /// 渲染前钩子,在 Markdown 解析后、HTML 渲染前处理代码块
64    ///
65    /// # Arguments
66    ///
67    /// * `context` - 插件上下文,包含文档内容等信息
68    ///
69    /// # Returns
70    ///
71    /// 处理后的插件上下文
72    fn before_render(&self, context: PluginContext) -> PluginContext {
73        let content = self.process_code_blocks(&context.content);
74
75        PluginContext { content, frontmatter: context.frontmatter, path: context.path }
76    }
77}