From 3f109a3cb53a519a87046484ee6c6834d6c1e6fc Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 27 Jan 2020 12:32:37 -0800 Subject: [PATCH] highlight: Fix logic for handling empty injections with no highlights --- cli/src/tests/helpers/fixtures.rs | 8 +++-- cli/src/tests/highlight_test.rs | 47 +++++++++++++++++++++++--- cli/src/tests/test_highlight_test.rs | 2 +- highlight/src/lib.rs | 50 ++++++++++++++++------------ script/fetch-fixtures | 5 +-- script/fetch-fixtures.cmd | 5 +-- 6 files changed, 84 insertions(+), 33 deletions(-) diff --git a/cli/src/tests/helpers/fixtures.rs b/cli/src/tests/helpers/fixtures.rs index 111ccd2c..fc459777 100644 --- a/cli/src/tests/helpers/fixtures.rs +++ b/cli/src/tests/helpers/fixtures.rs @@ -31,13 +31,17 @@ pub fn get_language_queries_path(language_name: &str) -> PathBuf { pub fn get_highlight_config( language_name: &str, - injection_query_filename: &str, + injection_query_filename: Option<&str>, highlight_names: &[String], ) -> HighlightConfiguration { let language = get_language(language_name); let queries_path = get_language_queries_path(language_name); let highlights_query = fs::read_to_string(queries_path.join("highlights.scm")).unwrap(); - let injections_query = fs::read_to_string(queries_path.join(injection_query_filename)).unwrap(); + let injections_query = if let Some(injection_query_filename) = injection_query_filename { + fs::read_to_string(queries_path.join(injection_query_filename)).unwrap() + } else { + String::new() + }; let locals_query = fs::read_to_string(queries_path.join("locals.scm")).unwrap_or(String::new()); let mut result = HighlightConfiguration::new( language, diff --git a/cli/src/tests/highlight_test.rs b/cli/src/tests/highlight_test.rs index 9f6cd12e..2e31005e 100644 --- a/cli/src/tests/highlight_test.rs +++ b/cli/src/tests/highlight_test.rs @@ -9,15 +9,21 @@ use tree_sitter_highlight::{ lazy_static! { static ref JS_HIGHLIGHT: HighlightConfiguration = - get_highlight_config("javascript", "injections.scm", &HIGHLIGHT_NAMES); + get_highlight_config("javascript", Some("injections.scm"), &HIGHLIGHT_NAMES); + static ref JSDOC_HIGHLIGHT: HighlightConfiguration = + get_highlight_config("jsdoc", None, &HIGHLIGHT_NAMES); static ref HTML_HIGHLIGHT: HighlightConfiguration = - get_highlight_config("html", "injections.scm", &HIGHLIGHT_NAMES); - static ref EJS_HIGHLIGHT: HighlightConfiguration = - get_highlight_config("embedded-template", "injections-ejs.scm", &HIGHLIGHT_NAMES); + get_highlight_config("html", Some("injections.scm"), &HIGHLIGHT_NAMES); + static ref EJS_HIGHLIGHT: HighlightConfiguration = get_highlight_config( + "embedded-template", + Some("injections-ejs.scm"), + &HIGHLIGHT_NAMES + ); static ref RUST_HIGHLIGHT: HighlightConfiguration = - get_highlight_config("rust", "injections.scm", &HIGHLIGHT_NAMES); + get_highlight_config("rust", Some("injections.scm"), &HIGHLIGHT_NAMES); static ref HIGHLIGHT_NAMES: Vec = [ "attribute", + "comment", "constant", "constructor", "function.builtin", @@ -351,6 +357,36 @@ fn test_highlighting_ejs_with_html_and_javascript() { ); } +#[test] +fn test_highlighting_javascript_with_jsdoc() { + // Regression test: the middle comment has no highlights. This should not prevent + // later injections from highlighting properly. + let source = vec!["a /* @see a */ b; /* nothing */ c; /* @see b */"].join("\n"); + + assert_eq!( + &to_token_vector(&source, &JS_HIGHLIGHT).unwrap(), + &[[ + ("a", vec!["variable"]), + (" ", vec![]), + ("/* ", vec!["comment"]), + ("@see", vec!["comment", "tag"]), + (" a */", vec!["comment"]), + (" ", vec![]), + ("b", vec!["variable"]), + (";", vec!["punctuation.delimiter"]), + (" ", vec![]), + ("/* nothing */", vec!["comment"]), + (" ", vec![]), + ("c", vec!["variable"]), + (";", vec!["punctuation.delimiter"]), + (" ", vec![]), + ("/* ", vec!["comment"]), + ("@see", vec!["comment", "tag"]), + (" b */", vec!["comment"]) + ]], + ); +} + #[test] fn test_highlighting_with_content_children_included() { let source = vec!["assert!(", " a.b.c() < D::e::()", ");"].join("\n"); @@ -562,6 +598,7 @@ fn test_language_for_injection_string<'a>(string: &str) -> Option<&'a HighlightC "javascript" => Some(&JS_HIGHLIGHT), "html" => Some(&HTML_HIGHLIGHT), "rust" => Some(&RUST_HIGHLIGHT), + "jsdoc" => Some(&JSDOC_HIGHLIGHT), _ => None, } } diff --git a/cli/src/tests/test_highlight_test.rs b/cli/src/tests/test_highlight_test.rs index 68fc31eb..6a857dd9 100644 --- a/cli/src/tests/test_highlight_test.rs +++ b/cli/src/tests/test_highlight_test.rs @@ -8,7 +8,7 @@ fn test_highlight_test_with_basic_test() { let language = get_language("javascript"); let config = get_highlight_config( "javascript", - "injections.scm", + Some("injections.scm"), &[ "function".to_string(), "variable.parameter".to_string(), diff --git a/highlight/src/lib.rs b/highlight/src/lib.rs index ef3b2304..31bca7e0 100644 --- a/highlight/src/lib.rs +++ b/highlight/src/lib.rs @@ -570,37 +570,45 @@ where } fn sort_layers(&mut self) { - if let Some(sort_key) = self.layers[0].sort_key() { - let mut i = 0; - while i + 1 < self.layers.len() { - if let Some(next_offset) = self.layers[i + 1].sort_key() { - if next_offset < sort_key { - i += 1; - continue; + while !self.layers.is_empty() { + if let Some(sort_key) = self.layers[0].sort_key() { + let mut i = 0; + while i + 1 < self.layers.len() { + if let Some(next_offset) = self.layers[i + 1].sort_key() { + if next_offset < sort_key { + i += 1; + continue; + } } + break; + } + if i > 0 { + &self.layers[0..(i + 1)].rotate_left(1); } break; + } else { + let layer = self.layers.remove(0); + self.highlighter.cursors.push(layer.cursor); } - if i > 0 { - &self.layers[0..(i + 1)].rotate_left(1); - } - } else { - let layer = self.layers.remove(0); - self.highlighter.cursors.push(layer.cursor); } } fn insert_layer(&mut self, mut layer: HighlightIterLayer<'a>) { - let sort_key = layer.sort_key(); - let mut i = 1; - while i < self.layers.len() { - if self.layers[i].sort_key() > sort_key { - self.layers.insert(i, layer); - return; + if let Some(sort_key) = layer.sort_key() { + let mut i = 1; + while i < self.layers.len() { + if let Some(sort_key_i) = self.layers[i].sort_key() { + if sort_key_i > sort_key { + self.layers.insert(i, layer); + return; + } + i += 1; + } else { + self.layers.remove(i); + } } - i += 1; + self.layers.push(layer); } - self.layers.push(layer); } } diff --git a/script/fetch-fixtures b/script/fetch-fixtures index f4f84017..2c26d5e6 100755 --- a/script/fetch-fixtures +++ b/script/fetch-fixtures @@ -24,10 +24,11 @@ fetch_grammar() { fetch_grammar bash master fetch_grammar c master fetch_grammar cpp master -fetch_grammar embedded-template new-highlight-injection-api +fetch_grammar embedded-template master fetch_grammar go master -fetch_grammar html new-highlight-injection-api +fetch_grammar html master fetch_grammar javascript master +fetch_grammar jsdoc master fetch_grammar json master fetch_grammar python master fetch_grammar ruby master diff --git a/script/fetch-fixtures.cmd b/script/fetch-fixtures.cmd index b5072003..48b9bfac 100644 --- a/script/fetch-fixtures.cmd +++ b/script/fetch-fixtures.cmd @@ -3,10 +3,11 @@ call:fetch_grammar bash master call:fetch_grammar c master call:fetch_grammar cpp master -call:fetch_grammar embedded-template new-highlight-injection-api +call:fetch_grammar embedded-template master call:fetch_grammar go master -call:fetch_grammar html new-highlight-injection-api +call:fetch_grammar html master call:fetch_grammar javascript master +call:fetch_grammar jsdoc master call:fetch_grammar json master call:fetch_grammar python master call:fetch_grammar ruby master