Merge pull request #1602 from the-mikedavis/md-ignore-future-matches-for-non-local-patterns

prevent future captures for `#is-not? local` matches
This commit is contained in:
Max Brunsfeld 2022-01-19 16:40:30 -08:00 committed by GitHub
commit fce23d63b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 0 deletions

View file

@ -3091,6 +3091,53 @@ fn test_query_captures_with_matches_removed() {
});
}
#[test]
fn test_query_captures_with_matches_removed_before_they_finish() {
allocations::record(|| {
let language = get_language("javascript");
// When Tree-sitter detects that a pattern is guaranteed to match,
// it will start to eagerly return the captures that it has found,
// even though it hasn't matched the entire pattern yet. A
// namespace_import node always has "*", "as" and then an identifier
// for children, so captures will be emitted eagerly for this pattern.
let query = Query::new(
language,
r#"
(namespace_import
"*" @star
"as" @as
(identifier) @identifier)
"#,
)
.unwrap();
let source = "
import * as name from 'module-name';
";
let mut parser = Parser::new();
parser.set_language(language).unwrap();
let tree = parser.parse(&source, None).unwrap();
let mut cursor = QueryCursor::new();
let mut captured_strings = Vec::new();
for (m, i) in cursor.captures(&query, tree.root_node(), source.as_bytes()) {
let capture = m.captures[i];
let text = capture.node.utf8_text(source.as_bytes()).unwrap();
if text == "as" {
m.remove();
continue;
}
captured_strings.push(text);
}
// .remove() removes the match before it is finished. The identifier
// "name" is part of this match, so we expect that removing the "as"
// capture from the match should prevent "name" from matching:
assert_eq!(captured_strings, &["*",]);
});
}
#[test]
fn test_query_captures_and_matches_iterators_are_fused() {
allocations::record(|| {

View file

@ -835,6 +835,7 @@ where
// highlighting patterns that are disabled for local variables.
if definition_highlight.is_some() || reference_highlight.is_some() {
while layer.config.non_local_variable_patterns[match_.pattern_index] {
match_.remove();
if let Some((next_match, next_capture_index)) = layer.captures.peek() {
let next_capture = next_match.captures[*next_capture_index];
if next_capture.node == capture.node {

View file

@ -3727,6 +3727,20 @@ void ts_query_cursor_remove_match(
return;
}
}
// Remove unfinished query states as well to prevent future
// captures for a match being removed.
for (unsigned i = 0; i < self->states.size; i++) {
const QueryState *state = &self->states.contents[i];
if (state->id == match_id) {
capture_list_pool_release(
&self->capture_list_pool,
state->capture_list_id
);
array_erase(&self->states, i);
return;
}
}
}
bool ts_query_cursor_next_capture(