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