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