nargo_document/plugin/
container.rs1use crate::plugin::{DocumentPlugin, PluginContext, PluginMeta};
6use lazy_static::lazy_static;
7use regex::Regex;
8use std::collections::HashMap;
9
10lazy_static! {
11 static ref CONTAINER_RE: Regex = Regex::new(r":::(\w+)\s*\n([\s\S]*?)\n:::").unwrap();
13}
14
15#[derive(Debug, Clone)]
17pub struct ContainerConfig {
18 pub containers: Vec<String>,
20 pub custom_containers: HashMap<String, ContainerOptions>,
22 pub default_icons: bool,
24}
25
26#[derive(Debug, Clone)]
28pub struct ContainerOptions {
29 pub title: Option<String>,
31 pub icon: Option<String>,
33 pub class: Option<String>,
35}
36
37impl Default for ContainerConfig {
38 fn default() -> Self {
39 Self { containers: vec!["tip".to_string(), "warning".to_string(), "danger".to_string(), "info".to_string()], custom_containers: HashMap::new(), default_icons: true }
40 }
41}
42
43pub struct ContainerPlugin {
45 meta: PluginMeta,
47 config: ContainerConfig,
49}
50
51impl ContainerPlugin {
52 pub fn new() -> Self {
54 Self { meta: PluginMeta::new("nargo-document-plugin-container".to_string(), "0.1.0".to_string(), "自定义容器插件,提供信息提示、警告提示等容器组件".to_string()), config: ContainerConfig::default() }
55 }
56
57 pub fn with_config(config: ContainerConfig) -> Self {
63 Self { meta: PluginMeta::new("nargo-document-plugin-container".to_string(), "0.1.0".to_string(), "自定义容器插件,提供信息提示、警告提示等容器组件".to_string()), config }
64 }
65
66 fn process_containers(&self, content: &str) -> String {
76 CONTAINER_RE
77 .replace_all(content, |caps: ®ex::Captures| {
78 let container_type = &caps[1];
79 let inner_content = &caps[2];
80
81 let options = self.config.custom_containers.get(container_type);
82 let class_name = options.and_then(|o| o.class.clone()).unwrap_or_else(|| format!("container-{}", container_type));
83
84 let mut html = String::new();
85 html.push_str(&format!("<div class=\"{}\">", class_name));
86
87 if let Some(options) = options {
88 if let Some(title) = &options.title {
89 html.push_str(&format!("<div class=\"container-title\">{}</div>", title));
90 }
91 }
92
93 html.push_str(&format!("<div class=\"container-content\">{}</div>", inner_content.trim()));
94 html.push_str("</div>");
95
96 html
97 })
98 .to_string()
99 }
100}
101
102impl Default for ContainerPlugin {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108impl DocumentPlugin for ContainerPlugin {
109 fn meta(&self) -> &PluginMeta {
111 &self.meta
112 }
113
114 fn before_render(&self, context: PluginContext) -> PluginContext {
124 let content = self.process_containers(&context.content);
125
126 PluginContext { content, frontmatter: context.frontmatter, path: context.path }
127 }
128}