From c440f3a71be2346e6b2b7eddb4dac898d2245b0a Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 22 May 2024 13:26:12 +0200 Subject: [PATCH] tasks: Fix runnables retrieval to not bail when a single tag can't be matched (#12113) This can happen with queries without `@run` indicator. Release Notes: - N/A --- crates/language/src/buffer.rs | 88 ++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 435f4ac79bcda3ad669c5e6520f5ebd73bc1f923..96ba71f4b0be8ac9d64e1e793330789d63e705f9 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -3005,52 +3005,56 @@ impl BufferSnapshot { .map(|grammar| grammar.runnable_config.as_ref()) .collect::>(); - iter::from_fn(move || { - let test_range = syntax_matches.peek().and_then(|mat| { - test_configs[mat.grammar_index].and_then(|test_configs| { - let mut tags: SmallVec<[(Range, RunnableTag); 1]> = - SmallVec::from_iter(mat.captures.iter().filter_map(|capture| { - test_configs - .runnable_tags - .get(&capture.index) - .cloned() - .map(|tag_name| (capture.node.byte_range(), tag_name)) - })); - let maximum_range = tags - .iter() - .max_by_key(|(byte_range, _)| byte_range.len()) - .map(|(range, _)| range)? - .clone(); - tags.sort_by_key(|(range, _)| range == &maximum_range); - let split_point = tags.partition_point(|(range, _)| range != &maximum_range); - let (extra_captures, tags) = tags.split_at(split_point); - let extra_captures = extra_captures - .into_iter() - .map(|(range, name)| { - ( - name.0.to_string(), - self.text_for_range(range.clone()).collect::(), - ) - }) - .collect(); - Some(RunnableRange { - run_range: mat - .captures - .iter() - .find(|capture| capture.index == test_configs.run_capture_ix) - .map(|mat| mat.node.byte_range())?, - runnable: Runnable { - tags: tags.into_iter().cloned().map(|(_, tag)| tag).collect(), - language: mat.language, - buffer: self.remote_id(), - }, - extra_captures, - buffer_id: self.remote_id(), + iter::from_fn(move || loop { + let mat = syntax_matches.peek()?; + let test_range = test_configs[mat.grammar_index].and_then(|test_configs| { + let mut tags: SmallVec<[(Range, RunnableTag); 1]> = + SmallVec::from_iter(mat.captures.iter().filter_map(|capture| { + test_configs + .runnable_tags + .get(&capture.index) + .cloned() + .map(|tag_name| (capture.node.byte_range(), tag_name)) + })); + let maximum_range = tags + .iter() + .max_by_key(|(byte_range, _)| byte_range.len()) + .map(|(range, _)| range)? + .clone(); + tags.sort_by_key(|(range, _)| range == &maximum_range); + let split_point = tags.partition_point(|(range, _)| range != &maximum_range); + let (extra_captures, tags) = tags.split_at(split_point); + let extra_captures = extra_captures + .into_iter() + .map(|(range, name)| { + ( + name.0.to_string(), + self.text_for_range(range.clone()).collect::(), + ) }) + .collect(); + Some(RunnableRange { + run_range: mat + .captures + .iter() + .find(|capture| capture.index == test_configs.run_capture_ix) + .map(|mat| mat.node.byte_range())?, + runnable: Runnable { + tags: tags.into_iter().cloned().map(|(_, tag)| tag).collect(), + language: mat.language, + buffer: self.remote_id(), + }, + extra_captures, + buffer_id: self.remote_id(), }) }); + syntax_matches.advance(); - test_range + if test_range.is_some() { + // It's fine for us to short-circuit on .peek()? returning None. We don't want to return None from this iter if we + // had a capture that did not contain a run marker, hence we'll just loop around for the next capture. + return test_range; + } }) }