From 1c7b518b9daa0958ab2c04fc6c1921b800d3ea26 Mon Sep 17 00:00:00 2001 From: Guillaume Bertholon Date: Sun, 28 Jul 2024 09:59:21 +0200 Subject: [PATCH] build(loader): make dependencies optional (#1638) The `tree-sitter-loader` crate currently always pulls `tree-sitter-highlight` and `tree-sitter-tags` as dependencies. However, apart from the tree-sitter CLI, most clients will not need both of these libraries. This commit makes the dependencies optional, but still includes them by default in order not to break the backward compatibility. --- cli/loader/Cargo.toml | 9 ++++--- cli/loader/src/lib.rs | 55 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/cli/loader/Cargo.toml b/cli/loader/Cargo.toml index bff2f630..5179b36d 100644 --- a/cli/loader/Cargo.toml +++ b/cli/loader/Cargo.toml @@ -14,6 +14,9 @@ categories.workspace = true [features] wasm = ["tree-sitter/wasm"] +# TODO: For backward compatibility these must be enabled by default, +# consider removing for the next semver incompatible release +default = ["tree-sitter-highlight", "tree-sitter-tags"] [dependencies] anyhow.workspace = true @@ -28,6 +31,6 @@ serde.workspace = true serde_json.workspace = true tempfile.workspace = true -tree-sitter.workspace = true -tree-sitter-highlight.workspace = true -tree-sitter-tags.workspace = true +tree-sitter = {workspace = true} +tree-sitter-highlight = {workspace = true, optional = true} +tree-sitter-tags = {workspace = true, optional = true} diff --git a/cli/loader/src/lib.rs b/cli/loader/src/lib.rs index eb829373..56ab0e65 100644 --- a/cli/loader/src/lib.rs +++ b/cli/loader/src/lib.rs @@ -1,5 +1,9 @@ #![doc = include_str!("../README.md")] +#[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] +use std::ops::Range; +#[cfg(feature = "tree-sitter-highlight")] +use std::sync::Mutex; use std::{ collections::HashMap, env, @@ -7,22 +11,28 @@ use std::{ fs, io::{BufRead, BufReader}, mem, - ops::Range, path::{Path, PathBuf}, process::Command, - sync::Mutex, time::SystemTime, }; -use anyhow::{anyhow, Context, Error, Result}; +#[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] +use anyhow::Error; +use anyhow::{anyhow, Context, Result}; use fs4::FileExt; use indoc::indoc; use libloading::{Library, Symbol}; use once_cell::unsync::OnceCell; use regex::{Regex, RegexBuilder}; use serde::{Deserialize, Deserializer, Serialize}; -use tree_sitter::{Language, QueryError, QueryErrorKind}; +use tree_sitter::Language; +#[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] +use tree_sitter::QueryError; +#[cfg(feature = "tree-sitter-highlight")] +use tree_sitter::QueryErrorKind; +#[cfg(feature = "tree-sitter-highlight")] use tree_sitter_highlight::HighlightConfiguration; +#[cfg(feature = "tree-sitter-tags")] use tree_sitter_tags::{Error as TagsError, TagsConfiguration}; pub const EMSCRIPTEN_TAG: &str = concat!("docker.io/emscripten/emsdk:", env!("EMSCRIPTEN_VERSION")); @@ -98,9 +108,13 @@ pub struct LanguageConfiguration<'a> { pub tags_filenames: Option>, pub language_name: String, language_id: usize, + #[cfg(feature = "tree-sitter-highlight")] highlight_config: OnceCell>, + #[cfg(feature = "tree-sitter-tags")] tags_config: OnceCell>, + #[cfg(feature = "tree-sitter-highlight")] highlight_names: &'a Mutex>, + #[cfg(feature = "tree-sitter-highlight")] use_all_highlight_names: bool, } @@ -111,7 +125,9 @@ pub struct Loader { language_configuration_ids_by_file_type: HashMap>, language_configuration_in_current_path: Option, language_configuration_ids_by_first_line_regex: HashMap>, + #[cfg(feature = "tree-sitter-highlight")] highlight_names: Box>>, + #[cfg(feature = "tree-sitter-highlight")] use_all_highlight_names: bool, debug_build: bool, sanitize_build: bool, @@ -177,7 +193,9 @@ impl Loader { language_configuration_ids_by_file_type: HashMap::new(), language_configuration_in_current_path: None, language_configuration_ids_by_first_line_regex: HashMap::new(), + #[cfg(feature = "tree-sitter-highlight")] highlight_names: Box::new(Mutex::new(Vec::new())), + #[cfg(feature = "tree-sitter-highlight")] use_all_highlight_names: true, debug_build: false, sanitize_build: false, @@ -187,6 +205,7 @@ impl Loader { } } + #[cfg(feature = "tree-sitter-highlight")] pub fn configure_highlights(&mut self, names: &[String]) { self.use_all_highlight_names = false; let mut highlights = self.highlight_names.lock().unwrap(); @@ -195,6 +214,7 @@ impl Loader { } #[must_use] + #[cfg(feature = "tree-sitter-highlight")] pub fn highlight_names(&self) -> Vec { self.highlight_names.lock().unwrap().clone() } @@ -889,6 +909,7 @@ impl Loader { } #[must_use] + #[cfg(feature = "tree-sitter-highlight")] pub fn highlight_config_for_injection_string<'a>( &'a self, string: &str, @@ -1041,9 +1062,13 @@ impl Loader { locals_filenames: config_json.locals.into_vec(), tags_filenames: config_json.tags.into_vec(), highlights_filenames: config_json.highlights.into_vec(), + #[cfg(feature = "tree-sitter-highlight")] highlight_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-tags")] tags_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-highlight")] highlight_names: &self.highlight_names, + #[cfg(feature = "tree-sitter-highlight")] use_all_highlight_names: self.use_all_highlight_names, }; @@ -1098,9 +1123,13 @@ impl Loader { locals_filenames: None, highlights_filenames: None, tags_filenames: None, + #[cfg(feature = "tree-sitter-highlight")] highlight_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-tags")] tags_config: OnceCell::new(), + #[cfg(feature = "tree-sitter-highlight")] highlight_names: &self.highlight_names, + #[cfg(feature = "tree-sitter-highlight")] use_all_highlight_names: self.use_all_highlight_names, }; self.language_configurations.push(unsafe { @@ -1187,6 +1216,7 @@ impl Loader { } impl<'a> LanguageConfiguration<'a> { + #[cfg(feature = "tree-sitter-highlight")] pub fn highlight_config( &self, language: Language, @@ -1197,14 +1227,14 @@ impl<'a> LanguageConfiguration<'a> { Some( paths .iter() - .filter(|p| p.ends_with("highlights.scm")) + .filter(|p| p.ends_with("tree-sitter-highlights.scm")) .cloned() .collect::>(), ), Some( paths .iter() - .filter(|p| p.ends_with("tags.scm")) + .filter(|p| p.ends_with("tree-sitter-tags.scm")) .cloned() .collect::>(), ), @@ -1226,7 +1256,7 @@ impl<'a> LanguageConfiguration<'a> { } else { self.highlights_filenames.as_deref() }, - "highlights.scm", + "tree-sitter-highlights.scm", )?; let (injections_query, injection_ranges) = self.read_queries( if injections_filenames.is_some() { @@ -1298,11 +1328,12 @@ impl<'a> LanguageConfiguration<'a> { .map(Option::as_ref) } + #[cfg(feature = "tree-sitter-tags")] pub fn tags_config(&self, language: Language) -> Result> { self.tags_config .get_or_try_init(|| { let (tags_query, tags_ranges) = - self.read_queries(self.tags_filenames.as_deref(), "tags.scm")?; + self.read_queries(self.tags_filenames.as_deref(), "tree-sitter-tags.scm")?; let (locals_query, locals_ranges) = self.read_queries(self.locals_filenames.as_deref(), "locals.scm")?; if tags_query.is_empty() { @@ -1336,6 +1367,7 @@ impl<'a> LanguageConfiguration<'a> { .map(Option::as_ref) } + #[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] fn include_path_in_query_error( mut error: QueryError, ranges: &[(String, Range)], @@ -1349,12 +1381,13 @@ impl<'a> LanguageConfiguration<'a> { .unwrap_or_else(|| ranges.last().unwrap()); error.offset = offset_within_section - range.start; error.row = source[range.start..offset_within_section] - .matches(|c| c == '\n') + .matches('\n') .count(); Error::from(error).context(format!("Error in query file {path:?}")) } #[allow(clippy::type_complexity)] + #[cfg(any(feature = "tree-sitter-highlight", feature = "tree-sitter-tags"))] fn read_queries( &self, paths: Option<&[String]>, @@ -1372,7 +1405,9 @@ impl<'a> LanguageConfiguration<'a> { } } else { // highlights.scm is needed to test highlights, and tags.scm to test tags - if default_path == "highlights.scm" || default_path == "tags.scm" { + if default_path == "tree-sitter-highlights.scm" + || default_path == "tree-sitter-tags.scm" + { eprintln!( indoc! {" Warning: you should add a `{}` entry pointing to the highlights path in `tree-sitter` language list in the grammar's package.json