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