Skip to main content

reovim_driver_syntax/
composite.rs

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