aboutsummaryrefslogtreecommitdiff
path: root/crates/test_utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/test_utils/src')
-rw-r--r--crates/test_utils/src/lib.rs58
1 files changed, 41 insertions, 17 deletions
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index bd017567c..b2fe25f82 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -190,10 +190,21 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
190 res 190 res
191} 191}
192 192
193/// Extracts `//^ some text` annotations 193/// Extracts `//^^^ some text` annotations.
194///
195/// A run of `^^^` can be arbitrary long and points to the corresponding range
196/// in the line above.
197///
198/// The `// ^file text` syntax can be used to attach `text` to the entirety of
199/// the file.
200///
201/// Multiline string values are supported:
202///
203/// // ^^^ first line
204/// // | second line
194pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { 205pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
195 let mut res = Vec::new(); 206 let mut res = Vec::new();
196 let mut prev_line_start: Option<TextSize> = None; 207 let mut prev_line_start: Option<TextSize> = Some(0.into());
197 let mut line_start: TextSize = 0.into(); 208 let mut line_start: TextSize = 0.into();
198 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); 209 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
199 for line in text.split_inclusive('\n') { 210 for line in text.split_inclusive('\n') {
@@ -202,10 +213,15 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
202 let annotation_offset = TextSize::of(&line[..idx + "//".len()]); 213 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
203 for annotation in extract_line_annotations(&line[idx + "//".len()..]) { 214 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
204 match annotation { 215 match annotation {
205 LineAnnotation::Annotation { mut range, content } => { 216 LineAnnotation::Annotation { mut range, content, file } => {
206 range += annotation_offset; 217 range += annotation_offset;
207 this_line_annotations.push((range.end(), res.len())); 218 this_line_annotations.push((range.end(), res.len()));
208 res.push((range + prev_line_start.unwrap(), content)) 219 let range = if file {
220 TextRange::up_to(TextSize::of(text))
221 } else {
222 range + prev_line_start.unwrap()
223 };
224 res.push((range, content))
209 } 225 }
210 LineAnnotation::Continuation { mut offset, content } => { 226 LineAnnotation::Continuation { mut offset, content } => {
211 offset += annotation_offset; 227 offset += annotation_offset;
@@ -226,11 +242,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
226 242
227 prev_line_annotations = this_line_annotations; 243 prev_line_annotations = this_line_annotations;
228 } 244 }
245
229 res 246 res
230} 247}
231 248
232enum LineAnnotation { 249enum LineAnnotation {
233 Annotation { range: TextRange, content: String }, 250 Annotation { range: TextRange, content: String, file: bool },
234 Continuation { offset: TextSize, content: String }, 251 Continuation { offset: TextSize, content: String },
235} 252}
236 253
@@ -238,14 +255,9 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
238 let mut res = Vec::new(); 255 let mut res = Vec::new();
239 let mut offset: TextSize = 0.into(); 256 let mut offset: TextSize = 0.into();
240 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' }; 257 let marker: fn(char) -> bool = if line.contains('^') { |c| c == '^' } else { |c| c == '|' };
241 loop { 258 while let Some(idx) = line.find(marker) {
242 match line.find(marker) { 259 offset += TextSize::try_from(idx).unwrap();
243 Some(idx) => { 260 line = &line[idx..];
244 offset += TextSize::try_from(idx).unwrap();
245 line = &line[idx..];
246 }
247 None => break,
248 };
249 261
250 let mut len = line.chars().take_while(|&it| it == '^').count(); 262 let mut len = line.chars().take_while(|&it| it == '^').count();
251 let mut continuation = false; 263 let mut continuation = false;
@@ -256,12 +268,20 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
256 } 268 }
257 let range = TextRange::at(offset, len.try_into().unwrap()); 269 let range = TextRange::at(offset, len.try_into().unwrap());
258 let next = line[len..].find(marker).map_or(line.len(), |it| it + len); 270 let next = line[len..].find(marker).map_or(line.len(), |it| it + len);
259 let content = line[len..][..next - len].trim().to_string(); 271 let mut content = &line[len..][..next - len];
272
273 let mut file = false;
274 if !continuation && content.starts_with("file") {
275 file = true;
276 content = &content["file".len()..]
277 }
278
279 let content = content.trim().to_string();
260 280
261 let annotation = if continuation { 281 let annotation = if continuation {
262 LineAnnotation::Continuation { offset: range.end(), content } 282 LineAnnotation::Continuation { offset: range.end(), content }
263 } else { 283 } else {
264 LineAnnotation::Annotation { range, content } 284 LineAnnotation::Annotation { range, content, file }
265 }; 285 };
266 res.push(annotation); 286 res.push(annotation);
267 287
@@ -282,16 +302,20 @@ fn main() {
282 zoo + 1 302 zoo + 1
283} //^^^ type: 303} //^^^ type:
284 // | i32 304 // | i32
305
306// ^file
285 "#, 307 "#,
286 ); 308 );
287 let res = extract_annotations(&text) 309 let res = extract_annotations(&text)
288 .into_iter() 310 .into_iter()
289 .map(|(range, ann)| (&text[range], ann)) 311 .map(|(range, ann)| (&text[range], ann))
290 .collect::<Vec<_>>(); 312 .collect::<Vec<_>>();
313
291 assert_eq!( 314 assert_eq!(
292 res, 315 res[..3],
293 vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),] 316 [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into())]
294 ); 317 );
318 assert_eq!(res[3].0.len(), 115);
295} 319}
296 320
297/// Returns `false` if slow tests should not run, otherwise returns `true` and 321/// Returns `false` if slow tests should not run, otherwise returns `true` and