syntax_map_tests.rs

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