streamdown_plugin/
builtin.rs1use crate::{latex::LatexPlugin, Plugin};
9use std::path::Path;
10
11pub fn builtin_plugins() -> Vec<Box<dyn Plugin>> {
15 vec![Box::new(LatexPlugin::new())]
16}
17
18#[derive(Debug, Clone)]
20pub struct PluginInfo {
21 pub name: &'static str,
23 pub description: &'static str,
25 pub default_enabled: bool,
27 pub priority: i32,
29}
30
31pub fn builtin_plugin_info() -> Vec<PluginInfo> {
33 vec![PluginInfo {
34 name: "latex",
35 description: "Converts LaTeX math expressions ($$ or $) to Unicode",
36 default_enabled: true,
37 priority: 10,
38 }]
39}
40
41pub fn create_plugin(name: &str) -> Option<Box<dyn Plugin>> {
47 match name {
48 "latex" => Some(Box::new(LatexPlugin::new())),
49 _ => None,
50 }
51}
52
53pub fn discover_plugins(_config_dir: &Path) -> Vec<Box<dyn Plugin>> {
67 vec![]
70}
71
72#[derive(Debug, Clone, Default)]
74pub struct PluginFilter {
75 pub include: Vec<String>,
77 pub exclude: Vec<String>,
79}
80
81impl PluginFilter {
82 pub fn all() -> Self {
84 Self::default()
85 }
86
87 pub fn none() -> Self {
89 Self {
90 include: vec![],
91 exclude: vec!["*".to_string()],
92 }
93 }
94
95 pub fn only(names: Vec<String>) -> Self {
97 Self {
98 include: names,
99 exclude: vec![],
100 }
101 }
102
103 pub fn should_load(&self, name: &str) -> bool {
105 if self.exclude.contains(&"*".to_string()) {
107 return self.include.iter().any(|n| n == name);
108 }
109 if self.exclude.iter().any(|n| n == name) {
110 return false;
111 }
112
113 if self.include.is_empty() {
115 return true;
116 }
117 self.include.iter().any(|n| n == name)
118 }
119}
120
121pub fn load_builtin_plugins(filter: &PluginFilter) -> Vec<Box<dyn Plugin>> {
123 builtin_plugin_info()
124 .iter()
125 .filter(|info| filter.should_load(info.name))
126 .filter_map(|info| create_plugin(info.name))
127 .collect()
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_builtin_plugins() {
136 let plugins = builtin_plugins();
137 assert!(!plugins.is_empty());
138
139 let names: Vec<_> = plugins.iter().map(|p| p.name()).collect();
141 assert!(names.contains(&"latex"));
142 }
143
144 #[test]
145 fn test_builtin_plugin_info() {
146 let info = builtin_plugin_info();
147 assert!(!info.is_empty());
148
149 let latex_info = info.iter().find(|i| i.name == "latex");
150 assert!(latex_info.is_some());
151 assert!(latex_info.unwrap().default_enabled);
152 }
153
154 #[test]
155 fn test_create_plugin() {
156 let latex = create_plugin("latex");
157 assert!(latex.is_some());
158 assert_eq!(latex.unwrap().name(), "latex");
159
160 let unknown = create_plugin("unknown");
161 assert!(unknown.is_none());
162 }
163
164 #[test]
165 fn test_discover_plugins() {
166 let plugins = discover_plugins(Path::new("/tmp"));
168 assert!(plugins.is_empty());
169 }
170
171 #[test]
172 fn test_plugin_filter_all() {
173 let filter = PluginFilter::all();
174 assert!(filter.should_load("latex"));
175 assert!(filter.should_load("any"));
176 }
177
178 #[test]
179 fn test_plugin_filter_none() {
180 let filter = PluginFilter::none();
181 assert!(!filter.should_load("latex"));
182 assert!(!filter.should_load("any"));
183 }
184
185 #[test]
186 fn test_plugin_filter_only() {
187 let filter = PluginFilter::only(vec!["latex".to_string()]);
188 assert!(filter.should_load("latex"));
189 assert!(!filter.should_load("other"));
190 }
191
192 #[test]
193 fn test_plugin_filter_exclude() {
194 let mut filter = PluginFilter::all();
195 filter.exclude.push("latex".to_string());
196 assert!(!filter.should_load("latex"));
197 assert!(filter.should_load("other"));
198 }
199
200 #[test]
201 fn test_load_builtin_plugins() {
202 let filter = PluginFilter::all();
203 let plugins = load_builtin_plugins(&filter);
204 assert!(!plugins.is_empty());
205
206 let filter = PluginFilter::none();
207 let plugins = load_builtin_plugins(&filter);
208 assert!(plugins.is_empty());
209 }
210}