feat(bindings): expose the queries dynamically
Available in the Rust, Python, and Node bindings Co-authored-by: ObserverOfTime <chronobserver@disroot.org>
This commit is contained in:
parent
3072d35ed5
commit
f3012a999d
9 changed files with 335 additions and 76 deletions
|
|
@ -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::<Vec<_>>()
|
||||
.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);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ charset = utf-8
|
|||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.js]
|
||||
[*.{js,ts}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
crates/cli/src/templates/index.d.ts
vendored
39
crates/cli/src/templates/index.d.ts
vendored
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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::<Vec<_>>(),
|
||||
),
|
||||
Some(
|
||||
paths
|
||||
.iter()
|
||||
.filter(|p| p.ends_with("tags.scm"))
|
||||
.filter(|p| p.ends_with(DEFAULT_TAGS_QUERY_FILE_NAME))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
Some(
|
||||
paths
|
||||
.iter()
|
||||
.filter(|p| p.ends_with("locals.scm"))
|
||||
.filter(|p| p.ends_with(DEFAULT_LOCALS_QUERY_FILE_NAME))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
|
|
@ -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<Option<&TagsConfiguration>> {
|
||||
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` ",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue