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