#![cfg_attr(coverage_nightly, allow(unused_features))]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
use std::sync::Arc;
use {
reovim_driver_syntax::{
CommentTokens, LanguageInfo, LanguageInfoStore, SyntaxDriver, SyntaxDriverFactory,
SyntaxFactoryStore,
},
reovim_driver_syntax_treesitter::{Language, Query, TreeSitterDriver},
reovim_kernel::api::v1::{Module, ModuleContext, ModuleError, ModuleId, ProbeResult, Version},
};
const BASH_HIGHLIGHTS_QUERY: &str = include_str!("queries/highlights.scm");
const BASH_FOLDS_QUERY: &str = include_str!("queries/folds.scm");
const BASH_CONTEXT_QUERY: &str = include_str!("queries/context.scm");
#[allow(clippy::struct_field_names)]
pub struct BashSyntaxFactory {
highlight_query: Arc<Query>,
folds_query: Arc<Query>,
context_query: Arc<Query>,
}
impl BashSyntaxFactory {
#[must_use]
pub fn new() -> Self {
let language: Language = tree_sitter_bash::LANGUAGE.into();
let highlight_query = Query::new(&language, BASH_HIGHLIGHTS_QUERY)
.expect("Failed to compile Bash highlights query");
let folds_query =
Query::new(&language, BASH_FOLDS_QUERY).expect("Failed to compile Bash folds query");
let context_query = Query::new(&language, BASH_CONTEXT_QUERY)
.expect("Failed to compile Bash context query");
Self {
highlight_query: Arc::new(highlight_query),
folds_query: Arc::new(folds_query),
context_query: Arc::new(context_query),
}
}
#[must_use]
pub const fn folds_query(&self) -> &Arc<Query> {
&self.folds_query
}
}
impl Default for BashSyntaxFactory {
fn default() -> Self {
Self::new()
}
}
impl SyntaxDriverFactory for BashSyntaxFactory {
fn create(&self, language_id: &str) -> Option<Box<dyn SyntaxDriver>> {
if language_id != "bash" {
return None;
}
let language: Language = tree_sitter_bash::LANGUAGE.into();
TreeSitterDriver::builder("bash", &language, self.highlight_query.clone())
.folds_query(self.folds_query.clone())
.context_query(self.context_query.clone())
.build()
.map(|d| Box::new(d) as Box<dyn SyntaxDriver>)
}
fn supported_languages(&self) -> Vec<&str> {
vec!["bash"]
}
fn supports(&self, language_id: &str) -> bool {
language_id == "bash"
}
}
pub struct TreesitterBashModule;
impl TreesitterBashModule {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Default for TreesitterBashModule {
fn default() -> Self {
Self::new()
}
}
impl Module for TreesitterBashModule {
fn id(&self) -> ModuleId {
ModuleId::new("treesitter-bash")
}
fn name(&self) -> &'static str {
"Treesitter Bash"
}
fn version(&self) -> Version {
Version::new(0, 10, 0)
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn init(&mut self, ctx: &ModuleContext) -> ProbeResult {
let factory = Arc::new(BashSyntaxFactory::new());
let syntax_store = ctx.services.get_or_create::<SyntaxFactoryStore>();
syntax_store.add(factory);
let lang_store = ctx.services.get_or_create::<LanguageInfoStore>();
lang_store.add(
LanguageInfo::new("bash", "Bash")
.with_extensions(["sh", "bash", "zsh"])
.with_comments(CommentTokens::line_only("#")),
);
tracing::info!("TreesitterBashModule: registered Bash syntax factory");
ProbeResult::Success
}
fn exit(&mut self) -> Result<(), ModuleError> {
tracing::info!("TreesitterBashModule: exiting");
Ok(())
}
}
#[cfg(test)]
#[path = "lib_tests.rs"]
mod tests;