Skip to main content

reovim_driver_syntax/
driver.rs

1//! Syntax driver trait definition.
2//!
3//! This module defines the [`SyntaxDriver`] trait, the main interface for
4//! syntax highlighting implementations. Implementations handle parsing and
5//! highlighting for specific languages.
6
7use std::{ops::Range, sync::Arc};
8
9use crate::{
10    edit::SyntaxEdit,
11    factory::SyntaxDriverFactory,
12    fold::FoldRange,
13    highlight::{Annotation, SyntaxContext},
14    injection::Injection,
15    scope::ContextHierarchy,
16    textobject::{TextObjectKind, TextObjectRange, TextObjectScope},
17};
18
19/// Main parsing interface for syntax highlighting.
20///
21/// Implementors provide language-specific parsing and highlighting.
22/// This trait is designed to be parser-agnostic - tree-sitter is just
23/// one possible implementation.
24///
25/// # Lifecycle
26///
27/// 1. Create driver via [`SyntaxDriverFactory`](crate::SyntaxDriverFactory)
28/// 2. Call [`parse()`](Self::parse) with initial content
29/// 3. Call [`update()`](Self::update) for incremental edits
30/// 4. Call [`highlights()`](Self::highlights) to get highlights for rendering
31///
32/// # Thread Safety
33///
34/// Implementations must be `Send + Sync` to allow use across threads.
35/// The driver may be shared between multiple views of the same buffer.
36///
37/// # Example
38///
39/// ```ignore
40/// // Get driver from factory
41/// let mut driver = factory.create("rust")?;
42///
43/// // Initial parse
44/// driver.parse("fn main() {}");
45/// assert!(driver.is_parsed());
46///
47/// // Get highlights for visible range
48/// let highlights = driver.highlights(0..100);
49///
50/// // After edit, update incrementally
51/// driver.update("fn main() { println!(); }", &edit);
52/// ```
53pub trait SyntaxDriver: Send + Sync {
54    /// Get the language identifier.
55    ///
56    /// Returns a unique identifier like "rust", "python", "javascript".
57    /// This should match the language ID used to create the driver.
58    fn language(&self) -> &str;
59
60    /// Perform a full parse of the content.
61    ///
62    /// Called on initial file open or when incremental update isn't possible.
63    /// After calling this, [`is_parsed()`](Self::is_parsed) should return true.
64    fn parse(&mut self, content: &str);
65
66    /// Apply an incremental edit.
67    ///
68    /// For efficient re-parsing after buffer modifications.
69    /// The edit describes what changed; the driver updates its internal state.
70    ///
71    /// # Arguments
72    ///
73    /// * `content` - The new full content after the edit
74    /// * `edit` - Description of what changed
75    fn update(&mut self, content: &str, edit: &SyntaxEdit);
76
77    /// Get annotations for a byte range.
78    ///
79    /// Returns all annotations that overlap with the given range.
80    /// Results should be sorted by start position.
81    ///
82    /// # Arguments
83    ///
84    /// * `byte_range` - The byte range to get annotations for
85    ///
86    /// # Returns
87    ///
88    /// A vector of annotations overlapping the requested range.
89    fn highlights(&self, byte_range: Range<usize>) -> Vec<Annotation>;
90
91    /// Get language injection points.
92    ///
93    /// Returns regions where a different language should be highlighted.
94    /// Used for embedded languages (markdown code blocks, HTML scripts, etc.).
95    ///
96    /// # Default
97    ///
98    /// Returns an empty vector. Override for languages that support injections.
99    fn injections(&self) -> Vec<Injection> {
100        Vec::new()
101    }
102
103    /// Get decoration annotations for a byte range.
104    ///
105    /// Returns annotations from decoration queries (e.g., markdown heading
106    /// markers, list bullets, code blocks). These carry semantic categories
107    /// like `markup.heading.1` that clients map to render behaviors.
108    /// Use-sites call this separately from [`highlights()`](Self::highlights)
109    /// to opt in to decoration rendering.
110    ///
111    /// # Default
112    ///
113    /// Returns an empty vector. Override for languages with decoration support.
114    fn decorations(&self, _byte_range: Range<usize>) -> Vec<Annotation> {
115        Vec::new()
116    }
117
118    /// Get foldable ranges.
119    ///
120    /// Returns all foldable regions in the document.
121    ///
122    /// # Default
123    ///
124    /// Returns an empty vector. Override to provide folding support.
125    fn folds(&self) -> Vec<FoldRange> {
126        Vec::new()
127    }
128
129    /// Get suggested indentation for a line.
130    ///
131    /// Returns the suggested indent level (in spaces) for a given line,
132    /// or None if indentation cannot be determined.
133    ///
134    /// # Arguments
135    ///
136    /// * `line` - The 0-indexed line number
137    ///
138    /// # Default
139    ///
140    /// Returns None. Override to provide indentation hints.
141    fn indent_for(&self, _line: usize) -> Option<usize> {
142        None
143    }
144
145    /// Configure injection support with the given factory.
146    ///
147    /// Called by the runtime after driver creation to enable recursive
148    /// injection highlighting. Implementations that support injections
149    /// use this factory to create child drivers for embedded languages.
150    ///
151    /// # Default
152    ///
153    /// No-op. Override for drivers that support injection highlighting.
154    fn set_injection_factory(&mut self, _factory: Arc<dyn SyntaxDriverFactory>) {}
155
156    /// Set the injection nesting depth for this driver.
157    ///
158    /// Used to propagate depth through the injection hierarchy so that
159    /// `MAX_INJECTION_DEPTH` is correctly enforced. Depth 0 = root driver,
160    /// depth 1 = direct child, etc.
161    ///
162    /// # Default
163    ///
164    /// No-op. Override for drivers that support injection highlighting.
165    fn set_injection_depth(&mut self, _depth: u8) {}
166
167    /// Set the default injection language for bare code blocks.
168    ///
169    /// When a child driver encounters an injection region with no explicit
170    /// language tag (e.g., bare ` ``` ` in Markdown), it falls back to this
171    /// value. The injection pipeline sets this to the parent driver's
172    /// language ID, so bare fences in Rust doc comments default to Rust,
173    /// bare fences in Python docstrings default to Python, etc.
174    ///
175    /// # Default
176    ///
177    /// No-op. Override for drivers that support injection highlighting.
178    fn set_default_injection_language(&mut self, _language: &str) {}
179
180    /// Get the enclosing scope hierarchy at a position.
181    ///
182    /// Returns the scope boundaries (function, class, module, etc.)
183    /// that contain the given line and column. Items are ordered
184    /// outermost-first.
185    ///
186    /// # Arguments
187    ///
188    /// * `line` - 0-indexed line number
189    /// * `col` - 0-indexed column number
190    ///
191    /// # Default
192    ///
193    /// Returns an empty hierarchy. Override for scope-aware behavior.
194    fn scopes(&self, _line: u32, _col: u32) -> ContextHierarchy {
195        ContextHierarchy::empty()
196    }
197
198    /// Get the syntax context at a byte position.
199    ///
200    /// Returns the syntactic context (code, string, comment) at the given
201    /// byte offset. Used by features like auto-pair to skip insertion
202    /// inside strings or comments.
203    ///
204    /// # Default
205    ///
206    /// Returns `SyntaxContext::Code`. Override for context-aware behavior.
207    #[cfg_attr(coverage_nightly, coverage(off))]
208    fn context_at_byte(&self, _byte_offset: usize) -> SyntaxContext {
209        SyntaxContext::Code
210    }
211
212    /// Get the range of a semantic text object at a position.
213    ///
214    /// Resolves language-aware text objects like functions, classes, arguments,
215    /// etc. at the given cursor position. Returns the byte and position range
216    /// of the matching construct, or `None` if no match exists.
217    ///
218    /// # Arguments
219    ///
220    /// * `kind` - The type of text object (function, class, etc.)
221    /// * `scope` - Inner (body only) or outer (full construct)
222    /// * `line` - 0-indexed cursor line
223    /// * `col` - 0-indexed cursor column
224    ///
225    /// # Default
226    ///
227    /// Returns `None`. Override for drivers with treesitter query support.
228    #[cfg_attr(coverage_nightly, coverage(off))]
229    fn textobject_range(
230        &self,
231        _kind: TextObjectKind,
232        _scope: TextObjectScope,
233        _line: u32,
234        _col: u32,
235    ) -> Option<TextObjectRange> {
236        None
237    }
238
239    /// Check if the driver has valid parse state.
240    ///
241    /// Returns true if the driver has successfully parsed content.
242    /// This should return false before [`parse()`](Self::parse) is called,
243    /// and true after a successful parse.
244    fn is_parsed(&self) -> bool;
245}
246
247#[cfg(test)]
248#[path = "driver_tests.rs"]
249mod tests;