From cfa882557eb24cf0bed0485d0811d3f35832ba4b Mon Sep 17 00:00:00 2001 From: A-Walrus <58790821+A-Walrus@users.noreply.github.com> Date: Fri, 5 Aug 2022 03:12:14 +0300 Subject: [PATCH] Fix nondeterministic highlighting (#3275) * Fix nondeterministic highlighting This is done by prefering matches in the begining, ie for `keyword.function`, `keyword` is a better match than `function`. * Use all positions and not just leftmost Fixes possible edgecase with something like `function.method.builtin` and the queries `function.builtin` and `function.method` * Switch to bitmask for slightly better performance * Make matches from the start of string Also change comments to match new behaviour --- helix-core/src/syntax.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 4188d1481..99922d377 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -1356,8 +1356,8 @@ impl HighlightConfiguration { /// Tree-sitter syntax-highlighting queries specify highlights in the form of dot-separated /// highlight names like `punctuation.bracket` and `function.method.builtin`. Consumers of /// these queries can choose to recognize highlights with different levels of specificity. - /// For example, the string `function.builtin` will match against `function.method.builtin` - /// and `function.builtin.constructor`, but will not match `function.method`. + /// For example, the string `function.builtin` will match against `function.builtin.constructor` + /// but will not match `function.method.builtin` and `function.method`. /// /// When highlighting, results are returned as `Highlight` values, which contain the index /// of the matched highlight this list of highlight names. @@ -1377,11 +1377,13 @@ impl HighlightConfiguration { let recognized_name = recognized_name; let mut len = 0; let mut matches = true; - for part in recognized_name.split('.') { - len += 1; - if !capture_parts.contains(&part) { - matches = false; - break; + for (i, part) in recognized_name.split('.').enumerate() { + match capture_parts.get(i) { + Some(capture_part) if *capture_part == part => len += 1, + _ => { + matches = false; + break; + } } } if matches && len > best_match_len {