Skip to main content

editor_core_treesitter/
loader.rs

1use crate::{
2    TreeSitterConfig, TreeSitterIndenterConfig, TreeSitterLanguage, TreeSitterProcessorConfig,
3};
4
5/// Errors produced when loading Tree-sitter WASM and query files from disk.
6#[derive(Debug)]
7pub enum TreeSitterLoadError {
8    /// I/O error while reading a required file.
9    Io(String),
10    /// A required file was not valid UTF-8.
11    InvalidUtf8(String),
12}
13
14impl std::fmt::Display for TreeSitterLoadError {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        match self {
17            Self::Io(msg) => write!(f, "tree-sitter load io error: {msg}"),
18            Self::InvalidUtf8(msg) => write!(f, "tree-sitter load utf-8 error: {msg}"),
19        }
20    }
21}
22
23impl std::error::Error for TreeSitterLoadError {}
24
25/// Load a [`TreeSitterProcessorConfig`] from a file-based [`TreeSitterConfig`].
26///
27/// This reads:
28/// - the WASM grammar bytes
29/// - `highlights.scm`
30/// - optionally `folds.scm`
31pub fn load_processor_config_from_config(
32    language_id: &str,
33    config: &TreeSitterConfig,
34) -> Result<TreeSitterProcessorConfig, TreeSitterLoadError> {
35    let wasm_bytes = std::fs::read(&config.wasm_path)
36        .map_err(|e| TreeSitterLoadError::Io(format!("{}: {e}", config.wasm_path.display())))?;
37
38    let highlights_query = std::fs::read_to_string(&config.highlights_path).map_err(|e| {
39        if e.kind() == std::io::ErrorKind::InvalidData {
40            TreeSitterLoadError::InvalidUtf8(format!("{}: {e}", config.highlights_path.display()))
41        } else {
42            TreeSitterLoadError::Io(format!("{}: {e}", config.highlights_path.display()))
43        }
44    })?;
45
46    let mut out = TreeSitterProcessorConfig::new(
47        TreeSitterLanguage::wasm(language_id.to_string(), wasm_bytes),
48        highlights_query,
49    );
50
51    if let Some(folds_path) = &config.folds_path {
52        let folds_query = std::fs::read_to_string(folds_path).map_err(|e| {
53            if e.kind() == std::io::ErrorKind::InvalidData {
54                TreeSitterLoadError::InvalidUtf8(format!("{}: {e}", folds_path.display()))
55            } else {
56                TreeSitterLoadError::Io(format!("{}: {e}", folds_path.display()))
57            }
58        })?;
59        if !folds_query.trim().is_empty() {
60            out = out.with_folds_query(folds_query);
61        }
62    }
63
64    Ok(out)
65}
66
67/// Load a [`TreeSitterIndenterConfig`] from a file-based [`TreeSitterConfig`], if available.
68///
69/// This reads:
70/// - the WASM grammar bytes
71/// - `indents.scm` (optional; returns `Ok(None)` when missing)
72pub fn load_indenter_config_from_config(
73    language_id: &str,
74    config: &TreeSitterConfig,
75) -> Result<Option<TreeSitterIndenterConfig>, TreeSitterLoadError> {
76    let Some(indents_path) = &config.indents_path else {
77        return Ok(None);
78    };
79
80    let wasm_bytes = std::fs::read(&config.wasm_path)
81        .map_err(|e| TreeSitterLoadError::Io(format!("{}: {e}", config.wasm_path.display())))?;
82
83    let indents_query = std::fs::read_to_string(indents_path).map_err(|e| {
84        if e.kind() == std::io::ErrorKind::InvalidData {
85            TreeSitterLoadError::InvalidUtf8(format!("{}: {e}", indents_path.display()))
86        } else {
87            TreeSitterLoadError::Io(format!("{}: {e}", indents_path.display()))
88        }
89    })?;
90
91    Ok(Some(TreeSitterIndenterConfig::new(
92        TreeSitterLanguage::wasm(language_id.to_string(), wasm_bytes),
93        indents_query,
94    )))
95}