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