1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! Composite syntax driver factory.
//!
//! Routes `create()` calls to the correct factory by language ID.
//! This replaces the single-factory limitation in bootstrap where
//! only the first registered factory was used.
use std::sync::Arc;
use crate::{SyntaxDriver, SyntaxDriverFactory};
/// A factory that aggregates multiple [`SyntaxDriverFactory`] instances.
///
/// When `create()` is called, it iterates the inner factories in registration
/// order and returns the first successful result. This allows multiple
/// language-specific factories (e.g., Rust + Markdown) to coexist.
///
/// # Example
///
/// ```ignore
/// let composite = CompositeFactory::new(vec![
/// Arc::new(RustSyntaxFactory::new()),
/// Arc::new(MarkdownSyntaxFactory::new()),
/// ]);
/// assert!(composite.supports("rust"));
/// assert!(composite.supports("markdown"));
/// ```
pub struct CompositeFactory {
factories: Vec<Arc<dyn SyntaxDriverFactory>>,
}
impl CompositeFactory {
/// Create a composite from a list of factories.
#[must_use]
pub fn new(factories: Vec<Arc<dyn SyntaxDriverFactory>>) -> Self {
Self { factories }
}
/// Get the number of inner factories.
#[must_use]
pub fn factory_count(&self) -> usize {
self.factories.len()
}
}
impl SyntaxDriverFactory for CompositeFactory {
fn create(&self, language_id: &str) -> Option<Box<dyn SyntaxDriver>> {
for factory in &self.factories {
if let Some(driver) = factory.create(language_id) {
return Some(driver);
}
}
None
}
fn supported_languages(&self) -> Vec<&str> {
let mut languages = Vec::new();
for factory in &self.factories {
for lang in factory.supported_languages() {
if !languages.contains(&lang) {
languages.push(lang);
}
}
}
languages
}
fn supports(&self, language_id: &str) -> bool {
self.factories.iter().any(|f| f.supports(language_id))
}
}
impl std::fmt::Debug for CompositeFactory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompositeFactory")
.field("factory_count", &self.factories.len())
.field("languages", &self.supported_languages())
.finish()
}
}
#[cfg(test)]
#[path = "composite_tests.rs"]
mod tests;