use crate::plugin::{DocumentPlugin, PluginContext, PluginMeta};
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::HashMap;
lazy_static! {
static ref CONTAINER_RE: Regex = Regex::new(r":::(\w+)\s*\n([\s\S]*?)\n:::").unwrap();
}
#[derive(Debug, Clone)]
pub struct ContainerConfig {
pub containers: Vec<String>,
pub custom_containers: HashMap<String, ContainerOptions>,
pub default_icons: bool,
}
#[derive(Debug, Clone)]
pub struct ContainerOptions {
pub title: Option<String>,
pub icon: Option<String>,
pub class: Option<String>,
}
impl Default for ContainerConfig {
fn default() -> Self {
Self { containers: vec!["tip".to_string(), "warning".to_string(), "danger".to_string(), "info".to_string()], custom_containers: HashMap::new(), default_icons: true }
}
}
pub struct ContainerPlugin {
meta: PluginMeta,
config: ContainerConfig,
}
impl ContainerPlugin {
pub fn new() -> Self {
Self { meta: PluginMeta::new("nargo-document-plugin-container".to_string(), "0.1.0".to_string(), "自定义容器插件,提供信息提示、警告提示等容器组件".to_string()), config: ContainerConfig::default() }
}
pub fn with_config(config: ContainerConfig) -> Self {
Self { meta: PluginMeta::new("nargo-document-plugin-container".to_string(), "0.1.0".to_string(), "自定义容器插件,提供信息提示、警告提示等容器组件".to_string()), config }
}
fn process_containers(&self, content: &str) -> String {
CONTAINER_RE
.replace_all(content, |caps: ®ex::Captures| {
let container_type = &caps[1];
let inner_content = &caps[2];
let options = self.config.custom_containers.get(container_type);
let class_name = options.and_then(|o| o.class.clone()).unwrap_or_else(|| format!("container-{}", container_type));
let mut html = String::new();
html.push_str(&format!("<div class=\"{}\">", class_name));
if let Some(options) = options {
if let Some(title) = &options.title {
html.push_str(&format!("<div class=\"container-title\">{}</div>", title));
}
}
html.push_str(&format!("<div class=\"container-content\">{}</div>", inner_content.trim()));
html.push_str("</div>");
html
})
.to_string()
}
}
impl Default for ContainerPlugin {
fn default() -> Self {
Self::new()
}
}
impl DocumentPlugin for ContainerPlugin {
fn meta(&self) -> &PluginMeta {
&self.meta
}
fn before_render(&self, context: PluginContext) -> PluginContext {
let content = self.process_containers(&context.content);
PluginContext { content, frontmatter: context.frontmatter, path: context.path }
}
}