1use super::*;
2use crate::LanguageConfig;
3use rand::rngs::StdRng;
4use std::{env, ops::Range, sync::Arc};
5use text::Buffer;
6use tree_sitter::Node;
7use unindent::Unindent as _;
8use util::test::marked_text_ranges;
9
10#[test]
11fn test_splice_included_ranges() {
12 let ranges = vec![ts_range(20..30), ts_range(50..60), ts_range(80..90)];
13
14 let new_ranges = splice_included_ranges(
15 ranges.clone(),
16 &[54..56, 58..68],
17 &[ts_range(50..54), ts_range(59..67)],
18 );
19 assert_eq!(
20 new_ranges,
21 &[
22 ts_range(20..30),
23 ts_range(50..54),
24 ts_range(59..67),
25 ts_range(80..90),
26 ]
27 );
28
29 let new_ranges = splice_included_ranges(ranges.clone(), &[70..71, 91..100], &[]);
30 assert_eq!(
31 new_ranges,
32 &[ts_range(20..30), ts_range(50..60), ts_range(80..90)]
33 );
34
35 let new_ranges =
36 splice_included_ranges(ranges.clone(), &[], &[ts_range(0..2), ts_range(70..75)]);
37 assert_eq!(
38 new_ranges,
39 &[
40 ts_range(0..2),
41 ts_range(20..30),
42 ts_range(50..60),
43 ts_range(70..75),
44 ts_range(80..90)
45 ]
46 );
47
48 let new_ranges = splice_included_ranges(ranges.clone(), &[30..50], &[ts_range(25..55)]);
49 assert_eq!(new_ranges, &[ts_range(25..55), ts_range(80..90)]);
50
51 fn ts_range(range: Range<usize>) -> tree_sitter::Range {
52 tree_sitter::Range {
53 start_byte: range.start,
54 start_point: tree_sitter::Point {
55 row: 0,
56 column: range.start,
57 },
58 end_byte: range.end,
59 end_point: tree_sitter::Point {
60 row: 0,
61 column: range.end,
62 },
63 }
64 }
65}
66
67#[gpui::test]
68fn test_syntax_map_layers_for_range() {
69 let registry = Arc::new(LanguageRegistry::test());
70 let language = Arc::new(rust_lang());
71 registry.add(language.clone());
72
73 let mut buffer = Buffer::new(
74 0,
75 0,
76 r#"
77 fn a() {
78 assert_eq!(
79 b(vec![C {}]),
80 vec![d.e],
81 );
82 println!("{}", f(|_| true));
83 }
84 "#
85 .unindent(),
86 );
87
88 let mut syntax_map = SyntaxMap::new();
89 syntax_map.set_language_registry(registry.clone());
90 syntax_map.reparse(language.clone(), &buffer);
91
92 assert_layers_for_range(
93 &syntax_map,
94 &buffer,
95 Point::new(2, 0)..Point::new(2, 0),
96 &[
97 "...(function_item ... (block (expression_statement (macro_invocation...",
98 "...(tuple_expression (call_expression ... arguments: (arguments (macro_invocation...",
99 ],
100 );
101 assert_layers_for_range(
102 &syntax_map,
103 &buffer,
104 Point::new(2, 14)..Point::new(2, 16),
105 &[
106 "...(function_item ...",
107 "...(tuple_expression (call_expression ... arguments: (arguments (macro_invocation...",
108 "...(array_expression (struct_expression ...",
109 ],
110 );
111 assert_layers_for_range(
112 &syntax_map,
113 &buffer,
114 Point::new(3, 14)..Point::new(3, 16),
115 &[
116 "...(function_item ...",
117 "...(tuple_expression (call_expression ... arguments: (arguments (macro_invocation...",
118 "...(array_expression (field_expression ...",
119 ],
120 );
121 assert_layers_for_range(
122 &syntax_map,
123 &buffer,
124 Point::new(5, 12)..Point::new(5, 16),
125 &[
126 "...(function_item ...",
127 "...(call_expression ... (arguments (closure_expression ...",
128 ],
129 );
130
131 // Replace a vec! macro invocation with a plain slice, removing a syntactic layer.
132 let macro_name_range = range_for_text(&buffer, "vec!");
133 buffer.edit([(macro_name_range, "&")]);
134 syntax_map.interpolate(&buffer);
135 syntax_map.reparse(language.clone(), &buffer);
136
137 assert_layers_for_range(
138 &syntax_map,
139 &buffer,
140 Point::new(2, 14)..Point::new(2, 16),
141 &[
142 "...(function_item ...",
143 "...(tuple_expression (call_expression ... arguments: (arguments (reference_expression value: (array_expression...",
144 ],
145 );
146
147 // Put the vec! macro back, adding back the syntactic layer.
148 buffer.undo();
149 syntax_map.interpolate(&buffer);
150 syntax_map.reparse(language.clone(), &buffer);
151
152 assert_layers_for_range(
153 &syntax_map,
154 &buffer,
155 Point::new(2, 14)..Point::new(2, 16),
156 &[
157 "...(function_item ...",
158 "...(tuple_expression (call_expression ... arguments: (arguments (macro_invocation...",
159 "...(array_expression (struct_expression ...",
160 ],
161 );
162}
163
164#[gpui::test]
165fn test_dynamic_language_injection() {
166 let registry = Arc::new(LanguageRegistry::test());
167 let markdown = Arc::new(markdown_lang());
168 registry.add(markdown.clone());
169 registry.add(Arc::new(rust_lang()));
170 registry.add(Arc::new(ruby_lang()));
171
172 let mut buffer = Buffer::new(
173 0,
174 0,
175 r#"
176 This is a code block:
177
178 ```rs
179 fn foo() {}
180 ```
181 "#
182 .unindent(),
183 );
184
185 let mut syntax_map = SyntaxMap::new();
186 syntax_map.set_language_registry(registry.clone());
187 syntax_map.reparse(markdown.clone(), &buffer);
188 assert_layers_for_range(
189 &syntax_map,
190 &buffer,
191 Point::new(3, 0)..Point::new(3, 0),
192 &[
193 "...(fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (code_fence_content) (fenced_code_block_delimiter...",
194 "...(function_item name: (identifier) parameters: (parameters) body: (block)...",
195 ],
196 );
197
198 // Replace Rust with Ruby in code block.
199 let macro_name_range = range_for_text(&buffer, "rs");
200 buffer.edit([(macro_name_range, "ruby")]);
201 syntax_map.interpolate(&buffer);
202 syntax_map.reparse(markdown.clone(), &buffer);
203 assert_layers_for_range(
204 &syntax_map,
205 &buffer,
206 Point::new(3, 0)..Point::new(3, 0),
207 &[
208 "...(fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (code_fence_content) (fenced_code_block_delimiter...",
209 "...(call method: (identifier) arguments: (argument_list (call method: (identifier) arguments: (argument_list) block: (block)...",
210 ],
211 );
212
213 // Replace Ruby with a language that hasn't been loaded yet.
214 let macro_name_range = range_for_text(&buffer, "ruby");
215 buffer.edit([(macro_name_range, "html")]);
216 syntax_map.interpolate(&buffer);
217 syntax_map.reparse(markdown.clone(), &buffer);
218 assert_layers_for_range(
219 &syntax_map,
220 &buffer,
221 Point::new(3, 0)..Point::new(3, 0),
222 &[
223 "...(fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (code_fence_content) (fenced_code_block_delimiter..."
224 ],
225 );
226 assert!(syntax_map.contains_unknown_injections());
227
228 registry.add(Arc::new(html_lang()));
229 syntax_map.reparse(markdown.clone(), &buffer);
230 assert_layers_for_range(
231 &syntax_map,
232 &buffer,
233 Point::new(3, 0)..Point::new(3, 0),
234 &[
235 "...(fenced_code_block (fenced_code_block_delimiter) (info_string (language)) (code_fence_content) (fenced_code_block_delimiter...",
236 "(fragment (text))",
237 ],
238 );
239 assert!(!syntax_map.contains_unknown_injections());
240}
241
242#[gpui::test]
243fn test_typing_multiple_new_injections() {
244 let (buffer, syntax_map) = test_edit_sequence(
245 "Rust",
246 &[
247 "fn a() { dbg }",
248 "fn a() { dbg«!» }",
249 "fn a() { dbg!«()» }",
250 "fn a() { dbg!(«b») }",
251 "fn a() { dbg!(b«.») }",
252 "fn a() { dbg!(b.«c») }",
253 "fn a() { dbg!(b.c«()») }",
254 "fn a() { dbg!(b.c(«vec»)) }",
255 "fn a() { dbg!(b.c(vec«!»)) }",
256 "fn a() { dbg!(b.c(vec!«[]»)) }",
257 "fn a() { dbg!(b.c(vec![«d»])) }",
258 "fn a() { dbg!(b.c(vec![d«.»])) }",
259 "fn a() { dbg!(b.c(vec![d.«e»])) }",
260 ],
261 );
262
263 assert_capture_ranges(
264 &syntax_map,
265 &buffer,
266 &["field"],
267 "fn a() { dbg!(b.«c»(vec![d.«e»])) }",
268 );
269}
270
271#[gpui::test]
272fn test_pasting_new_injection_line_between_others() {
273 let (buffer, syntax_map) = test_edit_sequence(
274 "Rust",
275 &[
276 "
277 fn a() {
278 b!(B {});
279 c!(C {});
280 d!(D {});
281 e!(E {});
282 f!(F {});
283 g!(G {});
284 }
285 ",
286 "
287 fn a() {
288 b!(B {});
289 c!(C {});
290 d!(D {});
291 « h!(H {});
292 » e!(E {});
293 f!(F {});
294 g!(G {});
295 }
296 ",
297 ],
298 );
299
300 assert_capture_ranges(
301 &syntax_map,
302 &buffer,
303 &["struct"],
304 "
305 fn a() {
306 b!(«B {}»);
307 c!(«C {}»);
308 d!(«D {}»);
309 h!(«H {}»);
310 e!(«E {}»);
311 f!(«F {}»);
312 g!(«G {}»);
313 }
314 ",
315 );
316}
317
318#[gpui::test]
319fn test_joining_injections_with_child_injections() {
320 let (buffer, syntax_map) = test_edit_sequence(
321 "Rust",
322 &[
323 "
324 fn a() {
325 b!(
326 c![one.two.three],
327 d![four.five.six],
328 );
329 e!(
330 f![seven.eight],
331 );
332 }
333 ",
334 "
335 fn a() {
336 b!(
337 c![one.two.three],
338 d![four.five.six],
339 ˇ f![seven.eight],
340 );
341 }
342 ",
343 ],
344 );
345
346 assert_capture_ranges(
347 &syntax_map,
348 &buffer,
349 &["field"],
350 "
351 fn a() {
352 b!(
353 c![one.«two».«three»],
354 d![four.«five».«six»],
355 f![seven.«eight»],
356 );
357 }
358 ",
359 );
360}
361
362#[gpui::test]
363fn test_editing_edges_of_injection() {
364 test_edit_sequence(
365 "Rust",
366 &[
367 "
368 fn a() {
369 b!(c!())
370 }
371 ",
372 "
373 fn a() {
374 «d»!(c!())
375 }
376 ",
377 "
378 fn a() {
379 «e»d!(c!())
380 }
381 ",
382 "
383 fn a() {
384 ed!«[»c!()«]»
385 }
386 ",
387 ],
388 );
389}
390
391#[gpui::test]
392fn test_edits_preceding_and_intersecting_injection() {
393 test_edit_sequence(
394 "Rust",
395 &[
396 //
397 "const aaaaaaaaaaaa: B = c!(d(e.f));",
398 "const aˇa: B = c!(d(eˇ));",
399 ],
400 );
401}
402
403#[gpui::test]
404fn test_non_local_changes_create_injections() {
405 test_edit_sequence(
406 "Rust",
407 &[
408 "
409 // a! {
410 static B: C = d;
411 // }
412 ",
413 "
414 ˇa! {
415 static B: C = d;
416 ˇ}
417 ",
418 ],
419 );
420}
421
422#[gpui::test]
423fn test_creating_many_injections_in_one_edit() {
424 test_edit_sequence(
425 "Rust",
426 &[
427 "
428 fn a() {
429 one(Two::three(3));
430 four(Five::six(6));
431 seven(Eight::nine(9));
432 }
433 ",
434 "
435 fn a() {
436 one«!»(Two::three(3));
437 four«!»(Five::six(6));
438 seven«!»(Eight::nine(9));
439 }
440 ",
441 "
442 fn a() {
443 one!(Two::three«!»(3));
444 four!(Five::six«!»(6));
445 seven!(Eight::nine«!»(9));
446 }
447 ",
448 ],
449 );
450}
451
452#[gpui::test]
453fn test_editing_across_injection_boundary() {
454 test_edit_sequence(
455 "Rust",
456 &[
457 "
458 fn one() {
459 two();
460 three!(
461 three.four,
462 five.six,
463 );
464 }
465 ",
466 "
467 fn one() {
468 two();
469 th«irty_five![»
470 three.four,
471 five.six,
472 « seven.eight,
473 ];»
474 }
475 ",
476 ],
477 );
478}
479
480#[gpui::test]
481fn test_removing_injection_by_replacing_across_boundary() {
482 test_edit_sequence(
483 "Rust",
484 &[
485 "
486 fn one() {
487 two!(
488 three.four,
489 );
490 }
491 ",
492 "
493 fn one() {
494 t«en
495 .eleven(
496 twelve,
497 »
498 three.four,
499 );
500 }
501 ",
502 ],
503 );
504}
505
506#[gpui::test]
507fn test_combined_injections() {
508 let (buffer, syntax_map) = test_edit_sequence(
509 "ERB",
510 &[
511 "
512 <body>
513 <% if @one %>
514 <div class=one>
515 <% else %>
516 <div class=two>
517 <% end %>
518 </div>
519 </body>
520 ",
521 "
522 <body>
523 <% if @one %>
524 <div class=one>
525 ˇ else ˇ
526 <div class=two>
527 <% end %>
528 </div>
529 </body>
530 ",
531 "
532 <body>
533 <% if @one «;» end %>
534 </div>
535 </body>
536 ",
537 ],
538 );
539
540 assert_capture_ranges(
541 &syntax_map,
542 &buffer,
543 &["tag", "ivar"],
544 "
545 <«body»>
546 <% if «@one» ; end %>
547 </«div»>
548 </«body»>
549 ",
550 );
551}
552
553#[gpui::test]
554fn test_combined_injections_empty_ranges() {
555 test_edit_sequence(
556 "ERB",
557 &[
558 "
559 <% if @one %>
560 <% else %>
561 <% end %>
562 ",
563 "
564 <% if @one %>
565 ˇ<% end %>
566 ",
567 ],
568 );
569}
570
571#[gpui::test]
572fn test_combined_injections_edit_edges_of_ranges() {
573 let (buffer, syntax_map) = test_edit_sequence(
574 "ERB",
575 &[
576 "
577 <%= one @two %>
578 <%= three @four %>
579 ",
580 "
581 <%= one @two %ˇ
582 <%= three @four %>
583 ",
584 "
585 <%= one @two %«>»
586 <%= three @four %>
587 ",
588 ],
589 );
590
591 assert_capture_ranges(
592 &syntax_map,
593 &buffer,
594 &["tag", "ivar"],
595 "
596 <%= one «@two» %>
597 <%= three «@four» %>
598 ",
599 );
600}
601
602#[gpui::test]
603fn test_combined_injections_splitting_some_injections() {
604 let (_buffer, _syntax_map) = test_edit_sequence(
605 "ERB",
606 &[
607 r#"
608 <%A if b(:c) %>
609 d
610 <% end %>
611 eee
612 <% f %>
613 "#,
614 r#"
615 <%« AAAAAAA %>
616 hhhhhhh
617 <%=» if b(:c) %>
618 d
619 <% end %>
620 eee
621 <% f %>
622 "#,
623 ],
624 );
625}
626
627#[gpui::test]
628fn test_combined_injections_inside_injections() {
629 let (_buffer, _syntax_map) = test_edit_sequence(
630 "Markdown",
631 &[
632 r#"
633 here is some ERB code:
634
635 ```erb
636 <ul>
637 <% people.each do |person| %>
638 <li><%= person.name %></li>
639 <% end %>
640 </ul>
641 ```
642 "#,
643 r#"
644 here is some ERB code:
645
646 ```erb
647 <ul>
648 <% people«2».each do |person| %>
649 <li><%= person.name %></li>
650 <% end %>
651 </ul>
652 ```
653 "#,
654 ],
655 );
656}
657
658#[gpui::test(iterations = 50)]
659fn test_random_syntax_map_edits(mut rng: StdRng) {
660 let operations = env::var("OPERATIONS")
661 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
662 .unwrap_or(10);
663
664 let text = r#"
665 fn test_something() {
666 let vec = vec![5, 1, 3, 8];
667 assert_eq!(
668 vec
669 .into_iter()
670 .map(|i| i * 2)
671 .collect::<Vec<usize>>(),
672 vec![
673 5 * 2, 1 * 2, 3 * 2, 8 * 2
674 ],
675 );
676 }
677 "#
678 .unindent()
679 .repeat(2);
680
681 let registry = Arc::new(LanguageRegistry::test());
682 let language = Arc::new(rust_lang());
683 registry.add(language.clone());
684 let mut buffer = Buffer::new(0, 0, text);
685
686 let mut syntax_map = SyntaxMap::new();
687 syntax_map.set_language_registry(registry.clone());
688 syntax_map.reparse(language.clone(), &buffer);
689
690 let mut reference_syntax_map = SyntaxMap::new();
691 reference_syntax_map.set_language_registry(registry.clone());
692
693 log::info!("initial text:\n{}", buffer.text());
694
695 for _ in 0..operations {
696 let prev_buffer = buffer.snapshot();
697 let prev_syntax_map = syntax_map.snapshot();
698
699 buffer.randomly_edit(&mut rng, 3);
700 log::info!("text:\n{}", buffer.text());
701
702 syntax_map.interpolate(&buffer);
703 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
704
705 syntax_map.reparse(language.clone(), &buffer);
706
707 reference_syntax_map.clear();
708 reference_syntax_map.reparse(language.clone(), &buffer);
709 }
710
711 for i in 0..operations {
712 let i = operations - i - 1;
713 buffer.undo();
714 log::info!("undoing operation {}", i);
715 log::info!("text:\n{}", buffer.text());
716
717 syntax_map.interpolate(&buffer);
718 syntax_map.reparse(language.clone(), &buffer);
719
720 reference_syntax_map.clear();
721 reference_syntax_map.reparse(language.clone(), &buffer);
722 assert_eq!(
723 syntax_map.layers(&buffer).len(),
724 reference_syntax_map.layers(&buffer).len(),
725 "wrong number of layers after undoing edit {i}"
726 );
727 }
728
729 let layers = syntax_map.layers(&buffer);
730 let reference_layers = reference_syntax_map.layers(&buffer);
731 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
732 assert_eq!(
733 edited_layer.node().to_sexp(),
734 reference_layer.node().to_sexp()
735 );
736 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
737 }
738}
739
740#[gpui::test(iterations = 50)]
741fn test_random_syntax_map_edits_with_combined_injections(mut rng: StdRng) {
742 let operations = env::var("OPERATIONS")
743 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
744 .unwrap_or(10);
745
746 let text = r#"
747 <div id="main">
748 <% if one?(:two) %>
749 <p class="three" four>
750 <%= yield :five %>
751 </p>
752 <% elsif Six.seven(8) %>
753 <p id="three" four>
754 <%= yield :five %>
755 </p>
756 <% else %>
757 <span>Ok</span>
758 <% end %>
759 </div>
760 "#
761 .unindent()
762 .repeat(8);
763
764 let registry = Arc::new(LanguageRegistry::test());
765 let language = Arc::new(erb_lang());
766 registry.add(language.clone());
767 registry.add(Arc::new(ruby_lang()));
768 registry.add(Arc::new(html_lang()));
769 let mut buffer = Buffer::new(0, 0, text);
770
771 let mut syntax_map = SyntaxMap::new();
772 syntax_map.set_language_registry(registry.clone());
773 syntax_map.reparse(language.clone(), &buffer);
774
775 let mut reference_syntax_map = SyntaxMap::new();
776 reference_syntax_map.set_language_registry(registry.clone());
777
778 log::info!("initial text:\n{}", buffer.text());
779
780 for _ in 0..operations {
781 let prev_buffer = buffer.snapshot();
782 let prev_syntax_map = syntax_map.snapshot();
783
784 buffer.randomly_edit(&mut rng, 3);
785 log::info!("text:\n{}", buffer.text());
786
787 syntax_map.interpolate(&buffer);
788 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
789
790 syntax_map.reparse(language.clone(), &buffer);
791
792 reference_syntax_map.clear();
793 reference_syntax_map.reparse(language.clone(), &buffer);
794 }
795
796 for i in 0..operations {
797 let i = operations - i - 1;
798 buffer.undo();
799 log::info!("undoing operation {}", i);
800 log::info!("text:\n{}", buffer.text());
801
802 syntax_map.interpolate(&buffer);
803 syntax_map.reparse(language.clone(), &buffer);
804
805 reference_syntax_map.clear();
806 reference_syntax_map.reparse(language.clone(), &buffer);
807 assert_eq!(
808 syntax_map.layers(&buffer).len(),
809 reference_syntax_map.layers(&buffer).len(),
810 "wrong number of layers after undoing edit {i}"
811 );
812 }
813
814 let layers = syntax_map.layers(&buffer);
815 let reference_layers = reference_syntax_map.layers(&buffer);
816 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
817 assert_eq!(
818 edited_layer.node().to_sexp(),
819 reference_layer.node().to_sexp()
820 );
821 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
822 }
823}
824
825fn check_interpolation(
826 old_syntax_map: &SyntaxSnapshot,
827 new_syntax_map: &SyntaxSnapshot,
828 old_buffer: &BufferSnapshot,
829 new_buffer: &BufferSnapshot,
830) {
831 let edits = new_buffer
832 .edits_since::<usize>(&old_buffer.version())
833 .collect::<Vec<_>>();
834
835 for (old_layer, new_layer) in old_syntax_map
836 .layers
837 .iter()
838 .zip(new_syntax_map.layers.iter())
839 {
840 assert_eq!(old_layer.range, new_layer.range);
841 let Some(old_tree) = old_layer.content.tree() else { continue };
842 let Some(new_tree) = new_layer.content.tree() else { continue };
843 let old_start_byte = old_layer.range.start.to_offset(old_buffer);
844 let new_start_byte = new_layer.range.start.to_offset(new_buffer);
845 let old_start_point = old_layer.range.start.to_point(old_buffer).to_ts_point();
846 let new_start_point = new_layer.range.start.to_point(new_buffer).to_ts_point();
847 let old_node = old_tree.root_node_with_offset(old_start_byte, old_start_point);
848 let new_node = new_tree.root_node_with_offset(new_start_byte, new_start_point);
849 check_node_edits(
850 old_layer.depth,
851 &old_layer.range,
852 old_node,
853 new_node,
854 old_buffer,
855 new_buffer,
856 &edits,
857 );
858 }
859
860 fn check_node_edits(
861 depth: usize,
862 range: &Range<Anchor>,
863 old_node: Node,
864 new_node: Node,
865 old_buffer: &BufferSnapshot,
866 new_buffer: &BufferSnapshot,
867 edits: &[text::Edit<usize>],
868 ) {
869 assert_eq!(old_node.kind(), new_node.kind());
870
871 let old_range = old_node.byte_range();
872 let new_range = new_node.byte_range();
873
874 let is_edited = edits
875 .iter()
876 .any(|edit| edit.new.start < new_range.end && edit.new.end > new_range.start);
877 if is_edited {
878 assert!(
879 new_node.has_changes(),
880 concat!(
881 "failed to mark node as edited.\n",
882 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
883 "node kind: {}, old node range: {:?}, new node range: {:?}",
884 ),
885 depth,
886 range.to_offset(old_buffer),
887 range.to_offset(new_buffer),
888 new_node.kind(),
889 old_range,
890 new_range,
891 );
892 }
893
894 if !new_node.has_changes() {
895 assert_eq!(
896 old_buffer
897 .text_for_range(old_range.clone())
898 .collect::<String>(),
899 new_buffer
900 .text_for_range(new_range.clone())
901 .collect::<String>(),
902 concat!(
903 "mismatched text for node\n",
904 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
905 "node kind: {}, old node range:{:?}, new node range:{:?}",
906 ),
907 depth,
908 range.to_offset(old_buffer),
909 range.to_offset(new_buffer),
910 new_node.kind(),
911 old_range,
912 new_range,
913 );
914 }
915
916 for i in 0..new_node.child_count() {
917 check_node_edits(
918 depth,
919 range,
920 old_node.child(i).unwrap(),
921 new_node.child(i).unwrap(),
922 old_buffer,
923 new_buffer,
924 edits,
925 )
926 }
927 }
928}
929
930fn test_edit_sequence(language_name: &str, steps: &[&str]) -> (Buffer, SyntaxMap) {
931 let registry = Arc::new(LanguageRegistry::test());
932 registry.add(Arc::new(rust_lang()));
933 registry.add(Arc::new(ruby_lang()));
934 registry.add(Arc::new(html_lang()));
935 registry.add(Arc::new(erb_lang()));
936 registry.add(Arc::new(markdown_lang()));
937 let language = registry
938 .language_for_name(language_name)
939 .now_or_never()
940 .unwrap()
941 .unwrap();
942 let mut buffer = Buffer::new(0, 0, Default::default());
943
944 let mut mutated_syntax_map = SyntaxMap::new();
945 mutated_syntax_map.set_language_registry(registry.clone());
946 mutated_syntax_map.reparse(language.clone(), &buffer);
947
948 for (i, marked_string) in steps.into_iter().enumerate() {
949 buffer.edit_via_marked_text(&marked_string.unindent());
950
951 // Reparse the syntax map
952 mutated_syntax_map.interpolate(&buffer);
953 mutated_syntax_map.reparse(language.clone(), &buffer);
954
955 // Create a second syntax map from scratch
956 let mut reference_syntax_map = SyntaxMap::new();
957 reference_syntax_map.set_language_registry(registry.clone());
958 reference_syntax_map.reparse(language.clone(), &buffer);
959
960 // Compare the mutated syntax map to the new syntax map
961 let mutated_layers = mutated_syntax_map.layers(&buffer);
962 let reference_layers = reference_syntax_map.layers(&buffer);
963 assert_eq!(
964 mutated_layers.len(),
965 reference_layers.len(),
966 "wrong number of layers at step {i}"
967 );
968 for (edited_layer, reference_layer) in
969 mutated_layers.into_iter().zip(reference_layers.into_iter())
970 {
971 assert_eq!(
972 edited_layer.node().to_sexp(),
973 reference_layer.node().to_sexp(),
974 "different layer at step {i}"
975 );
976 assert_eq!(
977 edited_layer.node().range(),
978 reference_layer.node().range(),
979 "different layer at step {i}"
980 );
981 }
982 }
983
984 (buffer, mutated_syntax_map)
985}
986
987fn html_lang() -> Language {
988 Language::new(
989 LanguageConfig {
990 name: "HTML".into(),
991 path_suffixes: vec!["html".to_string()],
992 ..Default::default()
993 },
994 Some(tree_sitter_html::language()),
995 )
996 .with_highlights_query(
997 r#"
998 (tag_name) @tag
999 (erroneous_end_tag_name) @tag
1000 (attribute_name) @property
1001 "#,
1002 )
1003 .unwrap()
1004}
1005
1006fn ruby_lang() -> Language {
1007 Language::new(
1008 LanguageConfig {
1009 name: "Ruby".into(),
1010 path_suffixes: vec!["rb".to_string()],
1011 ..Default::default()
1012 },
1013 Some(tree_sitter_ruby::language()),
1014 )
1015 .with_highlights_query(
1016 r#"
1017 ["if" "do" "else" "end"] @keyword
1018 (instance_variable) @ivar
1019 "#,
1020 )
1021 .unwrap()
1022}
1023
1024fn erb_lang() -> Language {
1025 Language::new(
1026 LanguageConfig {
1027 name: "ERB".into(),
1028 path_suffixes: vec!["erb".to_string()],
1029 ..Default::default()
1030 },
1031 Some(tree_sitter_embedded_template::language()),
1032 )
1033 .with_highlights_query(
1034 r#"
1035 ["<%" "%>"] @keyword
1036 "#,
1037 )
1038 .unwrap()
1039 .with_injection_query(
1040 r#"
1041 (
1042 (code) @content
1043 (#set! "language" "ruby")
1044 (#set! "combined")
1045 )
1046
1047 (
1048 (content) @content
1049 (#set! "language" "html")
1050 (#set! "combined")
1051 )
1052 "#,
1053 )
1054 .unwrap()
1055}
1056
1057fn rust_lang() -> Language {
1058 Language::new(
1059 LanguageConfig {
1060 name: "Rust".into(),
1061 path_suffixes: vec!["rs".to_string()],
1062 ..Default::default()
1063 },
1064 Some(tree_sitter_rust::language()),
1065 )
1066 .with_highlights_query(
1067 r#"
1068 (field_identifier) @field
1069 (struct_expression) @struct
1070 "#,
1071 )
1072 .unwrap()
1073 .with_injection_query(
1074 r#"
1075 (macro_invocation
1076 (token_tree) @content
1077 (#set! "language" "rust"))
1078 "#,
1079 )
1080 .unwrap()
1081}
1082
1083fn markdown_lang() -> Language {
1084 Language::new(
1085 LanguageConfig {
1086 name: "Markdown".into(),
1087 path_suffixes: vec!["md".into()],
1088 ..Default::default()
1089 },
1090 Some(tree_sitter_markdown::language()),
1091 )
1092 .with_injection_query(
1093 r#"
1094 (fenced_code_block
1095 (info_string
1096 (language) @language)
1097 (code_fence_content) @content)
1098 "#,
1099 )
1100 .unwrap()
1101}
1102
1103fn range_for_text(buffer: &Buffer, text: &str) -> Range<usize> {
1104 let start = buffer.as_rope().to_string().find(text).unwrap();
1105 start..start + text.len()
1106}
1107
1108fn assert_layers_for_range(
1109 syntax_map: &SyntaxMap,
1110 buffer: &BufferSnapshot,
1111 range: Range<Point>,
1112 expected_layers: &[&str],
1113) {
1114 let layers = syntax_map
1115 .layers_for_range(range, &buffer)
1116 .collect::<Vec<_>>();
1117 assert_eq!(
1118 layers.len(),
1119 expected_layers.len(),
1120 "wrong number of layers"
1121 );
1122 for (i, (layer, expected_s_exp)) in layers.iter().zip(expected_layers.iter()).enumerate() {
1123 let actual_s_exp = layer.node().to_sexp();
1124 assert!(
1125 string_contains_sequence(
1126 &actual_s_exp,
1127 &expected_s_exp.split("...").collect::<Vec<_>>()
1128 ),
1129 "layer {i}:\n\nexpected: {expected_s_exp}\nactual: {actual_s_exp}",
1130 );
1131 }
1132}
1133
1134fn assert_capture_ranges(
1135 syntax_map: &SyntaxMap,
1136 buffer: &BufferSnapshot,
1137 highlight_query_capture_names: &[&str],
1138 marked_string: &str,
1139) {
1140 let mut actual_ranges = Vec::<Range<usize>>::new();
1141 let captures = syntax_map.captures(0..buffer.len(), buffer, |grammar| {
1142 grammar.highlights_query.as_ref()
1143 });
1144 let queries = captures
1145 .grammars()
1146 .iter()
1147 .map(|grammar| grammar.highlights_query.as_ref().unwrap())
1148 .collect::<Vec<_>>();
1149 for capture in captures {
1150 let name = &queries[capture.grammar_index].capture_names()[capture.index as usize];
1151 if highlight_query_capture_names.contains(&name.as_str()) {
1152 actual_ranges.push(capture.node.byte_range());
1153 }
1154 }
1155
1156 let (text, expected_ranges) = marked_text_ranges(&marked_string.unindent(), false);
1157 assert_eq!(text, buffer.text());
1158 assert_eq!(actual_ranges, expected_ranges);
1159}
1160
1161pub fn string_contains_sequence(text: &str, parts: &[&str]) -> bool {
1162 let mut last_part_end = 0;
1163 for part in parts {
1164 if let Some(start_ix) = text[last_part_end..].find(part) {
1165 last_part_end = start_ix + part.len();
1166 } else {
1167 return false;
1168 }
1169 }
1170 true
1171}