reovim_module_treesitter_bash/
lib.rs1#![cfg_attr(coverage_nightly, allow(unused_features))]
2#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
3use std::sync::Arc;
36
37use {
38 reovim_driver_syntax::{
39 CommentTokens, LanguageInfo, LanguageInfoStore, SyntaxDriver, SyntaxDriverFactory,
40 SyntaxFactoryStore,
41 },
42 reovim_driver_syntax_treesitter::{Language, Query, TreeSitterDriver},
43 reovim_kernel::api::v1::{Module, ModuleContext, ModuleError, ModuleId, ProbeResult, Version},
44};
45
46const BASH_HIGHLIGHTS_QUERY: &str = include_str!("queries/highlights.scm");
48
49const BASH_FOLDS_QUERY: &str = include_str!("queries/folds.scm");
51
52const BASH_CONTEXT_QUERY: &str = include_str!("queries/context.scm");
54
55#[allow(clippy::struct_field_names)]
60pub struct BashSyntaxFactory {
61 highlight_query: Arc<Query>,
63 folds_query: Arc<Query>,
65 context_query: Arc<Query>,
67}
68
69impl BashSyntaxFactory {
70 #[must_use]
79 pub fn new() -> Self {
80 let language: Language = tree_sitter_bash::LANGUAGE.into();
81
82 let highlight_query = Query::new(&language, BASH_HIGHLIGHTS_QUERY)
83 .expect("Failed to compile Bash highlights query");
84
85 let folds_query =
86 Query::new(&language, BASH_FOLDS_QUERY).expect("Failed to compile Bash folds query");
87
88 let context_query = Query::new(&language, BASH_CONTEXT_QUERY)
89 .expect("Failed to compile Bash context query");
90
91 Self {
92 highlight_query: Arc::new(highlight_query),
93 folds_query: Arc::new(folds_query),
94 context_query: Arc::new(context_query),
95 }
96 }
97
98 #[must_use]
100 pub const fn folds_query(&self) -> &Arc<Query> {
101 &self.folds_query
102 }
103}
104
105impl Default for BashSyntaxFactory {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111impl SyntaxDriverFactory for BashSyntaxFactory {
112 fn create(&self, language_id: &str) -> Option<Box<dyn SyntaxDriver>> {
113 if language_id != "bash" {
114 return None;
115 }
116
117 let language: Language = tree_sitter_bash::LANGUAGE.into();
118
119 TreeSitterDriver::builder("bash", &language, self.highlight_query.clone())
120 .folds_query(self.folds_query.clone())
121 .context_query(self.context_query.clone())
122 .build()
123 .map(|d| Box::new(d) as Box<dyn SyntaxDriver>)
124 }
125
126 fn supported_languages(&self) -> Vec<&str> {
127 vec!["bash"]
128 }
129
130 fn supports(&self, language_id: &str) -> bool {
131 language_id == "bash"
132 }
133}
134
135pub struct TreesitterBashModule;
145
146impl TreesitterBashModule {
147 #[must_use]
149 pub const fn new() -> Self {
150 Self
151 }
152}
153
154impl Default for TreesitterBashModule {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160impl Module for TreesitterBashModule {
161 fn id(&self) -> ModuleId {
162 ModuleId::new("treesitter-bash")
163 }
164
165 fn name(&self) -> &'static str {
166 "Treesitter Bash"
167 }
168
169 fn version(&self) -> Version {
170 Version::new(0, 10, 0)
171 }
172
173 #[cfg_attr(coverage_nightly, coverage(off))]
174 fn init(&mut self, ctx: &ModuleContext) -> ProbeResult {
175 let factory = Arc::new(BashSyntaxFactory::new());
176
177 let syntax_store = ctx.services.get_or_create::<SyntaxFactoryStore>();
178 syntax_store.add(factory);
179
180 let lang_store = ctx.services.get_or_create::<LanguageInfoStore>();
181 lang_store.add(
182 LanguageInfo::new("bash", "Bash")
183 .with_extensions(["sh", "bash", "zsh"])
184 .with_comments(CommentTokens::line_only("#")),
185 );
186
187 tracing::info!("TreesitterBashModule: registered Bash syntax factory");
188 ProbeResult::Success
189 }
190
191 fn exit(&mut self) -> Result<(), ModuleError> {
192 tracing::info!("TreesitterBashModule: exiting");
193 Ok(())
194 }
195}
196
197#[cfg(test)]
198#[path = "lib_tests.rs"]
199mod tests;