1use super::*;
2use crate::{LanguageConfig, LanguageMatcher};
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 matcher: LanguageMatcher {
1096 path_suffixes: vec!["html".to_string()],
1097 ..Default::default()
1098 },
1099 ..Default::default()
1100 },
1101 Some(tree_sitter_html::language()),
1102 )
1103 .with_highlights_query(
1104 r#"
1105 (tag_name) @tag
1106 (erroneous_end_tag_name) @tag
1107 (attribute_name) @property
1108 "#,
1109 )
1110 .unwrap()
1111}
1112
1113fn ruby_lang() -> Language {
1114 Language::new(
1115 LanguageConfig {
1116 name: "Ruby".into(),
1117 matcher: LanguageMatcher {
1118 path_suffixes: vec!["rb".to_string()],
1119 ..Default::default()
1120 },
1121 ..Default::default()
1122 },
1123 Some(tree_sitter_ruby::language()),
1124 )
1125 .with_highlights_query(
1126 r#"
1127 ["if" "do" "else" "end"] @keyword
1128 (instance_variable) @ivar
1129 (call method: (identifier) @method)
1130 "#,
1131 )
1132 .unwrap()
1133}
1134
1135fn erb_lang() -> Language {
1136 Language::new(
1137 LanguageConfig {
1138 name: "ERB".into(),
1139 matcher: LanguageMatcher {
1140 path_suffixes: vec!["erb".to_string()],
1141 ..Default::default()
1142 },
1143 ..Default::default()
1144 },
1145 Some(tree_sitter_embedded_template::language()),
1146 )
1147 .with_highlights_query(
1148 r#"
1149 ["<%" "%>"] @keyword
1150 "#,
1151 )
1152 .unwrap()
1153 .with_injection_query(
1154 r#"
1155 (
1156 (code) @content
1157 (#set! "language" "ruby")
1158 (#set! "combined")
1159 )
1160
1161 (
1162 (content) @content
1163 (#set! "language" "html")
1164 (#set! "combined")
1165 )
1166 "#,
1167 )
1168 .unwrap()
1169}
1170
1171fn rust_lang() -> Language {
1172 Language::new(
1173 LanguageConfig {
1174 name: "Rust".into(),
1175 matcher: LanguageMatcher {
1176 path_suffixes: vec!["rs".to_string()],
1177 ..Default::default()
1178 },
1179 ..Default::default()
1180 },
1181 Some(tree_sitter_rust::language()),
1182 )
1183 .with_highlights_query(
1184 r#"
1185 (field_identifier) @field
1186 (struct_expression) @struct
1187 "#,
1188 )
1189 .unwrap()
1190 .with_injection_query(
1191 r#"
1192 (macro_invocation
1193 (token_tree) @content
1194 (#set! "language" "rust"))
1195 "#,
1196 )
1197 .unwrap()
1198}
1199
1200fn markdown_lang() -> Language {
1201 Language::new(
1202 LanguageConfig {
1203 name: "Markdown".into(),
1204 matcher: LanguageMatcher {
1205 path_suffixes: vec!["md".into()],
1206 ..Default::default()
1207 },
1208 ..Default::default()
1209 },
1210 Some(tree_sitter_markdown::language()),
1211 )
1212 .with_injection_query(
1213 r#"
1214 (fenced_code_block
1215 (info_string
1216 (language) @language)
1217 (code_fence_content) @content)
1218 "#,
1219 )
1220 .unwrap()
1221}
1222
1223fn elixir_lang() -> Language {
1224 Language::new(
1225 LanguageConfig {
1226 name: "Elixir".into(),
1227 matcher: LanguageMatcher {
1228 path_suffixes: vec!["ex".into()],
1229 ..Default::default()
1230 },
1231 ..Default::default()
1232 },
1233 Some(tree_sitter_elixir::language()),
1234 )
1235 .with_highlights_query(
1236 r#"
1237
1238 "#,
1239 )
1240 .unwrap()
1241}
1242
1243fn heex_lang() -> Language {
1244 Language::new(
1245 LanguageConfig {
1246 name: "HEEx".into(),
1247 matcher: LanguageMatcher {
1248 path_suffixes: vec!["heex".into()],
1249 ..Default::default()
1250 },
1251 ..Default::default()
1252 },
1253 Some(tree_sitter_heex::language()),
1254 )
1255 .with_injection_query(
1256 r#"
1257 (
1258 (directive
1259 [
1260 (partial_expression_value)
1261 (expression_value)
1262 (ending_expression_value)
1263 ] @content)
1264 (#set! language "elixir")
1265 (#set! combined)
1266 )
1267
1268 ((expression (expression_value) @content)
1269 (#set! language "elixir"))
1270 "#,
1271 )
1272 .unwrap()
1273}
1274
1275fn range_for_text(buffer: &Buffer, text: &str) -> Range<usize> {
1276 let start = buffer.as_rope().to_string().find(text).unwrap();
1277 start..start + text.len()
1278}
1279
1280#[track_caller]
1281fn assert_layers_for_range(
1282 syntax_map: &SyntaxMap,
1283 buffer: &BufferSnapshot,
1284 range: Range<Point>,
1285 expected_layers: &[&str],
1286) {
1287 let layers = syntax_map
1288 .layers_for_range(range, &buffer)
1289 .collect::<Vec<_>>();
1290 assert_eq!(
1291 layers.len(),
1292 expected_layers.len(),
1293 "wrong number of layers"
1294 );
1295 for (i, (layer, expected_s_exp)) in layers.iter().zip(expected_layers.iter()).enumerate() {
1296 let actual_s_exp = layer.node().to_sexp();
1297 assert!(
1298 string_contains_sequence(
1299 &actual_s_exp,
1300 &expected_s_exp.split("...").collect::<Vec<_>>()
1301 ),
1302 "layer {i}:\n\nexpected: {expected_s_exp}\nactual: {actual_s_exp}",
1303 );
1304 }
1305}
1306
1307fn assert_capture_ranges(
1308 syntax_map: &SyntaxMap,
1309 buffer: &BufferSnapshot,
1310 highlight_query_capture_names: &[&str],
1311 marked_string: &str,
1312) {
1313 let mut actual_ranges = Vec::<Range<usize>>::new();
1314 let captures = syntax_map.captures(0..buffer.len(), buffer, |grammar| {
1315 grammar.highlights_query.as_ref()
1316 });
1317 let queries = captures
1318 .grammars()
1319 .iter()
1320 .map(|grammar| grammar.highlights_query.as_ref().unwrap())
1321 .collect::<Vec<_>>();
1322 for capture in captures {
1323 let name = &queries[capture.grammar_index].capture_names()[capture.index as usize];
1324 if highlight_query_capture_names.contains(&name) {
1325 actual_ranges.push(capture.node.byte_range());
1326 }
1327 }
1328
1329 let (text, expected_ranges) = marked_text_ranges(&marked_string.unindent(), false);
1330 assert_eq!(text, buffer.text());
1331 assert_eq!(actual_ranges, expected_ranges);
1332}
1333
1334pub fn string_contains_sequence(text: &str, parts: &[&str]) -> bool {
1335 let mut last_part_end = 0;
1336 for part in parts {
1337 if let Some(start_ix) = text[last_part_end..].find(part) {
1338 last_part_end = start_ix + part.len();
1339 } else {
1340 return false;
1341 }
1342 }
1343 true
1344}