1use super::*;
2use crate::LanguageConfig;
3use rand::rngs::StdRng;
4use std::{env, ops::Range, sync::Arc};
5use text::Buffer;
6use tree_sitter::Node;
7use unindent::Unindent as _;
8use util::test::marked_text_ranges;
9
10#[test]
11fn test_splice_included_ranges() {
12 let ranges = vec![ts_range(20..30), ts_range(50..60), ts_range(80..90)];
13
14 let (new_ranges, 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 0,
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 0,
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() { dbg }",
262 "fn a() { dbg«!» }",
263 "fn a() { dbg!«()» }",
264 "fn a() { dbg!(«b») }",
265 "fn a() { dbg!(b«.») }",
266 "fn a() { dbg!(b.«c») }",
267 "fn a() { dbg!(b.c«()») }",
268 "fn a() { dbg!(b.c(«vec»)) }",
269 "fn a() { dbg!(b.c(vec«!»)) }",
270 "fn a() { dbg!(b.c(vec!«[]»)) }",
271 "fn a() { dbg!(b.c(vec![«d»])) }",
272 "fn a() { dbg!(b.c(vec![d«.»])) }",
273 "fn a() { dbg!(b.c(vec![d.«e»])) }",
274 ],
275 );
276
277 assert_capture_ranges(
278 &syntax_map,
279 &buffer,
280 &["field"],
281 "fn a() { dbg!(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(mut rng: StdRng) {
767 let operations = env::var("OPERATIONS")
768 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
769 .unwrap_or(10);
770
771 let text = r#"
772 fn test_something() {
773 let vec = vec![5, 1, 3, 8];
774 assert_eq!(
775 vec
776 .into_iter()
777 .map(|i| i * 2)
778 .collect::<Vec<usize>>(),
779 vec![
780 5 * 2, 1 * 2, 3 * 2, 8 * 2
781 ],
782 );
783 }
784 "#
785 .unindent()
786 .repeat(2);
787
788 let registry = Arc::new(LanguageRegistry::test());
789 let language = Arc::new(rust_lang());
790 registry.add(language.clone());
791 let mut buffer = Buffer::new(0, 0, text);
792
793 let mut syntax_map = SyntaxMap::new();
794 syntax_map.set_language_registry(registry.clone());
795 syntax_map.reparse(language.clone(), &buffer);
796
797 let mut reference_syntax_map = SyntaxMap::new();
798 reference_syntax_map.set_language_registry(registry.clone());
799
800 log::info!("initial text:\n{}", buffer.text());
801
802 for _ in 0..operations {
803 let prev_buffer = buffer.snapshot();
804 let prev_syntax_map = syntax_map.snapshot();
805
806 buffer.randomly_edit(&mut rng, 3);
807 log::info!("text:\n{}", buffer.text());
808
809 syntax_map.interpolate(&buffer);
810 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
811
812 syntax_map.reparse(language.clone(), &buffer);
813
814 reference_syntax_map.clear();
815 reference_syntax_map.reparse(language.clone(), &buffer);
816 }
817
818 for i in 0..operations {
819 let i = operations - i - 1;
820 buffer.undo();
821 log::info!("undoing operation {}", i);
822 log::info!("text:\n{}", buffer.text());
823
824 syntax_map.interpolate(&buffer);
825 syntax_map.reparse(language.clone(), &buffer);
826
827 reference_syntax_map.clear();
828 reference_syntax_map.reparse(language.clone(), &buffer);
829 assert_eq!(
830 syntax_map.layers(&buffer).len(),
831 reference_syntax_map.layers(&buffer).len(),
832 "wrong number of layers after undoing edit {i}"
833 );
834 }
835
836 let layers = syntax_map.layers(&buffer);
837 let reference_layers = reference_syntax_map.layers(&buffer);
838 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
839 assert_eq!(
840 edited_layer.node().to_sexp(),
841 reference_layer.node().to_sexp()
842 );
843 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
844 }
845}
846
847#[gpui::test(iterations = 50)]
848fn test_random_syntax_map_edits_with_combined_injections(mut rng: StdRng) {
849 let operations = env::var("OPERATIONS")
850 .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
851 .unwrap_or(10);
852
853 let text = r#"
854 <div id="main">
855 <% if one?(:two) %>
856 <p class="three" four>
857 <%= yield :five %>
858 </p>
859 <% elsif Six.seven(8) %>
860 <p id="three" four>
861 <%= yield :five %>
862 </p>
863 <% else %>
864 <span>Ok</span>
865 <% end %>
866 </div>
867 "#
868 .unindent()
869 .repeat(8);
870
871 let registry = Arc::new(LanguageRegistry::test());
872 let language = Arc::new(erb_lang());
873 registry.add(language.clone());
874 registry.add(Arc::new(ruby_lang()));
875 registry.add(Arc::new(html_lang()));
876 let mut buffer = Buffer::new(0, 0, text);
877
878 let mut syntax_map = SyntaxMap::new();
879 syntax_map.set_language_registry(registry.clone());
880 syntax_map.reparse(language.clone(), &buffer);
881
882 let mut reference_syntax_map = SyntaxMap::new();
883 reference_syntax_map.set_language_registry(registry.clone());
884
885 log::info!("initial text:\n{}", buffer.text());
886
887 for _ in 0..operations {
888 let prev_buffer = buffer.snapshot();
889 let prev_syntax_map = syntax_map.snapshot();
890
891 buffer.randomly_edit(&mut rng, 3);
892 log::info!("text:\n{}", buffer.text());
893
894 syntax_map.interpolate(&buffer);
895 check_interpolation(&prev_syntax_map, &syntax_map, &prev_buffer, &buffer);
896
897 syntax_map.reparse(language.clone(), &buffer);
898
899 reference_syntax_map.clear();
900 reference_syntax_map.reparse(language.clone(), &buffer);
901 }
902
903 for i in 0..operations {
904 let i = operations - i - 1;
905 buffer.undo();
906 log::info!("undoing operation {}", i);
907 log::info!("text:\n{}", buffer.text());
908
909 syntax_map.interpolate(&buffer);
910 syntax_map.reparse(language.clone(), &buffer);
911
912 reference_syntax_map.clear();
913 reference_syntax_map.reparse(language.clone(), &buffer);
914 assert_eq!(
915 syntax_map.layers(&buffer).len(),
916 reference_syntax_map.layers(&buffer).len(),
917 "wrong number of layers after undoing edit {i}"
918 );
919 }
920
921 let layers = syntax_map.layers(&buffer);
922 let reference_layers = reference_syntax_map.layers(&buffer);
923 for (edited_layer, reference_layer) in layers.into_iter().zip(reference_layers.into_iter()) {
924 assert_eq!(
925 edited_layer.node().to_sexp(),
926 reference_layer.node().to_sexp()
927 );
928 assert_eq!(edited_layer.node().range(), reference_layer.node().range());
929 }
930}
931
932fn check_interpolation(
933 old_syntax_map: &SyntaxSnapshot,
934 new_syntax_map: &SyntaxSnapshot,
935 old_buffer: &BufferSnapshot,
936 new_buffer: &BufferSnapshot,
937) {
938 let edits = new_buffer
939 .edits_since::<usize>(&old_buffer.version())
940 .collect::<Vec<_>>();
941
942 for (old_layer, new_layer) in old_syntax_map
943 .layers
944 .iter()
945 .zip(new_syntax_map.layers.iter())
946 {
947 assert_eq!(old_layer.range, new_layer.range);
948 let Some(old_tree) = old_layer.content.tree() else { continue };
949 let Some(new_tree) = new_layer.content.tree() else { continue };
950 let old_start_byte = old_layer.range.start.to_offset(old_buffer);
951 let new_start_byte = new_layer.range.start.to_offset(new_buffer);
952 let old_start_point = old_layer.range.start.to_point(old_buffer).to_ts_point();
953 let new_start_point = new_layer.range.start.to_point(new_buffer).to_ts_point();
954 let old_node = old_tree.root_node_with_offset(old_start_byte, old_start_point);
955 let new_node = new_tree.root_node_with_offset(new_start_byte, new_start_point);
956 check_node_edits(
957 old_layer.depth,
958 &old_layer.range,
959 old_node,
960 new_node,
961 old_buffer,
962 new_buffer,
963 &edits,
964 );
965 }
966
967 fn check_node_edits(
968 depth: usize,
969 range: &Range<Anchor>,
970 old_node: Node,
971 new_node: Node,
972 old_buffer: &BufferSnapshot,
973 new_buffer: &BufferSnapshot,
974 edits: &[text::Edit<usize>],
975 ) {
976 assert_eq!(old_node.kind(), new_node.kind());
977
978 let old_range = old_node.byte_range();
979 let new_range = new_node.byte_range();
980
981 let is_edited = edits
982 .iter()
983 .any(|edit| edit.new.start < new_range.end && edit.new.end > new_range.start);
984 if is_edited {
985 assert!(
986 new_node.has_changes(),
987 concat!(
988 "failed to mark node as edited.\n",
989 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
990 "node kind: {}, old node range: {:?}, new node range: {:?}",
991 ),
992 depth,
993 range.to_offset(old_buffer),
994 range.to_offset(new_buffer),
995 new_node.kind(),
996 old_range,
997 new_range,
998 );
999 }
1000
1001 if !new_node.has_changes() {
1002 assert_eq!(
1003 old_buffer
1004 .text_for_range(old_range.clone())
1005 .collect::<String>(),
1006 new_buffer
1007 .text_for_range(new_range.clone())
1008 .collect::<String>(),
1009 concat!(
1010 "mismatched text for node\n",
1011 "layer depth: {}, old layer range: {:?}, new layer range: {:?},\n",
1012 "node kind: {}, old node range:{:?}, new node range:{:?}",
1013 ),
1014 depth,
1015 range.to_offset(old_buffer),
1016 range.to_offset(new_buffer),
1017 new_node.kind(),
1018 old_range,
1019 new_range,
1020 );
1021 }
1022
1023 for i in 0..new_node.child_count() {
1024 check_node_edits(
1025 depth,
1026 range,
1027 old_node.child(i).unwrap(),
1028 new_node.child(i).unwrap(),
1029 old_buffer,
1030 new_buffer,
1031 edits,
1032 )
1033 }
1034 }
1035}
1036
1037fn test_edit_sequence(language_name: &str, steps: &[&str]) -> (Buffer, SyntaxMap) {
1038 let registry = Arc::new(LanguageRegistry::test());
1039 registry.add(Arc::new(elixir_lang()));
1040 registry.add(Arc::new(heex_lang()));
1041 registry.add(Arc::new(rust_lang()));
1042 registry.add(Arc::new(ruby_lang()));
1043 registry.add(Arc::new(html_lang()));
1044 registry.add(Arc::new(erb_lang()));
1045 registry.add(Arc::new(markdown_lang()));
1046
1047 let language = registry
1048 .language_for_name(language_name)
1049 .now_or_never()
1050 .unwrap()
1051 .unwrap();
1052 let mut buffer = Buffer::new(0, 0, Default::default());
1053
1054 let mut mutated_syntax_map = SyntaxMap::new();
1055 mutated_syntax_map.set_language_registry(registry.clone());
1056 mutated_syntax_map.reparse(language.clone(), &buffer);
1057
1058 for (i, marked_string) in steps.into_iter().enumerate() {
1059 let marked_string = marked_string.unindent();
1060 log::info!("incremental parse {i}: {marked_string:?}");
1061 buffer.edit_via_marked_text(&marked_string);
1062
1063 // Reparse the syntax map
1064 mutated_syntax_map.interpolate(&buffer);
1065 mutated_syntax_map.reparse(language.clone(), &buffer);
1066
1067 // Create a second syntax map from scratch
1068 log::info!("fresh parse {i}: {marked_string:?}");
1069 let mut reference_syntax_map = SyntaxMap::new();
1070 reference_syntax_map.set_language_registry(registry.clone());
1071 reference_syntax_map.reparse(language.clone(), &buffer);
1072
1073 // Compare the mutated syntax map to the new syntax map
1074 let mutated_layers = mutated_syntax_map.layers(&buffer);
1075 let reference_layers = reference_syntax_map.layers(&buffer);
1076 assert_eq!(
1077 mutated_layers.len(),
1078 reference_layers.len(),
1079 "wrong number of layers at step {i}"
1080 );
1081 for (edited_layer, reference_layer) in
1082 mutated_layers.into_iter().zip(reference_layers.into_iter())
1083 {
1084 assert_eq!(
1085 edited_layer.node().to_sexp(),
1086 reference_layer.node().to_sexp(),
1087 "different layer at step {i}"
1088 );
1089 assert_eq!(
1090 edited_layer.node().range(),
1091 reference_layer.node().range(),
1092 "different layer at step {i}"
1093 );
1094 }
1095 }
1096
1097 (buffer, mutated_syntax_map)
1098}
1099
1100fn html_lang() -> Language {
1101 Language::new(
1102 LanguageConfig {
1103 name: "HTML".into(),
1104 path_suffixes: vec!["html".to_string()],
1105 ..Default::default()
1106 },
1107 Some(tree_sitter_html::language()),
1108 )
1109 .with_highlights_query(
1110 r#"
1111 (tag_name) @tag
1112 (erroneous_end_tag_name) @tag
1113 (attribute_name) @property
1114 "#,
1115 )
1116 .unwrap()
1117}
1118
1119fn ruby_lang() -> Language {
1120 Language::new(
1121 LanguageConfig {
1122 name: "Ruby".into(),
1123 path_suffixes: vec!["rb".to_string()],
1124 ..Default::default()
1125 },
1126 Some(tree_sitter_ruby::language()),
1127 )
1128 .with_highlights_query(
1129 r#"
1130 ["if" "do" "else" "end"] @keyword
1131 (instance_variable) @ivar
1132 (call method: (identifier) @method)
1133 "#,
1134 )
1135 .unwrap()
1136}
1137
1138fn erb_lang() -> Language {
1139 Language::new(
1140 LanguageConfig {
1141 name: "ERB".into(),
1142 path_suffixes: vec!["erb".to_string()],
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 path_suffixes: vec!["rs".to_string()],
1176 ..Default::default()
1177 },
1178 Some(tree_sitter_rust::language()),
1179 )
1180 .with_highlights_query(
1181 r#"
1182 (field_identifier) @field
1183 (struct_expression) @struct
1184 "#,
1185 )
1186 .unwrap()
1187 .with_injection_query(
1188 r#"
1189 (macro_invocation
1190 (token_tree) @content
1191 (#set! "language" "rust"))
1192 "#,
1193 )
1194 .unwrap()
1195}
1196
1197fn markdown_lang() -> Language {
1198 Language::new(
1199 LanguageConfig {
1200 name: "Markdown".into(),
1201 path_suffixes: vec!["md".into()],
1202 ..Default::default()
1203 },
1204 Some(tree_sitter_markdown::language()),
1205 )
1206 .with_injection_query(
1207 r#"
1208 (fenced_code_block
1209 (info_string
1210 (language) @language)
1211 (code_fence_content) @content)
1212 "#,
1213 )
1214 .unwrap()
1215}
1216
1217fn elixir_lang() -> Language {
1218 Language::new(
1219 LanguageConfig {
1220 name: "Elixir".into(),
1221 path_suffixes: vec!["ex".into()],
1222 ..Default::default()
1223 },
1224 Some(tree_sitter_elixir::language()),
1225 )
1226 .with_highlights_query(
1227 r#"
1228
1229 "#,
1230 )
1231 .unwrap()
1232}
1233
1234fn heex_lang() -> Language {
1235 Language::new(
1236 LanguageConfig {
1237 name: "HEEx".into(),
1238 path_suffixes: vec!["heex".into()],
1239 ..Default::default()
1240 },
1241 Some(tree_sitter_heex::language()),
1242 )
1243 .with_injection_query(
1244 r#"
1245 (
1246 (directive
1247 [
1248 (partial_expression_value)
1249 (expression_value)
1250 (ending_expression_value)
1251 ] @content)
1252 (#set! language "elixir")
1253 (#set! combined)
1254 )
1255
1256 ((expression (expression_value) @content)
1257 (#set! language "elixir"))
1258 "#,
1259 )
1260 .unwrap()
1261}
1262
1263fn range_for_text(buffer: &Buffer, text: &str) -> Range<usize> {
1264 let start = buffer.as_rope().to_string().find(text).unwrap();
1265 start..start + text.len()
1266}
1267
1268#[track_caller]
1269fn assert_layers_for_range(
1270 syntax_map: &SyntaxMap,
1271 buffer: &BufferSnapshot,
1272 range: Range<Point>,
1273 expected_layers: &[&str],
1274) {
1275 let layers = syntax_map
1276 .layers_for_range(range, &buffer)
1277 .collect::<Vec<_>>();
1278 assert_eq!(
1279 layers.len(),
1280 expected_layers.len(),
1281 "wrong number of layers"
1282 );
1283 for (i, (layer, expected_s_exp)) in layers.iter().zip(expected_layers.iter()).enumerate() {
1284 let actual_s_exp = layer.node().to_sexp();
1285 assert!(
1286 string_contains_sequence(
1287 &actual_s_exp,
1288 &expected_s_exp.split("...").collect::<Vec<_>>()
1289 ),
1290 "layer {i}:\n\nexpected: {expected_s_exp}\nactual: {actual_s_exp}",
1291 );
1292 }
1293}
1294
1295fn assert_capture_ranges(
1296 syntax_map: &SyntaxMap,
1297 buffer: &BufferSnapshot,
1298 highlight_query_capture_names: &[&str],
1299 marked_string: &str,
1300) {
1301 let mut actual_ranges = Vec::<Range<usize>>::new();
1302 let captures = syntax_map.captures(0..buffer.len(), buffer, |grammar| {
1303 grammar.highlights_query.as_ref()
1304 });
1305 let queries = captures
1306 .grammars()
1307 .iter()
1308 .map(|grammar| grammar.highlights_query.as_ref().unwrap())
1309 .collect::<Vec<_>>();
1310 for capture in captures {
1311 let name = &queries[capture.grammar_index].capture_names()[capture.index as usize];
1312 if highlight_query_capture_names.contains(&name.as_str()) {
1313 actual_ranges.push(capture.node.byte_range());
1314 }
1315 }
1316
1317 let (text, expected_ranges) = marked_text_ranges(&marked_string.unindent(), false);
1318 assert_eq!(text, buffer.text());
1319 assert_eq!(actual_ranges, expected_ranges);
1320}
1321
1322pub fn string_contains_sequence(text: &str, parts: &[&str]) -> bool {
1323 let mut last_part_end = 0;
1324 for part in parts {
1325 if let Some(start_ix) = text[last_part_end..].find(part) {
1326 last_part_end = start_ix + part.len();
1327 } else {
1328 return false;
1329 }
1330 }
1331 true
1332}