test_utils: Make overlapping annotations possible

This commit is contained in:
Florian Diebold 2021-06-20 18:34:43 +02:00
parent 04fbdce426
commit d340f28a81

View file

@ -11,6 +11,7 @@ mod fixture;
mod assert_linear; mod assert_linear;
use std::{ use std::{
collections::BTreeMap,
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
env, fs, env, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -205,14 +206,25 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
/// ///
/// // ^^^ first line /// // ^^^ first line
/// // | second line /// // | second line
///
/// Annotations point to the last line that actually was long enough for the
/// range, not counting annotations themselves. So overlapping annotations are
/// possible:
/// ```no_run
/// // stuff other stuff
/// // ^^ 'st'
/// // ^^^^^ 'stuff'
/// // ^^^^^^^^^^^ 'other stuff'
/// ```
pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
let mut res = Vec::new(); let mut res = Vec::new();
let mut prev_line_start: Option<TextSize> = Some(0.into()); // map from line length to beginning of last line that had that length
let mut line_start_map = BTreeMap::new();
let mut line_start: TextSize = 0.into(); let mut line_start: TextSize = 0.into();
let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
for line in text.split_inclusive('\n') { for line in text.split_inclusive('\n') {
let mut this_line_annotations = Vec::new(); let mut this_line_annotations = Vec::new();
if let Some(idx) = line.find("//") { let line_length = if let Some(idx) = line.find("//") {
let annotation_offset = TextSize::of(&line[..idx + "//".len()]); let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
for annotation in extract_line_annotations(&line[idx + "//".len()..]) { for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
match annotation { match annotation {
@ -222,7 +234,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
let range = if file { let range = if file {
TextRange::up_to(TextSize::of(text)) TextRange::up_to(TextSize::of(text))
} else { } else {
range + prev_line_start.unwrap() let line_start = line_start_map.range(range.end()..).next().unwrap();
range + line_start.1
}; };
res.push((range, content)) res.push((range, content))
} }
@ -238,9 +252,14 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
} }
} }
} }
} idx.try_into().unwrap()
} else {
TextSize::of(line)
};
line_start_map = line_start_map.split_off(&line_length);
line_start_map.insert(line_length, line_start);
prev_line_start = Some(line_start);
line_start += TextSize::of(line); line_start += TextSize::of(line);
prev_line_annotations = this_line_annotations; prev_line_annotations = this_line_annotations;
@ -296,7 +315,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
} }
#[test] #[test]
fn test_extract_annotations() { fn test_extract_annotations_1() {
let text = stdx::trim_indent( let text = stdx::trim_indent(
r#" r#"
fn main() { fn main() {
@ -321,6 +340,25 @@ fn main() {
assert_eq!(res[3].0.len(), 115); assert_eq!(res[3].0.len(), 115);
} }
#[test]
fn test_extract_annotations_2() {
let text = stdx::trim_indent(
r#"
fn main() {
(x, y);
//^ a
// ^ b
//^^^^^^^^ c
}"#,
);
let res = extract_annotations(&text)
.into_iter()
.map(|(range, ann)| (&text[range], ann))
.collect::<Vec<_>>();
assert_eq!(res, [("x", "a".into()), ("y", "b".into()), ("(x, y)", "c".into())]);
}
/// Returns `false` if slow tests should not run, otherwise returns `true` and /// Returns `false` if slow tests should not run, otherwise returns `true` and
/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
/// that slow tests did run. /// that slow tests did run.