diff --git a/crates/cli/src/init.rs b/crates/cli/src/init.rs index 62923441..deb64292 100644 --- a/crates/cli/src/init.rs +++ b/crates/cli/src/init.rs @@ -14,7 +14,11 @@ use semver::Version; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use tree_sitter_generate::write_file; -use tree_sitter_loader::{Author, Bindings, Grammar, Links, Metadata, PathsJSON, TreeSitterJSON}; +use tree_sitter_loader::{ + Author, Bindings, Grammar, Links, Metadata, PathsJSON, TreeSitterJSON, + DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME, DEFAULT_INJECTIONS_QUERY_FILE_NAME, + DEFAULT_LOCALS_QUERY_FILE_NAME, DEFAULT_TAGS_QUERY_FILE_NAME, +}; const CLI_VERSION: &str = env!("CARGO_PKG_VERSION"); const CLI_VERSION_PLACEHOLDER: &str = "CLI_VERSION"; @@ -60,6 +64,11 @@ const AUTHOR_EMAIL_PLACEHOLDER_GRAMMAR: &str = " PARSER_AUTHOR_EMAIL"; const FUNDING_URL_PLACEHOLDER: &str = "FUNDING_URL"; +const HIGHLIGHTS_QUERY_PATH_PLACEHOLDER: &str = "HIGHLIGHTS_QUERY_PATH"; +const INJECTIONS_QUERY_PATH_PLACEHOLDER: &str = "INJECTIONS_QUERY_PATH"; +const LOCALS_QUERY_PATH_PLACEHOLDER: &str = "LOCALS_QUERY_PATH"; +const TAGS_QUERY_PATH_PLACEHOLDER: &str = "TAGS_QUERY_PATH"; + const GRAMMAR_JS_TEMPLATE: &str = include_str!("./templates/grammar.js"); const PACKAGE_JSON_TEMPLATE: &str = include_str!("./templates/package.json"); const GITIGNORE_TEMPLATE: &str = include_str!("./templates/gitignore"); @@ -205,6 +214,10 @@ struct GenerateOpts<'a> { camel_parser_name: &'a str, title_parser_name: &'a str, class_name: &'a str, + highlights_query_path: &'a str, + injections_query_path: &'a str, + locals_query_path: &'a str, + tags_query_path: &'a str, } pub fn generate_grammar_files( @@ -255,6 +268,20 @@ pub fn generate_grammar_files( .clone() .unwrap_or_else(|| format!("TreeSitter{}", language_name.to_upper_camel_case())); + fn pathsjson_to_variable<'a>(paths_json: &'a PathsJSON, default: &'a PathBuf) -> &'a str { + match paths_json { + PathsJSON::Empty => Some(default), + PathsJSON::Single(path_buf) => Some(path_buf), + PathsJSON::Multiple(paths) => paths.first(), + } + .map_or("", |path| path.as_os_str().to_str().unwrap_or("")) + } + + let default_highlights_path = Path::new("queries").join(DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME); + let default_injections_path = Path::new("queries").join(DEFAULT_INJECTIONS_QUERY_FILE_NAME); + let default_locals_path = Path::new("queries").join(DEFAULT_LOCALS_QUERY_FILE_NAME); + let default_tags_path = Path::new("queries").join(DEFAULT_TAGS_QUERY_FILE_NAME); + let generate_opts = GenerateOpts { author_name: authors .map(|a| a.first().map(|a| a.name.as_str())) @@ -281,6 +308,22 @@ pub fn generate_grammar_files( camel_parser_name: &camel_name, title_parser_name: &title_name, class_name: &class_name, + highlights_query_path: pathsjson_to_variable( + &tree_sitter_config.grammars[0].highlights, + &default_highlights_path, + ), + injections_query_path: pathsjson_to_variable( + &tree_sitter_config.grammars[0].injections, + &default_injections_path, + ), + locals_query_path: pathsjson_to_variable( + &tree_sitter_config.grammars[0].locals, + &default_locals_path, + ), + tags_query_path: pathsjson_to_variable( + &tree_sitter_config.grammars[0].tags, + &default_tags_path, + ), }; // Create package.json @@ -388,8 +431,47 @@ pub fn generate_grammar_files( // Generate Rust bindings if tree_sitter_config.bindings.rust { missing_path(bindings_dir.join("rust"), create_dir)?.apply(|path| { - missing_path(path.join("lib.rs"), |path| { + missing_path_else(path.join("lib.rs"), allow_update, |path| { generate_file(path, LIB_RS_TEMPLATE, language_name, &generate_opts) + }, |path| { + let mut contents = fs::read_to_string(path)?; + if !contents.contains("#[cfg(with_highlights_query)]") { + let replacement = indoc! {r#" + #[cfg(with_highlights_query)] + /// The syntax highlighting query for this grammar. + pub const HIGHLIGHTS_QUERY: &str = include_str!("../../HIGHLIGHTS_QUERY_PATH"); + + #[cfg(with_injections_query)] + /// The language injection query for this grammar. + pub const INJECTIONS_QUERY: &str = include_str!("../../INJECTIONS_QUERY_PATH"); + + #[cfg(with_locals_query)] + /// The local variable query for this grammar. + pub const LOCALS_QUERY: &str = include_str!("../../LOCALS_QUERY_PATH"); + + #[cfg(with_tags_query)] + /// The symbol tagging query for this grammar. + pub const TAGS_QUERY: &str = include_str!("../../TAGS_QUERY_PATH"); + "#} + .replace("HIGHLIGHTS_QUERY_PATH", generate_opts.highlights_query_path) + .replace("INJECTIONS_QUERY_PATH", generate_opts.injections_query_path) + .replace("LOCALS_QUERY_PATH", generate_opts.locals_query_path) + .replace("TAGS_QUERY_PATH", generate_opts.tags_query_path); + contents = contents + .replace( + indoc! {r#" + // NOTE: uncomment these to include any queries that this grammar contains: + + // pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); + // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); + // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); + // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); + "#}, + &replacement, + ); + } + write_file(path, contents)?; + Ok(()) })?; missing_path_else( @@ -397,27 +479,29 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, BUILD_RS_TEMPLATE, language_name, &generate_opts), |path| { - let replacement = indoc!{r#" - c_config.flag("-utf-8"); + let mut contents = fs::read_to_string(path)?; + if !contents.contains("wasm32-unknown-unknown") { + let replacement = indoc!{r#" + c_config.flag("-utf-8"); - if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { - let Ok(wasm_headers) = std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS") else { - panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS must be set by the language crate"); - }; - let Ok(wasm_src) = - std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_SRC").map(std::path::PathBuf::from) - else { - panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_SRC must be set by the language crate"); - }; + if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { + let Ok(wasm_headers) = std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS") else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS must be set by the language crate"); + }; + let Ok(wasm_src) = + std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_SRC").map(std::path::PathBuf::from) + else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_SRC must be set by the language crate"); + }; - c_config.include(&wasm_headers); - c_config.files([ - wasm_src.join("stdio.c"), - wasm_src.join("stdlib.c"), - wasm_src.join("string.c"), - ]); - } - "#}; + c_config.include(&wasm_headers); + c_config.files([ + wasm_src.join("stdio.c"), + wasm_src.join("stdlib.c"), + wasm_src.join("string.c"), + ]); + } + "#}; let indented_replacement = replacement .lines() @@ -425,11 +509,48 @@ pub fn generate_grammar_files( .collect::>() .join("\n"); - let mut contents = fs::read_to_string(path)?; - if !contents.contains("wasm32-unknown-unknown") { contents = contents.replace(r#" c_config.flag("-utf-8");"#, &indented_replacement); } + // Introduce configuration variables for dynamic query inclusion + if !contents.contains("with_highlights_query") { + let replaced = indoc! {r#" + c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + }"#} + .replace("KEBAB_PARSER_NAME", &language_name.to_kebab_case()); + + let replacement = indoc! {r#" + c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + + println!("cargo:rustc-check-cfg=cfg(with_highlights_query)"); + if !"HIGHLIGHTS_QUERY_PATH".is_empty() && std::path::Path::new("HIGHLIGHTS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_highlights_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_injections_query)"); + if !"INJECTIONS_QUERY_PATH".is_empty() && std::path::Path::new("INJECTIONS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_injections_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_locals_query)"); + if !"LOCALS_QUERY_PATH".is_empty() && std::path::Path::new("LOCALS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_locals_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_tags_query)"); + if !"TAGS_QUERY_PATH".is_empty() && std::path::Path::new("TAGS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_tags_query"); + } + }"#} + .replace("KEBAB_PARSER_NAME", &language_name.to_kebab_case()) + .replace("HIGHLIGHTS_QUERY_PATH", generate_opts.highlights_query_path) + .replace("INJECTIONS_QUERY_PATH", generate_opts.injections_query_path) + .replace("LOCALS_QUERY_PATH", generate_opts.locals_query_path) + .replace("TAGS_QUERY_PATH", generate_opts.tags_query_path); + + contents = contents.replace( + &replaced, + &replacement, + ); + } + write_file(path, contents)?; Ok(()) }, @@ -468,7 +589,7 @@ pub fn generate_grammar_files( |path| generate_file(path, INDEX_JS_TEMPLATE, language_name, &generate_opts), |path| { let contents = fs::read_to_string(path)?; - if !contents.contains("new URL") { + if !contents.contains("Object.defineProperty") { warn!("Replacing index.js"); generate_file(path, INDEX_JS_TEMPLATE, language_name, &generate_opts)?; } @@ -476,9 +597,19 @@ pub fn generate_grammar_files( }, )?; - missing_path(path.join("index.d.ts"), |path| { - generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + path.join("index.d.ts"), + allow_update, + |path| generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts), + |path| { + let contents = fs::read_to_string(path)?; + if !contents.contains("export default binding") { + warn!("Replacing index.d.ts"); + generate_file(path, INDEX_D_TS_TEMPLATE, language_name, &generate_opts)?; + } + Ok(()) + }, + )?; missing_path_else( path.join("binding_test.js"), @@ -717,9 +848,21 @@ pub fn generate_grammar_files( }, )?; - missing_path(lang_path.join("__init__.py"), |path| { - generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + lang_path.join("__init__.py"), + allow_update, + |path| { + generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts) + }, + |path| { + let contents = fs::read_to_string(path)?; + if !contents.contains("uncomment these to include any queries") { + warn!("Replacing __init__.py"); + generate_file(path, INIT_PY_TEMPLATE, language_name, &generate_opts)?; + } + Ok(()) + }, + )?; missing_path_else( lang_path.join("__init__.pyi"), @@ -727,7 +870,10 @@ pub fn generate_grammar_files( |path| generate_file(path, INIT_PYI_TEMPLATE, language_name, &generate_opts), |path| { let mut contents = fs::read_to_string(path)?; - if !contents.contains("CapsuleType") { + if contents.contains("uncomment these to include any queries") { + warn!("Replacing __init__.pyi"); + generate_file(path, INIT_PYI_TEMPLATE, language_name, &generate_opts)?; + } else if !contents.contains("CapsuleType") { contents = contents .replace( "from typing import Final", @@ -990,7 +1136,20 @@ fn generate_file( PARSER_VERSION_PLACEHOLDER, &generate_opts.version.to_string(), ) - .replace(PARSER_CLASS_NAME_PLACEHOLDER, generate_opts.class_name); + .replace(PARSER_CLASS_NAME_PLACEHOLDER, generate_opts.class_name) + .replace( + HIGHLIGHTS_QUERY_PATH_PLACEHOLDER, + generate_opts.highlights_query_path, + ) + .replace( + INJECTIONS_QUERY_PATH_PLACEHOLDER, + generate_opts.injections_query_path, + ) + .replace( + LOCALS_QUERY_PATH_PLACEHOLDER, + generate_opts.locals_query_path, + ) + .replace(TAGS_QUERY_PATH_PLACEHOLDER, generate_opts.tags_query_path); if let Some(name) = generate_opts.author_name { replacement = replacement.replace(AUTHOR_NAME_PLACEHOLDER, name); diff --git a/crates/cli/src/templates/.editorconfig b/crates/cli/src/templates/.editorconfig index 65330c40..c4650c59 100644 --- a/crates/cli/src/templates/.editorconfig +++ b/crates/cli/src/templates/.editorconfig @@ -7,7 +7,7 @@ charset = utf-8 indent_style = space indent_size = 2 -[*.js] +[*.{js,ts}] indent_style = space indent_size = 2 diff --git a/crates/cli/src/templates/__init__.py b/crates/cli/src/templates/__init__.py index fd137b0f..784887a7 100644 --- a/crates/cli/src/templates/__init__.py +++ b/crates/cli/src/templates/__init__.py @@ -6,32 +6,33 @@ from ._binding import language def _get_query(name, file): - query = _files(f"{__package__}.queries") / file - globals()[name] = query.read_text() + try: + query = _files(f"{__package__}") / file + globals()[name] = query.read_text() + except FileNotFoundError: + globals()[name] = None return globals()[name] def __getattr__(name): - # NOTE: uncomment these to include any queries that this grammar contains: - - # if name == "HIGHLIGHTS_QUERY": - # return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") - # if name == "INJECTIONS_QUERY": - # return _get_query("INJECTIONS_QUERY", "injections.scm") - # if name == "LOCALS_QUERY": - # return _get_query("LOCALS_QUERY", "locals.scm") - # if name == "TAGS_QUERY": - # return _get_query("TAGS_QUERY", "tags.scm") + if name == "HIGHLIGHTS_QUERY": + return _get_query("HIGHLIGHTS_QUERY", "HIGHLIGHTS_QUERY_PATH") + if name == "INJECTIONS_QUERY": + return _get_query("INJECTIONS_QUERY", "INJECTIONS_QUERY_PATH") + if name == "LOCALS_QUERY": + return _get_query("LOCALS_QUERY", "LOCALS_QUERY_PATH") + if name == "TAGS_QUERY": + return _get_query("TAGS_QUERY", "TAGS_QUERY_PATH") raise AttributeError(f"module {__name__!r} has no attribute {name!r}") __all__ = [ "language", - # "HIGHLIGHTS_QUERY", - # "INJECTIONS_QUERY", - # "LOCALS_QUERY", - # "TAGS_QUERY", + "HIGHLIGHTS_QUERY", + "INJECTIONS_QUERY", + "LOCALS_QUERY", + "TAGS_QUERY", ] diff --git a/crates/cli/src/templates/__init__.pyi b/crates/cli/src/templates/__init__.pyi index 5c63215d..5c88ff6c 100644 --- a/crates/cli/src/templates/__init__.pyi +++ b/crates/cli/src/templates/__init__.pyi @@ -1,11 +1,17 @@ from typing import Final from typing_extensions import CapsuleType -# NOTE: uncomment these to include any queries that this grammar contains: +HIGHLIGHTS_QUERY: Final[str] | None +"""The syntax highlighting query for this grammar.""" -# HIGHLIGHTS_QUERY: Final[str] -# INJECTIONS_QUERY: Final[str] -# LOCALS_QUERY: Final[str] -# TAGS_QUERY: Final[str] +INJECTIONS_QUERY: Final[str] | None +"""The language injection query for this grammar.""" -def language() -> CapsuleType: ... +LOCALS_QUERY: Final[str] | None +"""The local variable query for this grammar.""" + +TAGS_QUERY: Final[str] | None +"""The symbol tagging query for this grammar.""" + +def language() -> CapsuleType: + """The tree-sitter language function for this grammar.""" diff --git a/crates/cli/src/templates/build.rs b/crates/cli/src/templates/build.rs index 272d8961..e3fffe4b 100644 --- a/crates/cli/src/templates/build.rs +++ b/crates/cli/src/templates/build.rs @@ -36,4 +36,21 @@ fn main() { } c_config.compile("tree-sitter-KEBAB_PARSER_NAME"); + + println!("cargo:rustc-check-cfg=cfg(with_highlights_query)"); + if !"HIGHLIGHTS_QUERY_PATH".is_empty() && std::path::Path::new("HIGHLIGHTS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_highlights_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_injections_query)"); + if !"INJECTIONS_QUERY_PATH".is_empty() && std::path::Path::new("INJECTIONS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_injections_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_locals_query)"); + if !"LOCALS_QUERY_PATH".is_empty() && std::path::Path::new("LOCALS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_locals_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_tags_query)"); + if !"TAGS_QUERY_PATH".is_empty() && std::path::Path::new("TAGS_QUERY_PATH").exists() { + println!("cargo:rustc-cfg=with_tags_query"); + } } diff --git a/crates/cli/src/templates/index.d.ts b/crates/cli/src/templates/index.d.ts index 528e060f..24576d32 100644 --- a/crates/cli/src/templates/index.d.ts +++ b/crates/cli/src/templates/index.d.ts @@ -18,10 +18,43 @@ type NodeInfo = children: ChildNode[]; }); -type Language = { +/** + * The tree-sitter language object for this grammar. + * + * @see {@linkcode https://tree-sitter.github.io/node-tree-sitter/interfaces/Parser.Language.html Parser.Language} + * + * @example + * import Parser from "tree-sitter"; + * import CAMEL_PARSER_NAME from "tree-sitter-KEBAB_PARSER_NAME"; + * + * const parser = new Parser(); + * parser.setLanguage(CAMEL_PARSER_NAME); + */ +declare const binding: { + /** + * The inner language object. + * @private + */ language: unknown; + + /** + * The content of the `node-types.json` file for this grammar. + * + * @see {@linkplain https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types Static Node Types} + */ nodeTypeInfo: NodeInfo[]; + + /** The syntax highlighting query for this grammar. */ + HIGHLIGHTS_QUERY?: string; + + /** The language injection query for this grammar. */ + INJECTIONS_QUERY?: string; + + /** The local variable query for this grammar. */ + LOCALS_QUERY?: string; + + /** The symbol tagging query for this grammar. */ + TAGS_QUERY?: string; }; -declare const language: Language; -export = language; +export default binding; diff --git a/crates/cli/src/templates/index.js b/crates/cli/src/templates/index.js index 4b363040..b3edc2e3 100644 --- a/crates/cli/src/templates/index.js +++ b/crates/cli/src/templates/index.js @@ -1,3 +1,4 @@ +import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; const root = fileURLToPath(new URL("../..", import.meta.url)); @@ -8,8 +9,29 @@ const binding = typeof process.versions.bun === "string" : (await import("node-gyp-build")).default(root); try { - const nodeTypes = await import(`${root}/src/node-types.json`, {with: {type: "json"}}); + const nodeTypes = await import(`${root}/src/node-types.json`, { with: { type: "json" } }); binding.nodeTypeInfo = nodeTypes.default; -} catch (_) {} +} catch { } + +const queries = [ + ["HIGHLIGHTS_QUERY", `${root}/HIGHLIGHTS_QUERY_PATH`], + ["INJECTIONS_QUERY", `${root}/INJECTIONS_QUERY_PATH`], + ["LOCALS_QUERY", `${root}/LOCALS_QUERY_PATH`], + ["TAGS_QUERY", `${root}/TAGS_QUERY_PATH`], +]; + +for (const [prop, path] of queries) { + Object.defineProperty(binding, prop, { + configurable: true, + enumerable: true, + get() { + delete binding[prop]; + try { + binding[prop] = readFileSync(path, "utf8"); + } catch { } + return binding[prop]; + } + }); +} export default binding; diff --git a/crates/cli/src/templates/lib.rs b/crates/cli/src/templates/lib.rs index 8478f488..1e8c9ca3 100644 --- a/crates/cli/src/templates/lib.rs +++ b/crates/cli/src/templates/lib.rs @@ -32,12 +32,21 @@ pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_PARSE /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); -// NOTE: uncomment these to include any queries that this grammar contains: +#[cfg(with_highlights_query)] +/// The syntax highlighting query for this grammar. +pub const HIGHLIGHTS_QUERY: &str = include_str!("../../HIGHLIGHTS_QUERY_PATH"); -// pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); -// pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); -// pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); -// pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); +#[cfg(with_injections_query)] +/// The language injection query for this grammar. +pub const INJECTIONS_QUERY: &str = include_str!("../../INJECTIONS_QUERY_PATH"); + +#[cfg(with_locals_query)] +/// The local variable query for this grammar. +pub const LOCALS_QUERY: &str = include_str!("../../LOCALS_QUERY_PATH"); + +#[cfg(with_tags_query)] +/// The symbol tagging query for this grammar. +pub const TAGS_QUERY: &str = include_str!("../../TAGS_QUERY_PATH"); #[cfg(test)] mod tests { diff --git a/crates/loader/src/loader.rs b/crates/loader/src/loader.rs index cf2c1a77..7c2e5226 100644 --- a/crates/loader/src/loader.rs +++ b/crates/loader/src/loader.rs @@ -245,6 +245,14 @@ impl std::fmt::Display for WasiSDKClangError { } } +pub const DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME: &str = "highlights.scm"; + +pub const DEFAULT_INJECTIONS_QUERY_FILE_NAME: &str = "injections.scm"; + +pub const DEFAULT_LOCALS_QUERY_FILE_NAME: &str = "locals.scm"; + +pub const DEFAULT_TAGS_QUERY_FILE_NAME: &str = "tags.scm"; + #[derive(Default, Deserialize, Serialize)] pub struct Config { #[serde(default)] @@ -1764,21 +1772,21 @@ impl LanguageConfiguration<'_> { Some( paths .iter() - .filter(|p| p.ends_with("highlights.scm")) + .filter(|p| p.ends_with(DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), Some( paths .iter() - .filter(|p| p.ends_with("tags.scm")) + .filter(|p| p.ends_with(DEFAULT_TAGS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), Some( paths .iter() - .filter(|p| p.ends_with("locals.scm")) + .filter(|p| p.ends_with(DEFAULT_LOCALS_QUERY_FILE_NAME)) .cloned() .collect::>(), ), @@ -1793,7 +1801,7 @@ impl LanguageConfiguration<'_> { } else { self.highlights_filenames.as_deref() }, - "highlights.scm", + DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME, )?; let (injections_query, injection_ranges) = self.read_queries( if injections_filenames.is_some() { @@ -1801,7 +1809,7 @@ impl LanguageConfiguration<'_> { } else { self.injections_filenames.as_deref() }, - "injections.scm", + DEFAULT_INJECTIONS_QUERY_FILE_NAME, )?; let (locals_query, locals_ranges) = self.read_queries( if locals_filenames.is_some() { @@ -1809,7 +1817,7 @@ impl LanguageConfiguration<'_> { } else { self.locals_filenames.as_deref() }, - "locals.scm", + DEFAULT_LOCALS_QUERY_FILE_NAME, )?; if highlights_query.is_empty() { @@ -1871,10 +1879,12 @@ impl LanguageConfiguration<'_> { pub fn tags_config(&self, language: Language) -> LoaderResult> { self.tags_config .get_or_try_init(|| { - let (tags_query, tags_ranges) = - self.read_queries(self.tags_filenames.as_deref(), "tags.scm")?; - let (locals_query, locals_ranges) = - self.read_queries(self.locals_filenames.as_deref(), "locals.scm")?; + let (tags_query, tags_ranges) = self + .read_queries(self.tags_filenames.as_deref(), DEFAULT_TAGS_QUERY_FILE_NAME)?; + let (locals_query, locals_ranges) = self.read_queries( + self.locals_filenames.as_deref(), + DEFAULT_LOCALS_QUERY_FILE_NAME, + )?; if tags_query.is_empty() { Ok(None) } else { @@ -1947,7 +1957,9 @@ impl LanguageConfiguration<'_> { } } 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 == DEFAULT_HIGHLIGHTS_QUERY_FILE_NAME + || default_path == DEFAULT_TAGS_QUERY_FILE_NAME + { warn!( concat!( "You should add a `{}` entry pointing to the {} path in the `tree-sitter` ",