syntax_map_tests.rs

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