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