syntax_map_tests.rs

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