diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b24cdb8c9..2a1950dfb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -131,3 +131,23 @@ jobs: || (echo "Run 'cargo xtask docgen', commit the changes and push again" \ && exit 1) + queries: + name: Tree-sitter queries + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v3 + + - name: Install stable toolchain + uses: helix-editor/rust-toolchain@v1 + with: + profile: minimal + override: true + + - uses: Swatinem/rust-cache@v1 + + - name: Generate docs + uses: actions-rs/cargo@v1 + with: + command: xtask + args: query-check diff --git a/Cargo.lock b/Cargo.lock index 122e0d836..dd3ec09fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1476,6 +1476,7 @@ name = "xtask" version = "0.6.0" dependencies = [ "helix-core", + "helix-loader", "helix-term", "toml", ] diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 06e9cbc03..6ec56bde2 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -334,7 +334,7 @@ impl TextObjectQuery { } } -fn read_query(language: &str, filename: &str) -> String { +pub fn read_query(language: &str, filename: &str) -> String { static INHERITS_REGEX: Lazy = Lazy::new(|| Regex::new(r";+\s*inherits\s*:?\s*([a-z_,()-]+)\s*").unwrap()); diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 717530d0a..76c38c99e 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] helix-term = { version = "0.6", path = "../helix-term" } helix-core = { version = "0.6", path = "../helix-core" } +helix-loader = { version = "0.6", path = "../helix-loader" } toml = "0.5" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index f66fb4f42..c7640cd1e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -217,6 +217,41 @@ pub mod tasks { Ok(()) } + pub fn query_check() -> Result<(), String> { + use crate::helpers::lang_config; + use helix_core::{syntax::read_query, tree_sitter::Query}; + use helix_loader::grammar::get_language; + + let query_files = [ + "highlights.scm", + "locals.scm", + "injections.scm", + "textobjects.scm", + "indents.scm", + ]; + + for language in lang_config().language { + let language_name = language.language_id.to_ascii_lowercase(); + let grammar_name = language.grammar.unwrap_or(language.language_id); + for query_file in query_files { + let language = get_language(&grammar_name); + let query_text = read_query(&language_name, query_file); + if !query_text.is_empty() && language.is_ok() { + if let Err(reason) = Query::new(language.unwrap(), &query_text) { + return Err(format!( + "Failed to parse {} queries for {}: {}", + query_file, language_name, reason + )); + } + } + } + } + + println!("Query check succeeded"); + + Ok(()) + } + pub fn print_help() { println!( " @@ -224,6 +259,7 @@ Usage: Run with `cargo xtask `, eg. `cargo xtask docgen`. Tasks: docgen: Generate files to be included in the mdbook output. + query-check: Check that tree-sitter queries are valid. " ); } @@ -235,6 +271,7 @@ fn main() -> Result<(), DynError> { None => tasks::print_help(), Some(t) => match t.as_str() { "docgen" => tasks::docgen()?, + "query-check" => tasks::query_check()?, invalid => return Err(format!("Invalid task name: {}", invalid).into()), }, };