comfit_core/engine.rs
1//! Register languages and highlight source code, including embedded languages.
2
3use crate::{
4 Error, HighlightConfig, Highlighted, backend::Backend, document::Document, highlight,
5 language::Registry,
6};
7
8pub use crate::language::Queries;
9
10/// A highlighter with a parser backend and a language registry.
11///
12/// Queries are compiled during registration or on first use, then reused.
13/// Results borrow the source and capture names, not the temporary syntax trees.
14/// One-shot highlighting releases each layer's tree before parsing the next layer.
15pub struct Highlighter<B: Backend> {
16 backend: B,
17 registry: Registry<B>,
18}
19
20impl<B: Backend> Highlighter<B> {
21 /// Create an empty registry using the supplied backend.
22 pub fn new(backend: B) -> Self {
23 Self {
24 backend,
25 registry: Registry::new(),
26 }
27 }
28
29 /// Register a language and compile its queries.
30 ///
31 /// IDs and aliases share one namespace. Registration leaves the registry unchanged
32 /// if validation or compilation fails. Query sources are borrowed only during loading.
33 ///
34 /// # Errors
35 ///
36 /// Returns [`Error::DuplicateLanguage`] for empty or conflicting names, or a
37 /// backend/query error if compilation fails.
38 pub fn load(
39 &mut self,
40 id: &str,
41 aliases: &[&str],
42 language: B::Language,
43 queries: Queries<'_>,
44 ) -> Result<(), Error> {
45 self.registry
46 .load(&mut self.backend, id, aliases, language, queries)
47 }
48
49 /// Register static queries to compile when the language is first used.
50 /// Documents share uncompiled query sources and compiled queries with this registry.
51 /// Query compilation errors are reported when the language is first used.
52 ///
53 /// # Errors
54 ///
55 /// Returns [`Error::DuplicateLanguage`] for empty or conflicting names.
56 pub fn load_lazy(
57 &mut self,
58 id: &str,
59 aliases: &[&str],
60 language: B::Language,
61 queries: Queries<'static>,
62 ) -> Result<(), Error> {
63 self.registry.load_lazy(id, aliases, language, queries)
64 }
65
66 /// Return whether a language ID or alias is registered.
67 pub fn contains(&self, name: &str) -> bool {
68 self.registry.get(name).is_some()
69 }
70
71 /// Highlight source text using a registered language ID or alias.
72 ///
73 /// Injections into unregistered languages are skipped. Each syntax layer is parsed
74 /// once. Results borrow the source and capture names from this registry.
75 ///
76 /// # Errors
77 ///
78 /// Returns an error for an unloaded root language, a parser or query failure, an
79 /// invalid UTF-8 range, or injection nesting beyond 32 layers.
80 pub fn highlight<'a>(
81 &'a mut self,
82 source: &'a str,
83 name: &str,
84 config: &HighlightConfig,
85 ) -> Result<Highlighted<'a>, Error> {
86 highlight::source(&mut self.backend, &self.registry, source, name, config)
87 }
88
89 /// Create an independent document using a fresh backend and shared compiled queries.
90 pub fn create_document(
91 &self,
92 name: &str,
93 source: &str,
94 backend: B,
95 ) -> Result<Document<B>, Error> {
96 Document::new(self.registry.clone(), backend, name, source)
97 }
98}