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]
659fn test_empty_combined_injections_inside_injections() {
660 let (buffer, syntax_map) = test_edit_sequence(
661 "Markdown",
662 &[r#"
663 ```erb
664 hello
665 ```
666
667 goodbye
668 "#],
669 );
670
671 assert_layers_for_range(
672 &syntax_map,
673 &buffer,
674 Point::new(0, 0)..Point::new(5, 0),
675 &[
676 "...(paragraph)...",
677 "(template...",
678 "(fragment...",
679 // The ruby syntax tree should be empty, since there are
680 // no interpolations in the ERB template.
681 "(program)",
682 ],
683 );
684}
685
686#[gpui::test(iterations = 50)]
687fn test_random_syntax_map_edits(mut rng: StdRng) {
688 let operations = env::var("OPERATIONS")
689 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
690 .unwrap_or(10);
691
692 let text = r#"
693 fn test_something() {
694 let vec = vec![5, 1, 3, 8];
695 assert_eq!(
696 vec
697 .into_iter()
698 .map(|i| i * 2)
699 .collect::<Vec<usize>>(),
700 vec![
701 5 * 2, 1 * 2, 3 * 2, 8 * 2
702 ],
703 );
704 }
705 "#
706 .unindent()
707 .repeat(2);
708
709 let registry = Arc::new(LanguageRegistry::test());
710 let language = Arc::new(rust_lang());
711 registry.add(language.clone());
712 let mut buffer = Buffer::new(0, 0, text);
713
714 let mut syntax_map = SyntaxMap::new();
715 syntax_map.set_language_registry(registry.clone());
716 syntax_map.reparse(language.clone(), &buffer);
717
718 let mut reference_syntax_map = SyntaxMap::new();
719 reference_syntax_map.set_language_registry(registry.clone());
720
721 log::info!("initial text:\n{}", buffer.text());
722
723 for _ in 0..operations {
724 let prev_buffer = buffer.snapshot();
725 let prev_syntax_map = syntax_map.snapshot();
726
727 buffer.randomly_edit(&mut rng, 3);
728 log::info!("text:\n{}", buffer.text());
729
730 syntax_map.interpolate(&buffer);
731 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
732
733 syntax_map.reparse(language.clone(), &buffer);
734
735 reference_syntax_map.clear();
736 reference_syntax_map.reparse(language.clone(), &buffer);
737 }
738
739 for i in 0..operations {
740 let i = operations - i - 1;
741 buffer.undo();
742 log::info!("undoing operation {}", i);
743 log::info!("text:\n{}", buffer.text());
744
745 syntax_map.interpolate(&buffer);
746 syntax_map.reparse(language.clone(), &buffer);
747
748 reference_syntax_map.clear();
749 reference_syntax_map.reparse(language.clone(), &buffer);
750 assert_eq!(
751 syntax_map.layers(&buffer).len(),
752 reference_syntax_map.layers(&buffer).len(),
753 "wrong number of layers after undoing edit {i}"
754 );
755 }
756
757 let layers = syntax_map.layers(&buffer);
758 let reference_layers = reference_syntax_map.layers(&buffer);
759 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
760 assert_eq!(
761 edited_layer.node().to_sexp(),
762 reference_layer.node().to_sexp()
763 );
764 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
765 }
766}
767
768#[gpui::test(iterations = 50)]
769fn test_random_syntax_map_edits_with_combined_injections(mut rng: StdRng) {
770 let operations = env::var("OPERATIONS")
771 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
772 .unwrap_or(10);
773
774 let text = r#"
775 <div id="main">
776 <% if one?(:two) %>
777 <p class="three" four>
778 <%= yield :five %>
779 </p>
780 <% elsif Six.seven(8) %>
781 <p id="three" four>
782 <%= yield :five %>
783 </p>
784 <% else %>
785 <span>Ok</span>
786 <% end %>
787 </div>
788 "#
789 .unindent()
790 .repeat(8);
791
792 let registry = Arc::new(LanguageRegistry::test());
793 let language = Arc::new(erb_lang());
794 registry.add(language.clone());
795 registry.add(Arc::new(ruby_lang()));
796 registry.add(Arc::new(html_lang()));
797 let mut buffer = Buffer::new(0, 0, text);
798
799 let mut syntax_map = SyntaxMap::new();
800 syntax_map.set_language_registry(registry.clone());
801 syntax_map.reparse(language.clone(), &buffer);
802
803 let mut reference_syntax_map = SyntaxMap::new();
804 reference_syntax_map.set_language_registry(registry.clone());
805
806 log::info!("initial text:\n{}", buffer.text());
807
808 for _ in 0..operations {
809 let prev_buffer = buffer.snapshot();
810 let prev_syntax_map = syntax_map.snapshot();
811
812 buffer.randomly_edit(&mut rng, 3);
813 log::info!("text:\n{}", buffer.text());
814
815 syntax_map.interpolate(&buffer);
816 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
817
818 syntax_map.reparse(language.clone(), &buffer);
819
820 reference_syntax_map.clear();
821 reference_syntax_map.reparse(language.clone(), &buffer);
822 }
823
824 for i in 0..operations {
825 let i = operations - i - 1;
826 buffer.undo();
827 log::info!("undoing operation {}", i);
828 log::info!("text:\n{}", buffer.text());
829
830 syntax_map.interpolate(&buffer);
831 syntax_map.reparse(language.clone(), &buffer);
832
833 reference_syntax_map.clear();
834 reference_syntax_map.reparse(language.clone(), &buffer);
835 assert_eq!(
836 syntax_map.layers(&buffer).len(),
837 reference_syntax_map.layers(&buffer).len(),
838 "wrong number of layers after undoing edit {i}"
839 );
840 }
841
842 let layers = syntax_map.layers(&buffer);
843 let reference_layers = reference_syntax_map.layers(&buffer);
844 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
845 assert_eq!(
846 edited_layer.node().to_sexp(),
847 reference_layer.node().to_sexp()
848 );
849 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
850 }
851}
852
853fn check_interpolation(
854 old_syntax_map: &SyntaxSnapshot,
855 new_syntax_map: &SyntaxSnapshot,
856 old_buffer: &BufferSnapshot,
857 new_buffer: &BufferSnapshot,
858) {
859 let edits = new_buffer
860 .edits_since::<usize>(&old_buffer.version())
861 .collect::<Vec<_>>();
862
863 for (old_layer, new_layer) in old_syntax_map
864 .layers
865 .iter()
866 .zip(new_syntax_map.layers.iter())
867 {
868 assert_eq!(old_layer.range, new_layer.range);
869 let Some(old_tree) = old_layer.content.tree() else { continue };
870 let Some(new_tree) = new_layer.content.tree() else { continue };
871 let old_start_byte = old_layer.range.start.to_offset(old_buffer);
872 let new_start_byte = new_layer.range.start.to_offset(new_buffer);
873 let old_start_point = old_layer.range.start.to_point(old_buffer).to_ts_point();
874 let new_start_point = new_layer.range.start.to_point(new_buffer).to_ts_point();
875 let old_node = old_tree.root_node_with_offset(old_start_byte, old_start_point);
876 let new_node = new_tree.root_node_with_offset(new_start_byte, new_start_point);
877 check_node_edits(
878 old_layer.depth,
879 &old_layer.range,
880 old_node,
881 new_node,
882 old_buffer,
883 new_buffer,
884 &edits,
885 );
886 }
887
888 fn check_node_edits(
889 depth: usize,
890 range: &Range<Anchor>,
891 old_node: Node,
892 new_node: Node,
893 old_buffer: &BufferSnapshot,
894 new_buffer: &BufferSnapshot,
895 edits: &[text::Edit<usize>],
896 ) {
897 assert_eq!(old_node.kind(), new_node.kind());
898
899 let old_range = old_node.byte_range();
900 let new_range = new_node.byte_range();
901
902 let is_edited = edits
903 .iter()
904 .any(|edit| edit.new.start < new_range.end && edit.new.end > new_range.start);
905 if is_edited {
906 assert!(
907 new_node.has_changes(),
908 concat!(
909 "failed to mark node as edited.\n",
910 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
911 "node kind: {}, old node range: {:?}, new node range: {:?}",
912 ),
913 depth,
914 range.to_offset(old_buffer),
915 range.to_offset(new_buffer),
916 new_node.kind(),
917 old_range,
918 new_range,
919 );
920 }
921
922 if !new_node.has_changes() {
923 assert_eq!(
924 old_buffer
925 .text_for_range(old_range.clone())
926 .collect::<String>(),
927 new_buffer
928 .text_for_range(new_range.clone())
929 .collect::<String>(),
930 concat!(
931 "mismatched text for node\n",
932 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
933 "node kind: {}, old node range:{:?}, new node range:{:?}",
934 ),
935 depth,
936 range.to_offset(old_buffer),
937 range.to_offset(new_buffer),
938 new_node.kind(),
939 old_range,
940 new_range,
941 );
942 }
943
944 for i in 0..new_node.child_count() {
945 check_node_edits(
946 depth,
947 range,
948 old_node.child(i).unwrap(),
949 new_node.child(i).unwrap(),
950 old_buffer,
951 new_buffer,
952 edits,
953 )
954 }
955 }
956}
957
958fn test_edit_sequence(language_name: &str, steps: &[&str]) -> (Buffer, SyntaxMap) {
959 let registry = Arc::new(LanguageRegistry::test());
960 registry.add(Arc::new(rust_lang()));
961 registry.add(Arc::new(ruby_lang()));
962 registry.add(Arc::new(html_lang()));
963 registry.add(Arc::new(erb_lang()));
964 registry.add(Arc::new(markdown_lang()));
965 let language = registry
966 .language_for_name(language_name)
967 .now_or_never()
968 .unwrap()
969 .unwrap();
970 let mut buffer = Buffer::new(0, 0, Default::default());
971
972 let mut mutated_syntax_map = SyntaxMap::new();
973 mutated_syntax_map.set_language_registry(registry.clone());
974 mutated_syntax_map.reparse(language.clone(), &buffer);
975
976 for (i, marked_string) in steps.into_iter().enumerate() {
977 buffer.edit_via_marked_text(&marked_string.unindent());
978
979 // Reparse the syntax map
980 mutated_syntax_map.interpolate(&buffer);
981 mutated_syntax_map.reparse(language.clone(), &buffer);
982
983 // Create a second syntax map from scratch
984 let mut reference_syntax_map = SyntaxMap::new();
985 reference_syntax_map.set_language_registry(registry.clone());
986 reference_syntax_map.reparse(language.clone(), &buffer);
987
988 // Compare the mutated syntax map to the new syntax map
989 let mutated_layers = mutated_syntax_map.layers(&buffer);
990 let reference_layers = reference_syntax_map.layers(&buffer);
991 assert_eq!(
992 mutated_layers.len(),
993 reference_layers.len(),
994 "wrong number of layers at step {i}"
995 );
996 for (edited_layer, reference_layer) in
997 mutated_layers.into_iter().zip(reference_layers.into_iter())
998 {
999 assert_eq!(
1000 edited_layer.node().to_sexp(),
1001 reference_layer.node().to_sexp(),
1002 "different layer at step {i}"
1003 );
1004 assert_eq!(
1005 edited_layer.node().range(),
1006 reference_layer.node().range(),
1007 "different layer at step {i}"
1008 );
1009 }
1010 }
1011
1012 (buffer, mutated_syntax_map)
1013}
1014
1015fn html_lang() -> Language {
1016 Language::new(
1017 LanguageConfig {
1018 name: "HTML".into(),
1019 path_suffixes: vec!["html".to_string()],
1020 ..Default::default()
1021 },
1022 Some(tree_sitter_html::language()),
1023 )
1024 .with_highlights_query(
1025 r#"
1026 (tag_name) @tag
1027 (erroneous_end_tag_name) @tag
1028 (attribute_name) @property
1029 "#,
1030 )
1031 .unwrap()
1032}
1033
1034fn ruby_lang() -> Language {
1035 Language::new(
1036 LanguageConfig {
1037 name: "Ruby".into(),
1038 path_suffixes: vec!["rb".to_string()],
1039 ..Default::default()
1040 },
1041 Some(tree_sitter_ruby::language()),
1042 )
1043 .with_highlights_query(
1044 r#"
1045 ["if" "do" "else" "end"] @keyword
1046 (instance_variable) @ivar
1047 "#,
1048 )
1049 .unwrap()
1050}
1051
1052fn erb_lang() -> Language {
1053 Language::new(
1054 LanguageConfig {
1055 name: "ERB".into(),
1056 path_suffixes: vec!["erb".to_string()],
1057 ..Default::default()
1058 },
1059 Some(tree_sitter_embedded_template::language()),
1060 )
1061 .with_highlights_query(
1062 r#"
1063 ["<%" "%>"] @keyword
1064 "#,
1065 )
1066 .unwrap()
1067 .with_injection_query(
1068 r#"
1069 (
1070 (code) @content
1071 (#set! "language" "ruby")
1072 (#set! "combined")
1073 )
1074
1075 (
1076 (content) @content
1077 (#set! "language" "html")
1078 (#set! "combined")
1079 )
1080 "#,
1081 )
1082 .unwrap()
1083}
1084
1085fn rust_lang() -> Language {
1086 Language::new(
1087 LanguageConfig {
1088 name: "Rust".into(),
1089 path_suffixes: vec!["rs".to_string()],
1090 ..Default::default()
1091 },
1092 Some(tree_sitter_rust::language()),
1093 )
1094 .with_highlights_query(
1095 r#"
1096 (field_identifier) @field
1097 (struct_expression) @struct
1098 "#,
1099 )
1100 .unwrap()
1101 .with_injection_query(
1102 r#"
1103 (macro_invocation
1104 (token_tree) @content
1105 (#set! "language" "rust"))
1106 "#,
1107 )
1108 .unwrap()
1109}
1110
1111fn markdown_lang() -> Language {
1112 Language::new(
1113 LanguageConfig {
1114 name: "Markdown".into(),
1115 path_suffixes: vec!["md".into()],
1116 ..Default::default()
1117 },
1118 Some(tree_sitter_markdown::language()),
1119 )
1120 .with_injection_query(
1121 r#"
1122 (fenced_code_block
1123 (info_string
1124 (language) @language)
1125 (code_fence_content) @content)
1126 "#,
1127 )
1128 .unwrap()
1129}
1130
1131fn range_for_text(buffer: &Buffer, text: &str) -> Range<usize> {
1132 let start = buffer.as_rope().to_string().find(text).unwrap();
1133 start..start + text.len()
1134}
1135
1136fn assert_layers_for_range(
1137 syntax_map: &SyntaxMap,
1138 buffer: &BufferSnapshot,
1139 range: Range<Point>,
1140 expected_layers: &[&str],
1141) {
1142 let layers = syntax_map
1143 .layers_for_range(range, &buffer)
1144 .collect::<Vec<_>>();
1145 assert_eq!(
1146 layers.len(),
1147 expected_layers.len(),
1148 "wrong number of layers"
1149 );
1150 for (i, (layer, expected_s_exp)) in layers.iter().zip(expected_layers.iter()).enumerate() {
1151 let actual_s_exp = layer.node().to_sexp();
1152 assert!(
1153 string_contains_sequence(
1154 &actual_s_exp,
1155 &expected_s_exp.split("...").collect::<Vec<_>>()
1156 ),
1157 "layer {i}:\n\nexpected: {expected_s_exp}\nactual: {actual_s_exp}",
1158 );
1159 }
1160}
1161
1162fn assert_capture_ranges(
1163 syntax_map: &SyntaxMap,
1164 buffer: &BufferSnapshot,
1165 highlight_query_capture_names: &[&str],
1166 marked_string: &str,
1167) {
1168 let mut actual_ranges = Vec::<Range<usize>>::new();
1169 let captures = syntax_map.captures(0..buffer.len(), buffer, |grammar| {
1170 grammar.highlights_query.as_ref()
1171 });
1172 let queries = captures
1173 .grammars()
1174 .iter()
1175 .map(|grammar| grammar.highlights_query.as_ref().unwrap())
1176 .collect::<Vec<_>>();
1177 for capture in captures {
1178 let name = &queries[capture.grammar_index].capture_names()[capture.index as usize];
1179 if highlight_query_capture_names.contains(&name.as_str()) {
1180 actual_ranges.push(capture.node.byte_range());
1181 }
1182 }
1183
1184 let (text, expected_ranges) = marked_text_ranges(&marked_string.unindent(), false);
1185 assert_eq!(text, buffer.text());
1186 assert_eq!(actual_ranges, expected_ranges);
1187}
1188
1189pub fn string_contains_sequence(text: &str, parts: &[&str]) -> bool {
1190 let mut last_part_end = 0;
1191 for part in parts {
1192 if let Some(start_ix) = text[last_part_end..].find(part) {
1193 last_part_end = start_ix + part.len();
1194 } else {
1195 return false;
1196 }
1197 }
1198 true
1199}