buffer_tests.rs

   1use super::*;
   2use crate::language_settings::{
   3    AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent,
   4};
   5use crate::Buffer;
   6use clock::ReplicaId;
   7use collections::BTreeMap;
   8use futures::FutureExt as _;
   9use gpui::{AppContext, Model};
  10use gpui::{Context, TestAppContext};
  11use indoc::indoc;
  12use proto::deserialize_operation;
  13use rand::prelude::*;
  14use regex::RegexBuilder;
  15use settings::SettingsStore;
  16use std::{
  17    env,
  18    ops::Range,
  19    time::{Duration, Instant},
  20};
  21use text::network::Network;
  22use text::{BufferId, LineEnding};
  23use text::{Point, ToPoint};
  24use unindent::Unindent as _;
  25use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  26
  27lazy_static! {
  28    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  29        .multi_line(true)
  30        .build()
  31        .unwrap();
  32}
  33
  34#[cfg(test)]
  35#[ctor::ctor]
  36fn init_logger() {
  37    if std::env::var("RUST_LOG").is_ok() {
  38        env_logger::init();
  39    }
  40}
  41
  42#[gpui::test]
  43fn test_line_endings(cx: &mut gpui::AppContext) {
  44    init_settings(cx, |_| {});
  45
  46    cx.new_model(|cx| {
  47        let mut buffer = Buffer::new(
  48            0,
  49            BufferId::new(cx.entity_id().as_u64()).unwrap(),
  50            "one\r\ntwo\rthree",
  51        )
  52        .with_language(Arc::new(rust_lang()), cx);
  53        assert_eq!(buffer.text(), "one\ntwo\nthree");
  54        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  55
  56        buffer.check_invariants();
  57        buffer.edit(
  58            [(buffer.len()..buffer.len(), "\r\nfour")],
  59            Some(AutoindentMode::EachLine),
  60            cx,
  61        );
  62        buffer.edit([(0..0, "zero\r\n")], None, cx);
  63        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  64        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  65        buffer.check_invariants();
  66
  67        buffer
  68    });
  69}
  70
  71#[gpui::test]
  72fn test_select_language() {
  73    let registry = Arc::new(LanguageRegistry::test());
  74    registry.add(Arc::new(Language::new(
  75        LanguageConfig {
  76            name: "Rust".into(),
  77            matcher: LanguageMatcher {
  78                path_suffixes: vec!["rs".to_string()],
  79                ..Default::default()
  80            },
  81            ..Default::default()
  82        },
  83        Some(tree_sitter_rust::language()),
  84    )));
  85    registry.add(Arc::new(Language::new(
  86        LanguageConfig {
  87            name: "Make".into(),
  88            matcher: LanguageMatcher {
  89                path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  90                ..Default::default()
  91            },
  92            ..Default::default()
  93        },
  94        Some(tree_sitter_rust::language()),
  95    )));
  96
  97    // matching file extension
  98    assert_eq!(
  99        registry
 100            .language_for_file("zed/lib.rs", None)
 101            .now_or_never()
 102            .and_then(|l| Some(l.ok()?.name())),
 103        Some("Rust".into())
 104    );
 105    assert_eq!(
 106        registry
 107            .language_for_file("zed/lib.mk", None)
 108            .now_or_never()
 109            .and_then(|l| Some(l.ok()?.name())),
 110        Some("Make".into())
 111    );
 112
 113    // matching filename
 114    assert_eq!(
 115        registry
 116            .language_for_file("zed/Makefile", None)
 117            .now_or_never()
 118            .and_then(|l| Some(l.ok()?.name())),
 119        Some("Make".into())
 120    );
 121
 122    // matching suffix that is not the full file extension or filename
 123    assert_eq!(
 124        registry
 125            .language_for_file("zed/cars", None)
 126            .now_or_never()
 127            .and_then(|l| Some(l.ok()?.name())),
 128        None
 129    );
 130    assert_eq!(
 131        registry
 132            .language_for_file("zed/a.cars", None)
 133            .now_or_never()
 134            .and_then(|l| Some(l.ok()?.name())),
 135        None
 136    );
 137    assert_eq!(
 138        registry
 139            .language_for_file("zed/sumk", None)
 140            .now_or_never()
 141            .and_then(|l| Some(l.ok()?.name())),
 142        None
 143    );
 144}
 145
 146#[gpui::test]
 147fn test_edit_events(cx: &mut gpui::AppContext) {
 148    let mut now = Instant::now();
 149    let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
 150    let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
 151
 152    let buffer1 = cx
 153        .new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
 154    let buffer2 = cx
 155        .new_model(|cx| Buffer::new(1, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
 156    let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
 157    buffer1.update(cx, {
 158        let buffer1_ops = buffer1_ops.clone();
 159        |buffer, cx| {
 160            let buffer_1_events = buffer_1_events.clone();
 161            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 162                Event::Operation(op) => buffer1_ops.lock().push(op),
 163                event => buffer_1_events.lock().push(event),
 164            })
 165            .detach();
 166            let buffer_2_events = buffer_2_events.clone();
 167            cx.subscribe(&buffer2, move |_, _, event, _| {
 168                buffer_2_events.lock().push(event.clone())
 169            })
 170            .detach();
 171
 172            // An edit emits an edited event, followed by a dirty changed event,
 173            // since the buffer was previously in a clean state.
 174            buffer.edit([(2..4, "XYZ")], None, cx);
 175
 176            // An empty transaction does not emit any events.
 177            buffer.start_transaction();
 178            buffer.end_transaction(cx);
 179
 180            // A transaction containing two edits emits one edited event.
 181            now += Duration::from_secs(1);
 182            buffer.start_transaction_at(now);
 183            buffer.edit([(5..5, "u")], None, cx);
 184            buffer.edit([(6..6, "w")], None, cx);
 185            buffer.end_transaction_at(now, cx);
 186
 187            // Undoing a transaction emits one edited event.
 188            buffer.undo(cx);
 189        }
 190    });
 191
 192    // Incorporating a set of remote ops emits a single edited event,
 193    // followed by a dirty changed event.
 194    buffer2.update(cx, |buffer, cx| {
 195        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 196    });
 197    assert_eq!(
 198        mem::take(&mut *buffer_1_events.lock()),
 199        vec![
 200            Event::Edited,
 201            Event::DirtyChanged,
 202            Event::Edited,
 203            Event::Edited,
 204        ]
 205    );
 206    assert_eq!(
 207        mem::take(&mut *buffer_2_events.lock()),
 208        vec![Event::Edited, Event::DirtyChanged]
 209    );
 210
 211    buffer1.update(cx, |buffer, cx| {
 212        // Undoing the first transaction emits edited event, followed by a
 213        // dirty changed event, since the buffer is again in a clean state.
 214        buffer.undo(cx);
 215    });
 216    // Incorporating the remote ops again emits a single edited event,
 217    // followed by a dirty changed event.
 218    buffer2.update(cx, |buffer, cx| {
 219        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 220    });
 221    assert_eq!(
 222        mem::take(&mut *buffer_1_events.lock()),
 223        vec![Event::Edited, Event::DirtyChanged,]
 224    );
 225    assert_eq!(
 226        mem::take(&mut *buffer_2_events.lock()),
 227        vec![Event::Edited, Event::DirtyChanged]
 228    );
 229}
 230
 231#[gpui::test]
 232async fn test_apply_diff(cx: &mut TestAppContext) {
 233    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 234    let buffer =
 235        cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
 236    let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 237
 238    let text = "a\nccc\ndddd\nffffff\n";
 239    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 240    buffer.update(cx, |buffer, cx| {
 241        buffer.apply_diff(diff, cx).unwrap();
 242        assert_eq!(buffer.text(), text);
 243        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 244    });
 245
 246    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 247    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 248    buffer.update(cx, |buffer, cx| {
 249        buffer.apply_diff(diff, cx).unwrap();
 250        assert_eq!(buffer.text(), text);
 251        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 252    });
 253}
 254
 255#[gpui::test(iterations = 10)]
 256async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 257    let text = [
 258        "zero",     //
 259        "one  ",    // 2 trailing spaces
 260        "two",      //
 261        "three   ", // 3 trailing spaces
 262        "four",     //
 263        "five    ", // 4 trailing spaces
 264    ]
 265    .join("\n");
 266
 267    let buffer =
 268        cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
 269
 270    // Spawn a task to format the buffer's whitespace.
 271    // Pause so that the foratting task starts running.
 272    let format = buffer.update(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 273    smol::future::yield_now().await;
 274
 275    // Edit the buffer while the normalization task is running.
 276    let version_before_edit = buffer.update(cx, |buffer, _| buffer.version());
 277    buffer.update(cx, |buffer, cx| {
 278        buffer.edit(
 279            [
 280                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 281                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 282            ],
 283            None,
 284            cx,
 285        );
 286    });
 287
 288    let format_diff = format.await;
 289    buffer.update(cx, |buffer, cx| {
 290        let version_before_format = format_diff.base_version.clone();
 291        buffer.apply_diff(format_diff, cx);
 292
 293        // The outcome depends on the order of concurrent tasks.
 294        //
 295        // If the edit occurred while searching for trailing whitespace ranges,
 296        // then the trailing whitespace region touched by the edit is left intact.
 297        if version_before_format == version_before_edit {
 298            assert_eq!(
 299                buffer.text(),
 300                [
 301                    "zEEero",      //
 302                    "one",         //
 303                    "two",         //
 304                    "threeEEE   ", //
 305                    "four",        //
 306                    "five",        //
 307                ]
 308                .join("\n")
 309            );
 310        }
 311        // Otherwise, all trailing whitespace is removed.
 312        else {
 313            assert_eq!(
 314                buffer.text(),
 315                [
 316                    "zEEero",   //
 317                    "one",      //
 318                    "two",      //
 319                    "threeEEE", //
 320                    "four",     //
 321                    "five",     //
 322                ]
 323                .join("\n")
 324            );
 325        }
 326    });
 327}
 328
 329#[gpui::test]
 330async fn test_reparse(cx: &mut gpui::TestAppContext) {
 331    let text = "fn a() {}";
 332    let buffer = cx.new_model(|cx| {
 333        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 334            .with_language(Arc::new(rust_lang()), cx)
 335    });
 336
 337    // Wait for the initial text to parse
 338    cx.executor().run_until_parked();
 339    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 340    assert_eq!(
 341        get_tree_sexp(&buffer, cx),
 342        concat!(
 343            "(source_file (function_item name: (identifier) ",
 344            "parameters: (parameters) ",
 345            "body: (block)))"
 346        )
 347    );
 348
 349    buffer.update(cx, |buffer, _| {
 350        buffer.set_sync_parse_timeout(Duration::ZERO)
 351    });
 352
 353    // Perform some edits (add parameter and variable reference)
 354    // Parsing doesn't begin until the transaction is complete
 355    buffer.update(cx, |buf, cx| {
 356        buf.start_transaction();
 357
 358        let offset = buf.text().find(')').unwrap();
 359        buf.edit([(offset..offset, "b: C")], None, cx);
 360        assert!(!buf.is_parsing());
 361
 362        let offset = buf.text().find('}').unwrap();
 363        buf.edit([(offset..offset, " d; ")], None, cx);
 364        assert!(!buf.is_parsing());
 365
 366        buf.end_transaction(cx);
 367        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 368        assert!(buf.is_parsing());
 369    });
 370    cx.executor().run_until_parked();
 371    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 372    assert_eq!(
 373        get_tree_sexp(&buffer, cx),
 374        concat!(
 375            "(source_file (function_item name: (identifier) ",
 376            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 377            "body: (block (expression_statement (identifier)))))"
 378        )
 379    );
 380
 381    // Perform a series of edits without waiting for the current parse to complete:
 382    // * turn identifier into a field expression
 383    // * turn field expression into a method call
 384    // * add a turbofish to the method call
 385    buffer.update(cx, |buf, cx| {
 386        let offset = buf.text().find(';').unwrap();
 387        buf.edit([(offset..offset, ".e")], None, cx);
 388        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 389        assert!(buf.is_parsing());
 390    });
 391    buffer.update(cx, |buf, cx| {
 392        let offset = buf.text().find(';').unwrap();
 393        buf.edit([(offset..offset, "(f)")], None, cx);
 394        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 395        assert!(buf.is_parsing());
 396    });
 397    buffer.update(cx, |buf, cx| {
 398        let offset = buf.text().find("(f)").unwrap();
 399        buf.edit([(offset..offset, "::<G>")], None, cx);
 400        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 401        assert!(buf.is_parsing());
 402    });
 403    cx.executor().run_until_parked();
 404    assert_eq!(
 405        get_tree_sexp(&buffer, cx),
 406        concat!(
 407            "(source_file (function_item name: (identifier) ",
 408            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 409            "body: (block (expression_statement (call_expression ",
 410            "function: (generic_function ",
 411            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 412            "type_arguments: (type_arguments (type_identifier))) ",
 413            "arguments: (arguments (identifier)))))))",
 414        )
 415    );
 416
 417    buffer.update(cx, |buf, cx| {
 418        buf.undo(cx);
 419        buf.undo(cx);
 420        buf.undo(cx);
 421        buf.undo(cx);
 422        assert_eq!(buf.text(), "fn a() {}");
 423        assert!(buf.is_parsing());
 424    });
 425
 426    cx.executor().run_until_parked();
 427    assert_eq!(
 428        get_tree_sexp(&buffer, cx),
 429        concat!(
 430            "(source_file (function_item name: (identifier) ",
 431            "parameters: (parameters) ",
 432            "body: (block)))"
 433        )
 434    );
 435
 436    buffer.update(cx, |buf, cx| {
 437        buf.redo(cx);
 438        buf.redo(cx);
 439        buf.redo(cx);
 440        buf.redo(cx);
 441        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 442        assert!(buf.is_parsing());
 443    });
 444    cx.executor().run_until_parked();
 445    assert_eq!(
 446        get_tree_sexp(&buffer, cx),
 447        concat!(
 448            "(source_file (function_item name: (identifier) ",
 449            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 450            "body: (block (expression_statement (call_expression ",
 451            "function: (generic_function ",
 452            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 453            "type_arguments: (type_arguments (type_identifier))) ",
 454            "arguments: (arguments (identifier)))))))",
 455        )
 456    );
 457}
 458
 459#[gpui::test]
 460async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 461    let buffer = cx.new_model(|cx| {
 462        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "{}")
 463            .with_language(Arc::new(rust_lang()), cx);
 464        buffer.set_sync_parse_timeout(Duration::ZERO);
 465        buffer
 466    });
 467
 468    // Wait for the initial text to parse
 469    cx.executor().run_until_parked();
 470    assert_eq!(
 471        get_tree_sexp(&buffer, cx),
 472        "(source_file (expression_statement (block)))"
 473    );
 474
 475    buffer.update(cx, |buffer, cx| {
 476        buffer.set_language(Some(Arc::new(json_lang())), cx)
 477    });
 478    cx.executor().run_until_parked();
 479    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 480}
 481
 482#[gpui::test]
 483async fn test_outline(cx: &mut gpui::TestAppContext) {
 484    let text = r#"
 485        struct Person {
 486            name: String,
 487            age: usize,
 488        }
 489
 490        mod module {
 491            enum LoginState {
 492                LoggedOut,
 493                LoggingOn,
 494                LoggedIn {
 495                    person: Person,
 496                    time: Instant,
 497                }
 498            }
 499        }
 500
 501        impl Eq for Person {}
 502
 503        impl Drop for Person {
 504            fn drop(&mut self) {
 505                println!("bye");
 506            }
 507        }
 508    "#
 509    .unindent();
 510
 511    let buffer = cx.new_model(|cx| {
 512        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 513            .with_language(Arc::new(rust_lang()), cx)
 514    });
 515    let outline = buffer
 516        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 517        .unwrap();
 518
 519    assert_eq!(
 520        outline
 521            .items
 522            .iter()
 523            .map(|item| (item.text.as_str(), item.depth))
 524            .collect::<Vec<_>>(),
 525        &[
 526            ("struct Person", 0),
 527            ("name", 1),
 528            ("age", 1),
 529            ("mod module", 0),
 530            ("enum LoginState", 1),
 531            ("LoggedOut", 2),
 532            ("LoggingOn", 2),
 533            ("LoggedIn", 2),
 534            ("person", 3),
 535            ("time", 3),
 536            ("impl Eq for Person", 0),
 537            ("impl Drop for Person", 0),
 538            ("fn drop", 1),
 539        ]
 540    );
 541
 542    // Without space, we only match on names
 543    assert_eq!(
 544        search(&outline, "oon", cx).await,
 545        &[
 546            ("mod module", vec![]),                    // included as the parent of a match
 547            ("enum LoginState", vec![]),               // included as the parent of a match
 548            ("LoggingOn", vec![1, 7, 8]),              // matches
 549            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 550        ]
 551    );
 552
 553    assert_eq!(
 554        search(&outline, "dp p", cx).await,
 555        &[
 556            ("impl Drop for Person", vec![5, 8, 9, 14]),
 557            ("fn drop", vec![]),
 558        ]
 559    );
 560    assert_eq!(
 561        search(&outline, "dpn", cx).await,
 562        &[("impl Drop for Person", vec![5, 14, 19])]
 563    );
 564    assert_eq!(
 565        search(&outline, "impl ", cx).await,
 566        &[
 567            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 568            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 569            ("fn drop", vec![]),
 570        ]
 571    );
 572
 573    async fn search<'a>(
 574        outline: &'a Outline<Anchor>,
 575        query: &'a str,
 576        cx: &'a gpui::TestAppContext,
 577    ) -> Vec<(&'a str, Vec<usize>)> {
 578        let matches = cx
 579            .update(|cx| outline.search(query, cx.background_executor().clone()))
 580            .await;
 581        matches
 582            .into_iter()
 583            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 584            .collect::<Vec<_>>()
 585    }
 586}
 587
 588#[gpui::test]
 589async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 590    let text = r#"
 591        impl A for B<
 592            C
 593        > {
 594        };
 595    "#
 596    .unindent();
 597
 598    let buffer = cx.new_model(|cx| {
 599        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 600            .with_language(Arc::new(rust_lang()), cx)
 601    });
 602    let outline = buffer
 603        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 604        .unwrap();
 605
 606    assert_eq!(
 607        outline
 608            .items
 609            .iter()
 610            .map(|item| (item.text.as_str(), item.depth))
 611            .collect::<Vec<_>>(),
 612        &[("impl A for B<", 0)]
 613    );
 614}
 615
 616#[gpui::test]
 617async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
 618    let language = javascript_lang()
 619        .with_outline_query(
 620            r#"
 621            (function_declaration
 622                "function" @context
 623                name: (_) @name
 624                parameters: (formal_parameters
 625                    "(" @context.extra
 626                    ")" @context.extra)) @item
 627            "#,
 628        )
 629        .unwrap();
 630
 631    let text = r#"
 632        function a() {}
 633        function b(c) {}
 634    "#
 635    .unindent();
 636
 637    let buffer = cx.new_model(|cx| {
 638        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 639            .with_language(Arc::new(language), cx)
 640    });
 641    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 642
 643    // extra context nodes are included in the outline.
 644    let outline = snapshot.outline(None).unwrap();
 645    assert_eq!(
 646        outline
 647            .items
 648            .iter()
 649            .map(|item| (item.text.as_str(), item.depth))
 650            .collect::<Vec<_>>(),
 651        &[("function a()", 0), ("function b( )", 0),]
 652    );
 653
 654    // extra context nodes do not appear in breadcrumbs.
 655    let symbols = snapshot.symbols_containing(3, None).unwrap();
 656    assert_eq!(
 657        symbols
 658            .iter()
 659            .map(|item| (item.text.as_str(), item.depth))
 660            .collect::<Vec<_>>(),
 661        &[("function a", 0)]
 662    );
 663}
 664
 665#[gpui::test]
 666async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 667    let text = r#"
 668        impl Person {
 669            fn one() {
 670                1
 671            }
 672
 673            fn two() {
 674                2
 675            }fn three() {
 676                3
 677            }
 678        }
 679    "#
 680    .unindent();
 681
 682    let buffer = cx.new_model(|cx| {
 683        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 684            .with_language(Arc::new(rust_lang()), cx)
 685    });
 686    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 687
 688    // point is at the start of an item
 689    assert_eq!(
 690        symbols_containing(Point::new(1, 4), &snapshot),
 691        vec![
 692            (
 693                "impl Person".to_string(),
 694                Point::new(0, 0)..Point::new(10, 1)
 695            ),
 696            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 697        ]
 698    );
 699
 700    // point is in the middle of an item
 701    assert_eq!(
 702        symbols_containing(Point::new(2, 8), &snapshot),
 703        vec![
 704            (
 705                "impl Person".to_string(),
 706                Point::new(0, 0)..Point::new(10, 1)
 707            ),
 708            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 709        ]
 710    );
 711
 712    // point is at the end of an item
 713    assert_eq!(
 714        symbols_containing(Point::new(3, 5), &snapshot),
 715        vec![
 716            (
 717                "impl Person".to_string(),
 718                Point::new(0, 0)..Point::new(10, 1)
 719            ),
 720            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 721        ]
 722    );
 723
 724    // point is in between two adjacent items
 725    assert_eq!(
 726        symbols_containing(Point::new(7, 5), &snapshot),
 727        vec![
 728            (
 729                "impl Person".to_string(),
 730                Point::new(0, 0)..Point::new(10, 1)
 731            ),
 732            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 733        ]
 734    );
 735
 736    fn symbols_containing(
 737        position: Point,
 738        snapshot: &BufferSnapshot,
 739    ) -> Vec<(String, Range<Point>)> {
 740        snapshot
 741            .symbols_containing(position, None)
 742            .unwrap()
 743            .into_iter()
 744            .map(|item| {
 745                (
 746                    item.text,
 747                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 748                )
 749            })
 750            .collect()
 751    }
 752}
 753
 754#[gpui::test]
 755fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 756    let mut assert = |selection_text, range_markers| {
 757        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 758    };
 759
 760    assert(
 761        indoc! {"
 762            mod x {
 763                moˇd y {
 764
 765                }
 766            }
 767            let foo = 1;"},
 768        vec![indoc! {"
 769            mod x «{»
 770                mod y {
 771
 772                }
 773            «}»
 774            let foo = 1;"}],
 775    );
 776
 777    assert(
 778        indoc! {"
 779            mod x {
 780                mod y ˇ{
 781
 782                }
 783            }
 784            let foo = 1;"},
 785        vec![
 786            indoc! {"
 787                mod x «{»
 788                    mod y {
 789
 790                    }
 791                «}»
 792                let foo = 1;"},
 793            indoc! {"
 794                mod x {
 795                    mod y «{»
 796
 797                    «}»
 798                }
 799                let foo = 1;"},
 800        ],
 801    );
 802
 803    assert(
 804        indoc! {"
 805            mod x {
 806                mod y {
 807
 808 809            }
 810            let foo = 1;"},
 811        vec![
 812            indoc! {"
 813                mod x «{»
 814                    mod y {
 815
 816                    }
 817                «}»
 818                let foo = 1;"},
 819            indoc! {"
 820                mod x {
 821                    mod y «{»
 822
 823                    «}»
 824                }
 825                let foo = 1;"},
 826        ],
 827    );
 828
 829    assert(
 830        indoc! {"
 831            mod x {
 832                mod y {
 833
 834                }
 835            ˇ}
 836            let foo = 1;"},
 837        vec![indoc! {"
 838            mod x «{»
 839                mod y {
 840
 841                }
 842            «}»
 843            let foo = 1;"}],
 844    );
 845
 846    assert(
 847        indoc! {"
 848            mod x {
 849                mod y {
 850
 851                }
 852            }
 853            let fˇoo = 1;"},
 854        vec![],
 855    );
 856
 857    // Regression test: avoid crash when querying at the end of the buffer.
 858    assert(
 859        indoc! {"
 860            mod x {
 861                mod y {
 862
 863                }
 864            }
 865            let foo = 1;ˇ"},
 866        vec![],
 867    );
 868}
 869
 870#[gpui::test]
 871fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 872    let mut assert = |selection_text, bracket_pair_texts| {
 873        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 874    };
 875
 876    assert(
 877        indoc! {"
 878        for (const a in b)ˇ {
 879            // a comment that's longer than the for-loop header
 880        }"},
 881        vec![indoc! {"
 882        for «(»const a in b«)» {
 883            // a comment that's longer than the for-loop header
 884        }"}],
 885    );
 886
 887    // Regression test: even though the parent node of the parentheses (the for loop) does
 888    // intersect the given range, the parentheses themselves do not contain the range, so
 889    // they should not be returned. Only the curly braces contain the range.
 890    assert(
 891        indoc! {"
 892        for (const a in b) {ˇ
 893            // a comment that's longer than the for-loop header
 894        }"},
 895        vec![indoc! {"
 896        for (const a in b) «{»
 897            // a comment that's longer than the for-loop header
 898        «}»"}],
 899    );
 900}
 901
 902#[gpui::test]
 903fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
 904    cx.new_model(|cx| {
 905        let text = "fn a() { b(|c| {}) }";
 906        let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 907            .with_language(Arc::new(rust_lang()), cx);
 908        let snapshot = buffer.snapshot();
 909
 910        assert_eq!(
 911            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 912            Some(range_of(text, "|"))
 913        );
 914        assert_eq!(
 915            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 916            Some(range_of(text, "|c|"))
 917        );
 918        assert_eq!(
 919            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 920            Some(range_of(text, "|c| {}"))
 921        );
 922        assert_eq!(
 923            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 924            Some(range_of(text, "(|c| {})"))
 925        );
 926
 927        buffer
 928    });
 929
 930    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 931        let start = text.find(part).unwrap();
 932        start..start
 933    }
 934
 935    fn range_of(text: &str, part: &str) -> Range<usize> {
 936        let start = text.find(part).unwrap();
 937        start..start + part.len()
 938    }
 939}
 940
 941#[gpui::test]
 942fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
 943    init_settings(cx, |_| {});
 944
 945    cx.new_model(|cx| {
 946        let text = "fn a() {}";
 947        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 948            .with_language(Arc::new(rust_lang()), cx);
 949
 950        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 951        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 952
 953        buffer.edit(
 954            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 955            Some(AutoindentMode::EachLine),
 956            cx,
 957        );
 958        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 959
 960        // Create a field expression on a new line, causing that line
 961        // to be indented.
 962        buffer.edit(
 963            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 964            Some(AutoindentMode::EachLine),
 965            cx,
 966        );
 967        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 968
 969        // Remove the dot so that the line is no longer a field expression,
 970        // causing the line to be outdented.
 971        buffer.edit(
 972            [(Point::new(2, 8)..Point::new(2, 9), "")],
 973            Some(AutoindentMode::EachLine),
 974            cx,
 975        );
 976        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 977
 978        buffer
 979    });
 980}
 981
 982#[gpui::test]
 983fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
 984    init_settings(cx, |settings| {
 985        settings.defaults.hard_tabs = Some(true);
 986    });
 987
 988    cx.new_model(|cx| {
 989        let text = "fn a() {}";
 990        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 991            .with_language(Arc::new(rust_lang()), cx);
 992
 993        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 994        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 995
 996        buffer.edit(
 997            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 998            Some(AutoindentMode::EachLine),
 999            cx,
1000        );
1001        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1002
1003        // Create a field expression on a new line, causing that line
1004        // to be indented.
1005        buffer.edit(
1006            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1007            Some(AutoindentMode::EachLine),
1008            cx,
1009        );
1010        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1011
1012        // Remove the dot so that the line is no longer a field expression,
1013        // causing the line to be outdented.
1014        buffer.edit(
1015            [(Point::new(2, 2)..Point::new(2, 3), "")],
1016            Some(AutoindentMode::EachLine),
1017            cx,
1018        );
1019        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1020
1021        buffer
1022    });
1023}
1024
1025#[gpui::test]
1026fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1027    init_settings(cx, |_| {});
1028
1029    cx.new_model(|cx| {
1030        let mut buffer = Buffer::new(
1031            0,
1032            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1033            "
1034            fn a() {
1035            c;
1036            d;
1037            }
1038            "
1039            .unindent(),
1040        )
1041        .with_language(Arc::new(rust_lang()), cx);
1042
1043        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1044        // their indentation is not adjusted.
1045        buffer.edit_via_marked_text(
1046            &"
1047            fn a() {
1048            c«()»;
1049            d«()»;
1050            }
1051            "
1052            .unindent(),
1053            Some(AutoindentMode::EachLine),
1054            cx,
1055        );
1056        assert_eq!(
1057            buffer.text(),
1058            "
1059            fn a() {
1060            c();
1061            d();
1062            }
1063            "
1064            .unindent()
1065        );
1066
1067        // When appending new content after these lines, the indentation is based on the
1068        // preceding lines' actual indentation.
1069        buffer.edit_via_marked_text(
1070            &"
1071            fn a() {
10721073            .f
1074            .g()»;
10751076            .f
1077            .g()»;
1078            }
1079            "
1080            .unindent(),
1081            Some(AutoindentMode::EachLine),
1082            cx,
1083        );
1084
1085        assert_eq!(
1086            buffer.text(),
1087            "
1088            fn a() {
1089            c
1090                .f
1091                .g();
1092            d
1093                .f
1094                .g();
1095            }
1096            "
1097            .unindent()
1098        );
1099        buffer
1100    });
1101
1102    cx.new_model(|cx| {
1103        eprintln!("second buffer: {:?}", cx.entity_id());
1104
1105        let mut buffer = Buffer::new(
1106            0,
1107            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1108            "
1109            fn a() {
1110                b();
1111                |
1112            "
1113            .replace("|", "") // marker to preserve trailing whitespace
1114            .unindent(),
1115        )
1116        .with_language(Arc::new(rust_lang()), cx);
1117
1118        // Insert a closing brace. It is outdented.
1119        buffer.edit_via_marked_text(
1120            &"
1121            fn a() {
1122                b();
1123                «}»
1124            "
1125            .unindent(),
1126            Some(AutoindentMode::EachLine),
1127            cx,
1128        );
1129        assert_eq!(
1130            buffer.text(),
1131            "
1132            fn a() {
1133                b();
1134            }
1135            "
1136            .unindent()
1137        );
1138
1139        // Manually edit the leading whitespace. The edit is preserved.
1140        buffer.edit_via_marked_text(
1141            &"
1142            fn a() {
1143                b();
1144            «    »}
1145            "
1146            .unindent(),
1147            Some(AutoindentMode::EachLine),
1148            cx,
1149        );
1150        assert_eq!(
1151            buffer.text(),
1152            "
1153            fn a() {
1154                b();
1155                }
1156            "
1157            .unindent()
1158        );
1159        buffer
1160    });
1161
1162    eprintln!("DONE");
1163}
1164
1165#[gpui::test]
1166fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1167    init_settings(cx, |_| {});
1168
1169    cx.new_model(|cx| {
1170        let mut buffer = Buffer::new(
1171            0,
1172            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1173            "
1174            fn a() {
1175                i
1176            }
1177            "
1178            .unindent(),
1179        )
1180        .with_language(Arc::new(rust_lang()), cx);
1181
1182        // Regression test: line does not get outdented due to syntax error
1183        buffer.edit_via_marked_text(
1184            &"
1185            fn a() {
1186                i«f let Some(x) = y»
1187            }
1188            "
1189            .unindent(),
1190            Some(AutoindentMode::EachLine),
1191            cx,
1192        );
1193        assert_eq!(
1194            buffer.text(),
1195            "
1196            fn a() {
1197                if let Some(x) = y
1198            }
1199            "
1200            .unindent()
1201        );
1202
1203        buffer.edit_via_marked_text(
1204            &"
1205            fn a() {
1206                if let Some(x) = y« {»
1207            }
1208            "
1209            .unindent(),
1210            Some(AutoindentMode::EachLine),
1211            cx,
1212        );
1213        assert_eq!(
1214            buffer.text(),
1215            "
1216            fn a() {
1217                if let Some(x) = y {
1218            }
1219            "
1220            .unindent()
1221        );
1222
1223        buffer
1224    });
1225}
1226
1227#[gpui::test]
1228fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1229    init_settings(cx, |_| {});
1230
1231    cx.new_model(|cx| {
1232        let mut buffer = Buffer::new(
1233            0,
1234            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1235            "
1236            fn a() {}
1237            "
1238            .unindent(),
1239        )
1240        .with_language(Arc::new(rust_lang()), cx);
1241
1242        buffer.edit_via_marked_text(
1243            &"
1244            fn a(«
1245            b») {}
1246            "
1247            .unindent(),
1248            Some(AutoindentMode::EachLine),
1249            cx,
1250        );
1251        assert_eq!(
1252            buffer.text(),
1253            "
1254            fn a(
1255                b) {}
1256            "
1257            .unindent()
1258        );
1259
1260        // The indentation suggestion changed because `@end` node (a close paren)
1261        // is now at the beginning of the line.
1262        buffer.edit_via_marked_text(
1263            &"
1264            fn a(
1265                ˇ) {}
1266            "
1267            .unindent(),
1268            Some(AutoindentMode::EachLine),
1269            cx,
1270        );
1271        assert_eq!(
1272            buffer.text(),
1273            "
1274                fn a(
1275                ) {}
1276            "
1277            .unindent()
1278        );
1279
1280        buffer
1281    });
1282}
1283
1284#[gpui::test]
1285fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1286    init_settings(cx, |_| {});
1287
1288    cx.new_model(|cx| {
1289        let text = "a\nb";
1290        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1291            .with_language(Arc::new(rust_lang()), cx);
1292        buffer.edit(
1293            [(0..1, "\n"), (2..3, "\n")],
1294            Some(AutoindentMode::EachLine),
1295            cx,
1296        );
1297        assert_eq!(buffer.text(), "\n\n\n");
1298        buffer
1299    });
1300}
1301
1302#[gpui::test]
1303fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1304    init_settings(cx, |_| {});
1305
1306    cx.new_model(|cx| {
1307        let text = "
1308            const a: usize = 1;
1309            fn b() {
1310                if c {
1311                    let d = 2;
1312                }
1313            }
1314        "
1315        .unindent();
1316
1317        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1318            .with_language(Arc::new(rust_lang()), cx);
1319        buffer.edit(
1320            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1321            Some(AutoindentMode::EachLine),
1322            cx,
1323        );
1324        assert_eq!(
1325            buffer.text(),
1326            "
1327                const a: usize = 1;
1328                fn b() {
1329                    if c {
1330                        e(
1331                            f()
1332                        );
1333                        let d = 2;
1334                    }
1335                }
1336            "
1337            .unindent()
1338        );
1339
1340        buffer
1341    });
1342}
1343
1344#[gpui::test]
1345fn test_autoindent_block_mode(cx: &mut AppContext) {
1346    init_settings(cx, |_| {});
1347
1348    cx.new_model(|cx| {
1349        let text = r#"
1350            fn a() {
1351                b();
1352            }
1353        "#
1354        .unindent();
1355        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1356            .with_language(Arc::new(rust_lang()), cx);
1357
1358        // When this text was copied, both of the quotation marks were at the same
1359        // indent level, but the indentation of the first line was not included in
1360        // the copied text. This information is retained in the
1361        // 'original_indent_columns' vector.
1362        let original_indent_columns = vec![4];
1363        let inserted_text = r#"
1364            "
1365                  c
1366                    d
1367                      e
1368                "
1369        "#
1370        .unindent();
1371
1372        // Insert the block at column zero. The entire block is indented
1373        // so that the first line matches the previous line's indentation.
1374        buffer.edit(
1375            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1376            Some(AutoindentMode::Block {
1377                original_indent_columns: original_indent_columns.clone(),
1378            }),
1379            cx,
1380        );
1381        assert_eq!(
1382            buffer.text(),
1383            r#"
1384            fn a() {
1385                b();
1386                "
1387                  c
1388                    d
1389                      e
1390                "
1391            }
1392            "#
1393            .unindent()
1394        );
1395
1396        // Grouping is disabled in tests, so we need 2 undos
1397        buffer.undo(cx); // Undo the auto-indent
1398        buffer.undo(cx); // Undo the original edit
1399
1400        // Insert the block at a deeper indent level. The entire block is outdented.
1401        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1402        buffer.edit(
1403            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1404            Some(AutoindentMode::Block {
1405                original_indent_columns: original_indent_columns.clone(),
1406            }),
1407            cx,
1408        );
1409        assert_eq!(
1410            buffer.text(),
1411            r#"
1412            fn a() {
1413                b();
1414                "
1415                  c
1416                    d
1417                      e
1418                "
1419            }
1420            "#
1421            .unindent()
1422        );
1423
1424        buffer
1425    });
1426}
1427
1428#[gpui::test]
1429fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1430    init_settings(cx, |_| {});
1431
1432    cx.new_model(|cx| {
1433        let text = r#"
1434            fn a() {
1435                if b() {
1436
1437                }
1438            }
1439        "#
1440        .unindent();
1441        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1442            .with_language(Arc::new(rust_lang()), cx);
1443
1444        // The original indent columns are not known, so this text is
1445        // auto-indented in a block as if the first line was copied in
1446        // its entirety.
1447        let original_indent_columns = Vec::new();
1448        let inserted_text = "    c\n        .d()\n        .e();";
1449
1450        // Insert the block at column zero. The entire block is indented
1451        // so that the first line matches the previous line's indentation.
1452        buffer.edit(
1453            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1454            Some(AutoindentMode::Block {
1455                original_indent_columns: original_indent_columns.clone(),
1456            }),
1457            cx,
1458        );
1459        assert_eq!(
1460            buffer.text(),
1461            r#"
1462            fn a() {
1463                if b() {
1464                    c
1465                        .d()
1466                        .e();
1467                }
1468            }
1469            "#
1470            .unindent()
1471        );
1472
1473        // Grouping is disabled in tests, so we need 2 undos
1474        buffer.undo(cx); // Undo the auto-indent
1475        buffer.undo(cx); // Undo the original edit
1476
1477        // Insert the block at a deeper indent level. The entire block is outdented.
1478        buffer.edit(
1479            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1480            None,
1481            cx,
1482        );
1483        buffer.edit(
1484            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1485            Some(AutoindentMode::Block {
1486                original_indent_columns: Vec::new(),
1487            }),
1488            cx,
1489        );
1490        assert_eq!(
1491            buffer.text(),
1492            r#"
1493            fn a() {
1494                if b() {
1495                    c
1496                        .d()
1497                        .e();
1498                }
1499            }
1500            "#
1501            .unindent()
1502        );
1503
1504        buffer
1505    });
1506}
1507
1508#[gpui::test]
1509fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1510    init_settings(cx, |_| {});
1511
1512    cx.new_model(|cx| {
1513        let text = "
1514            * one
1515                - a
1516                - b
1517            * two
1518        "
1519        .unindent();
1520
1521        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1522            .with_language(
1523                Arc::new(Language::new(
1524                    LanguageConfig {
1525                        name: "Markdown".into(),
1526                        auto_indent_using_last_non_empty_line: false,
1527                        ..Default::default()
1528                    },
1529                    Some(tree_sitter_json::language()),
1530                )),
1531                cx,
1532            );
1533        buffer.edit(
1534            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1535            Some(AutoindentMode::EachLine),
1536            cx,
1537        );
1538        assert_eq!(
1539            buffer.text(),
1540            "
1541            * one
1542                - a
1543                - b
1544
1545            * two
1546            "
1547            .unindent()
1548        );
1549        buffer
1550    });
1551}
1552
1553#[gpui::test]
1554fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1555    init_settings(cx, |settings| {
1556        settings.languages.extend([
1557            (
1558                "HTML".into(),
1559                LanguageSettingsContent {
1560                    tab_size: Some(2.try_into().unwrap()),
1561                    ..Default::default()
1562                },
1563            ),
1564            (
1565                "JavaScript".into(),
1566                LanguageSettingsContent {
1567                    tab_size: Some(8.try_into().unwrap()),
1568                    ..Default::default()
1569                },
1570            ),
1571        ])
1572    });
1573
1574    let html_language = Arc::new(html_lang());
1575
1576    let javascript_language = Arc::new(javascript_lang());
1577
1578    let language_registry = Arc::new(LanguageRegistry::test());
1579    language_registry.add(html_language.clone());
1580    language_registry.add(javascript_language.clone());
1581
1582    cx.new_model(|cx| {
1583        let (text, ranges) = marked_text_ranges(
1584            &"
1585                <div>ˇ
1586                </div>
1587                <script>
1588                    init({ˇ
1589                    })
1590                </script>
1591                <span>ˇ
1592                </span>
1593            "
1594            .unindent(),
1595            false,
1596        );
1597
1598        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
1599        buffer.set_language_registry(language_registry);
1600        buffer.set_language(Some(html_language), cx);
1601        buffer.edit(
1602            ranges.into_iter().map(|range| (range, "\na")),
1603            Some(AutoindentMode::EachLine),
1604            cx,
1605        );
1606        assert_eq!(
1607            buffer.text(),
1608            "
1609                <div>
1610                  a
1611                </div>
1612                <script>
1613                    init({
1614                            a
1615                    })
1616                </script>
1617                <span>
1618                  a
1619                </span>
1620            "
1621            .unindent()
1622        );
1623        buffer
1624    });
1625}
1626
1627#[gpui::test]
1628fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1629    init_settings(cx, |settings| {
1630        settings.defaults.tab_size = Some(2.try_into().unwrap());
1631    });
1632
1633    cx.new_model(|cx| {
1634        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
1635            .with_language(Arc::new(ruby_lang()), cx);
1636
1637        let text = r#"
1638            class C
1639            def a(b, c)
1640            puts b
1641            puts c
1642            rescue
1643            puts "errored"
1644            exit 1
1645            end
1646            end
1647        "#
1648        .unindent();
1649
1650        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1651
1652        assert_eq!(
1653            buffer.text(),
1654            r#"
1655                class C
1656                  def a(b, c)
1657                    puts b
1658                    puts c
1659                  rescue
1660                    puts "errored"
1661                    exit 1
1662                  end
1663                end
1664            "#
1665            .unindent()
1666        );
1667
1668        buffer
1669    });
1670}
1671
1672#[gpui::test]
1673fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1674    init_settings(cx, |_| {});
1675
1676    cx.new_model(|cx| {
1677        let language = Language::new(
1678            LanguageConfig {
1679                name: "JavaScript".into(),
1680                line_comments: vec!["// ".into()],
1681                brackets: BracketPairConfig {
1682                    pairs: vec![
1683                        BracketPair {
1684                            start: "{".into(),
1685                            end: "}".into(),
1686                            close: true,
1687                            newline: false,
1688                        },
1689                        BracketPair {
1690                            start: "'".into(),
1691                            end: "'".into(),
1692                            close: true,
1693                            newline: false,
1694                        },
1695                    ],
1696                    disabled_scopes_by_bracket_ix: vec![
1697                        Vec::new(), //
1698                        vec!["string".into()],
1699                    ],
1700                },
1701                overrides: [(
1702                    "element".into(),
1703                    LanguageConfigOverride {
1704                        line_comments: Override::Remove { remove: true },
1705                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1706                        ..Default::default()
1707                    },
1708                )]
1709                .into_iter()
1710                .collect(),
1711                ..Default::default()
1712            },
1713            Some(tree_sitter_typescript::language_tsx()),
1714        )
1715        .with_override_query(
1716            r#"
1717                (jsx_element) @element
1718                (string) @string
1719                [
1720                    (jsx_opening_element)
1721                    (jsx_closing_element)
1722                    (jsx_expression)
1723                ] @default
1724            "#,
1725        )
1726        .unwrap();
1727
1728        let text = r#"
1729            a["b"] = <C d="e">
1730                <F></F>
1731                { g() }
1732            </C>;
1733        "#
1734        .unindent();
1735
1736        let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), &text)
1737            .with_language(Arc::new(language), cx);
1738        let snapshot = buffer.snapshot();
1739
1740        let config = snapshot.language_scope_at(0).unwrap();
1741        assert_eq!(config.line_comment_prefixes().unwrap(), &[Arc::from("// ")]);
1742        // Both bracket pairs are enabled
1743        assert_eq!(
1744            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1745            &[true, true]
1746        );
1747
1748        let string_config = snapshot
1749            .language_scope_at(text.find("b\"").unwrap())
1750            .unwrap();
1751        assert_eq!(
1752            string_config.line_comment_prefixes().unwrap(),
1753            &[Arc::from("// ")]
1754        );
1755        // Second bracket pair is disabled
1756        assert_eq!(
1757            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1758            &[true, false]
1759        );
1760
1761        // In between JSX tags: use the `element` override.
1762        let element_config = snapshot
1763            .language_scope_at(text.find("<F>").unwrap())
1764            .unwrap();
1765        assert_eq!(element_config.line_comment_prefixes(), None);
1766        assert_eq!(
1767            element_config.block_comment_delimiters(),
1768            Some((&"{/*".into(), &"*/}".into()))
1769        );
1770        assert_eq!(
1771            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1772            &[true, true]
1773        );
1774
1775        // Within a JSX tag: use the default config.
1776        let tag_config = snapshot
1777            .language_scope_at(text.find(" d=").unwrap() + 1)
1778            .unwrap();
1779        assert_eq!(
1780            tag_config.line_comment_prefixes().unwrap(),
1781            &[Arc::from("// ")]
1782        );
1783        assert_eq!(
1784            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1785            &[true, true]
1786        );
1787
1788        // In a JSX expression: use the default config.
1789        let expression_in_element_config = snapshot
1790            .language_scope_at(text.find("{").unwrap() + 1)
1791            .unwrap();
1792        assert_eq!(
1793            expression_in_element_config
1794                .line_comment_prefixes()
1795                .unwrap(),
1796            &[Arc::from("// ")]
1797        );
1798        assert_eq!(
1799            expression_in_element_config
1800                .brackets()
1801                .map(|e| e.1)
1802                .collect::<Vec<_>>(),
1803            &[true, true]
1804        );
1805
1806        buffer
1807    });
1808}
1809
1810#[gpui::test]
1811fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1812    init_settings(cx, |_| {});
1813
1814    cx.new_model(|cx| {
1815        let language = Language::new(
1816            LanguageConfig {
1817                name: "Rust".into(),
1818                brackets: BracketPairConfig {
1819                    pairs: vec![
1820                        BracketPair {
1821                            start: "{".into(),
1822                            end: "}".into(),
1823                            close: true,
1824                            newline: false,
1825                        },
1826                        BracketPair {
1827                            start: "'".into(),
1828                            end: "'".into(),
1829                            close: true,
1830                            newline: false,
1831                        },
1832                    ],
1833                    disabled_scopes_by_bracket_ix: vec![
1834                        Vec::new(), //
1835                        vec!["string".into()],
1836                    ],
1837                },
1838                ..Default::default()
1839            },
1840            Some(tree_sitter_rust::language()),
1841        )
1842        .with_override_query(
1843            r#"
1844                (string_literal) @string
1845            "#,
1846        )
1847        .unwrap();
1848
1849        let text = r#"
1850            const S: &'static str = "hello";
1851        "#
1852        .unindent();
1853
1854        let buffer = Buffer::new(
1855            0,
1856            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1857            text.clone(),
1858        )
1859        .with_language(Arc::new(language), cx);
1860        let snapshot = buffer.snapshot();
1861
1862        // By default, all brackets are enabled
1863        let config = snapshot.language_scope_at(0).unwrap();
1864        assert_eq!(
1865            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1866            &[true, true]
1867        );
1868
1869        // Within a string, the quotation brackets are disabled.
1870        let string_config = snapshot
1871            .language_scope_at(text.find("ello").unwrap())
1872            .unwrap();
1873        assert_eq!(
1874            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1875            &[true, false]
1876        );
1877
1878        buffer
1879    });
1880}
1881
1882#[gpui::test]
1883fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1884    init_settings(cx, |_| {});
1885
1886    cx.new_model(|cx| {
1887        let text = r#"
1888            <ol>
1889            <% people.each do |person| %>
1890                <li>
1891                    <%= person.name %>
1892                </li>
1893            <% end %>
1894            </ol>
1895        "#
1896        .unindent();
1897
1898        let language_registry = Arc::new(LanguageRegistry::test());
1899        language_registry.add(Arc::new(ruby_lang()));
1900        language_registry.add(Arc::new(html_lang()));
1901        language_registry.add(Arc::new(erb_lang()));
1902
1903        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
1904        buffer.set_language_registry(language_registry.clone());
1905        buffer.set_language(
1906            language_registry
1907                .language_for_name("ERB")
1908                .now_or_never()
1909                .unwrap()
1910                .ok(),
1911            cx,
1912        );
1913
1914        let snapshot = buffer.snapshot();
1915        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1916        assert_eq!(html_config.line_comment_prefixes(), Some(&vec![]));
1917        assert_eq!(
1918            html_config.block_comment_delimiters(),
1919            Some((&"<!--".into(), &"-->".into()))
1920        );
1921
1922        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1923        assert_eq!(
1924            ruby_config.line_comment_prefixes().unwrap(),
1925            &[Arc::from("# ")]
1926        );
1927        assert_eq!(ruby_config.block_comment_delimiters(), None);
1928
1929        buffer
1930    });
1931}
1932
1933#[gpui::test]
1934fn test_serialization(cx: &mut gpui::AppContext) {
1935    let mut now = Instant::now();
1936
1937    let buffer1 = cx.new_model(|cx| {
1938        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abc");
1939        buffer.edit([(3..3, "D")], None, cx);
1940
1941        now += Duration::from_secs(1);
1942        buffer.start_transaction_at(now);
1943        buffer.edit([(4..4, "E")], None, cx);
1944        buffer.end_transaction_at(now, cx);
1945        assert_eq!(buffer.text(), "abcDE");
1946
1947        buffer.undo(cx);
1948        assert_eq!(buffer.text(), "abcD");
1949
1950        buffer.edit([(4..4, "F")], None, cx);
1951        assert_eq!(buffer.text(), "abcDF");
1952        buffer
1953    });
1954    assert_eq!(buffer1.read(cx).text(), "abcDF");
1955
1956    let state = buffer1.read(cx).to_proto();
1957    let ops = cx
1958        .background_executor()
1959        .block(buffer1.read(cx).serialize_ops(None, cx));
1960    let buffer2 = cx.new_model(|cx| {
1961        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
1962        buffer
1963            .apply_ops(
1964                ops.into_iter()
1965                    .map(|op| proto::deserialize_operation(op).unwrap()),
1966                cx,
1967            )
1968            .unwrap();
1969        buffer
1970    });
1971    assert_eq!(buffer2.read(cx).text(), "abcDF");
1972}
1973
1974#[gpui::test(iterations = 100)]
1975fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1976    let min_peers = env::var("MIN_PEERS")
1977        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1978        .unwrap_or(1);
1979    let max_peers = env::var("MAX_PEERS")
1980        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1981        .unwrap_or(5);
1982    let operations = env::var("OPERATIONS")
1983        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1984        .unwrap_or(10);
1985
1986    let base_text_len = rng.gen_range(0..10);
1987    let base_text = RandomCharIter::new(&mut rng)
1988        .take(base_text_len)
1989        .collect::<String>();
1990    let mut replica_ids = Vec::new();
1991    let mut buffers = Vec::new();
1992    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
1993    let base_buffer = cx.new_model(|cx| {
1994        Buffer::new(
1995            0,
1996            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1997            base_text.as_str(),
1998        )
1999    });
2000
2001    for i in 0..rng.gen_range(min_peers..=max_peers) {
2002        let buffer = cx.new_model(|cx| {
2003            let state = base_buffer.read(cx).to_proto();
2004            let ops = cx
2005                .background_executor()
2006                .block(base_buffer.read(cx).serialize_ops(None, cx));
2007            let mut buffer =
2008                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2009            buffer
2010                .apply_ops(
2011                    ops.into_iter()
2012                        .map(|op| proto::deserialize_operation(op).unwrap()),
2013                    cx,
2014                )
2015                .unwrap();
2016            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2017            let network = network.clone();
2018            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2019                if let Event::Operation(op) = event {
2020                    network
2021                        .lock()
2022                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2023                }
2024            })
2025            .detach();
2026            buffer
2027        });
2028
2029        buffers.push(buffer);
2030        replica_ids.push(i as ReplicaId);
2031        network.lock().add_peer(i as ReplicaId);
2032        log::info!("Adding initial peer with replica id {}", i);
2033    }
2034
2035    log::info!("initial text: {:?}", base_text);
2036
2037    let mut now = Instant::now();
2038    let mut mutation_count = operations;
2039    let mut next_diagnostic_id = 0;
2040    let mut active_selections = BTreeMap::default();
2041    loop {
2042        let replica_index = rng.gen_range(0..replica_ids.len());
2043        let replica_id = replica_ids[replica_index];
2044        let buffer = &mut buffers[replica_index];
2045        let mut new_buffer = None;
2046        match rng.gen_range(0..100) {
2047            0..=29 if mutation_count != 0 => {
2048                buffer.update(cx, |buffer, cx| {
2049                    buffer.start_transaction_at(now);
2050                    buffer.randomly_edit(&mut rng, 5, cx);
2051                    buffer.end_transaction_at(now, cx);
2052                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2053                });
2054                mutation_count -= 1;
2055            }
2056            30..=39 if mutation_count != 0 => {
2057                buffer.update(cx, |buffer, cx| {
2058                    if rng.gen_bool(0.2) {
2059                        log::info!("peer {} clearing active selections", replica_id);
2060                        active_selections.remove(&replica_id);
2061                        buffer.remove_active_selections(cx);
2062                    } else {
2063                        let mut selections = Vec::new();
2064                        for id in 0..rng.gen_range(1..=5) {
2065                            let range = buffer.random_byte_range(0, &mut rng);
2066                            selections.push(Selection {
2067                                id,
2068                                start: buffer.anchor_before(range.start),
2069                                end: buffer.anchor_before(range.end),
2070                                reversed: false,
2071                                goal: SelectionGoal::None,
2072                            });
2073                        }
2074                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2075                        log::info!(
2076                            "peer {} setting active selections: {:?}",
2077                            replica_id,
2078                            selections
2079                        );
2080                        active_selections.insert(replica_id, selections.clone());
2081                        buffer.set_active_selections(selections, false, Default::default(), cx);
2082                    }
2083                });
2084                mutation_count -= 1;
2085            }
2086            40..=49 if mutation_count != 0 && replica_id == 0 => {
2087                let entry_count = rng.gen_range(1..=5);
2088                buffer.update(cx, |buffer, cx| {
2089                    let diagnostics = DiagnosticSet::new(
2090                        (0..entry_count).map(|_| {
2091                            let range = buffer.random_byte_range(0, &mut rng);
2092                            let range = range.to_point_utf16(buffer);
2093                            let range = range.start..range.end;
2094                            DiagnosticEntry {
2095                                range,
2096                                diagnostic: Diagnostic {
2097                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2098                                    ..Default::default()
2099                                },
2100                            }
2101                        }),
2102                        buffer,
2103                    );
2104                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2105                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2106                });
2107                mutation_count -= 1;
2108            }
2109            50..=59 if replica_ids.len() < max_peers => {
2110                let old_buffer_state = buffer.read(cx).to_proto();
2111                let old_buffer_ops = cx
2112                    .background_executor()
2113                    .block(buffer.read(cx).serialize_ops(None, cx));
2114                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2115                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2116                    .choose(&mut rng)
2117                    .unwrap();
2118                log::info!(
2119                    "Adding new replica {} (replicating from {})",
2120                    new_replica_id,
2121                    replica_id
2122                );
2123                new_buffer = Some(cx.new_model(|cx| {
2124                    let mut new_buffer = Buffer::from_proto(
2125                        new_replica_id,
2126                        Capability::ReadWrite,
2127                        old_buffer_state,
2128                        None,
2129                    )
2130                    .unwrap();
2131                    new_buffer
2132                        .apply_ops(
2133                            old_buffer_ops
2134                                .into_iter()
2135                                .map(|op| deserialize_operation(op).unwrap()),
2136                            cx,
2137                        )
2138                        .unwrap();
2139                    log::info!(
2140                        "New replica {} text: {:?}",
2141                        new_buffer.replica_id(),
2142                        new_buffer.text()
2143                    );
2144                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2145                    let network = network.clone();
2146                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2147                        if let Event::Operation(op) = event {
2148                            network.lock().broadcast(
2149                                buffer.replica_id(),
2150                                vec![proto::serialize_operation(op)],
2151                            );
2152                        }
2153                    })
2154                    .detach();
2155                    new_buffer
2156                }));
2157                network.lock().replicate(replica_id, new_replica_id);
2158
2159                if new_replica_id as usize == replica_ids.len() {
2160                    replica_ids.push(new_replica_id);
2161                } else {
2162                    let new_buffer = new_buffer.take().unwrap();
2163                    while network.lock().has_unreceived(new_replica_id) {
2164                        let ops = network
2165                            .lock()
2166                            .receive(new_replica_id)
2167                            .into_iter()
2168                            .map(|op| proto::deserialize_operation(op).unwrap());
2169                        if ops.len() > 0 {
2170                            log::info!(
2171                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2172                                new_replica_id,
2173                                buffer.read(cx).version(),
2174                                ops.len(),
2175                                ops
2176                            );
2177                            new_buffer.update(cx, |new_buffer, cx| {
2178                                new_buffer.apply_ops(ops, cx).unwrap();
2179                            });
2180                        }
2181                    }
2182                    buffers[new_replica_id as usize] = new_buffer;
2183                }
2184            }
2185            60..=69 if mutation_count != 0 => {
2186                buffer.update(cx, |buffer, cx| {
2187                    buffer.randomly_undo_redo(&mut rng, cx);
2188                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2189                });
2190                mutation_count -= 1;
2191            }
2192            _ if network.lock().has_unreceived(replica_id) => {
2193                let ops = network
2194                    .lock()
2195                    .receive(replica_id)
2196                    .into_iter()
2197                    .map(|op| proto::deserialize_operation(op).unwrap());
2198                if ops.len() > 0 {
2199                    log::info!(
2200                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2201                        replica_id,
2202                        buffer.read(cx).version(),
2203                        ops.len(),
2204                        ops
2205                    );
2206                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2207                }
2208            }
2209            _ => {}
2210        }
2211
2212        now += Duration::from_millis(rng.gen_range(0..=200));
2213        buffers.extend(new_buffer);
2214
2215        for buffer in &buffers {
2216            buffer.read(cx).check_invariants();
2217        }
2218
2219        if mutation_count == 0 && network.lock().is_idle() {
2220            break;
2221        }
2222    }
2223
2224    let first_buffer = buffers[0].read(cx).snapshot();
2225    for buffer in &buffers[1..] {
2226        let buffer = buffer.read(cx).snapshot();
2227        assert_eq!(
2228            buffer.version(),
2229            first_buffer.version(),
2230            "Replica {} version != Replica 0 version",
2231            buffer.replica_id()
2232        );
2233        assert_eq!(
2234            buffer.text(),
2235            first_buffer.text(),
2236            "Replica {} text != Replica 0 text",
2237            buffer.replica_id()
2238        );
2239        assert_eq!(
2240            buffer
2241                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2242                .collect::<Vec<_>>(),
2243            first_buffer
2244                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2245                .collect::<Vec<_>>(),
2246            "Replica {} diagnostics != Replica 0 diagnostics",
2247            buffer.replica_id()
2248        );
2249    }
2250
2251    for buffer in &buffers {
2252        let buffer = buffer.read(cx).snapshot();
2253        let actual_remote_selections = buffer
2254            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2255            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2256            .collect::<Vec<_>>();
2257        let expected_remote_selections = active_selections
2258            .iter()
2259            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2260            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2261            .collect::<Vec<_>>();
2262        assert_eq!(
2263            actual_remote_selections,
2264            expected_remote_selections,
2265            "Replica {} remote selections != expected selections",
2266            buffer.replica_id()
2267        );
2268    }
2269}
2270
2271#[test]
2272fn test_contiguous_ranges() {
2273    assert_eq!(
2274        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2275        &[1..4, 5..7, 9..13]
2276    );
2277
2278    // Respects the `max_len` parameter
2279    assert_eq!(
2280        contiguous_ranges(
2281            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2282            3
2283        )
2284        .collect::<Vec<_>>(),
2285        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2286    );
2287}
2288
2289#[gpui::test(iterations = 500)]
2290fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2291    // Generate a random multi-line string containing
2292    // some lines with trailing whitespace.
2293    let mut text = String::new();
2294    for _ in 0..rng.gen_range(0..16) {
2295        for _ in 0..rng.gen_range(0..36) {
2296            text.push(match rng.gen_range(0..10) {
2297                0..=1 => ' ',
2298                3 => '\t',
2299                _ => rng.gen_range('a'..'z'),
2300            });
2301        }
2302        text.push('\n');
2303    }
2304
2305    match rng.gen_range(0..10) {
2306        // sometimes remove the last newline
2307        0..=1 => drop(text.pop()), //
2308
2309        // sometimes add extra newlines
2310        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2311        _ => {}
2312    }
2313
2314    let rope = Rope::from(text.as_str());
2315    let actual_ranges = trailing_whitespace_ranges(&rope);
2316    let expected_ranges = TRAILING_WHITESPACE_REGEX
2317        .find_iter(&text)
2318        .map(|m| m.range())
2319        .collect::<Vec<_>>();
2320    assert_eq!(
2321        actual_ranges,
2322        expected_ranges,
2323        "wrong ranges for text lines:\n{:?}",
2324        text.split("\n").collect::<Vec<_>>()
2325    );
2326}
2327
2328fn ruby_lang() -> Language {
2329    Language::new(
2330        LanguageConfig {
2331            name: "Ruby".into(),
2332            matcher: LanguageMatcher {
2333                path_suffixes: vec!["rb".to_string()],
2334                ..Default::default()
2335            },
2336            line_comments: vec!["# ".into()],
2337            ..Default::default()
2338        },
2339        Some(tree_sitter_ruby::language()),
2340    )
2341    .with_indents_query(
2342        r#"
2343            (class "end" @end) @indent
2344            (method "end" @end) @indent
2345            (rescue) @outdent
2346            (then) @indent
2347        "#,
2348    )
2349    .unwrap()
2350}
2351
2352fn html_lang() -> Language {
2353    Language::new(
2354        LanguageConfig {
2355            name: "HTML".into(),
2356            block_comment: Some(("<!--".into(), "-->".into())),
2357            ..Default::default()
2358        },
2359        Some(tree_sitter_html::language()),
2360    )
2361    .with_indents_query(
2362        "
2363        (element
2364          (start_tag) @start
2365          (end_tag)? @end) @indent
2366        ",
2367    )
2368    .unwrap()
2369    .with_injection_query(
2370        r#"
2371        (script_element
2372            (raw_text) @content
2373            (#set! "language" "javascript"))
2374        "#,
2375    )
2376    .unwrap()
2377}
2378
2379fn erb_lang() -> Language {
2380    Language::new(
2381        LanguageConfig {
2382            name: "ERB".into(),
2383            matcher: LanguageMatcher {
2384                path_suffixes: vec!["erb".to_string()],
2385                ..Default::default()
2386            },
2387            block_comment: Some(("<%#".into(), "%>".into())),
2388            ..Default::default()
2389        },
2390        Some(tree_sitter_embedded_template::language()),
2391    )
2392    .with_injection_query(
2393        r#"
2394            (
2395                (code) @content
2396                (#set! "language" "ruby")
2397                (#set! "combined")
2398            )
2399
2400            (
2401                (content) @content
2402                (#set! "language" "html")
2403                (#set! "combined")
2404            )
2405        "#,
2406    )
2407    .unwrap()
2408}
2409
2410fn rust_lang() -> Language {
2411    Language::new(
2412        LanguageConfig {
2413            name: "Rust".into(),
2414            matcher: LanguageMatcher {
2415                path_suffixes: vec!["rs".to_string()],
2416                ..Default::default()
2417            },
2418            ..Default::default()
2419        },
2420        Some(tree_sitter_rust::language()),
2421    )
2422    .with_indents_query(
2423        r#"
2424        (call_expression) @indent
2425        (field_expression) @indent
2426        (_ "(" ")" @end) @indent
2427        (_ "{" "}" @end) @indent
2428        "#,
2429    )
2430    .unwrap()
2431    .with_brackets_query(
2432        r#"
2433        ("{" @open "}" @close)
2434        "#,
2435    )
2436    .unwrap()
2437    .with_outline_query(
2438        r#"
2439        (struct_item
2440            "struct" @context
2441            name: (_) @name) @item
2442        (enum_item
2443            "enum" @context
2444            name: (_) @name) @item
2445        (enum_variant
2446            name: (_) @name) @item
2447        (field_declaration
2448            name: (_) @name) @item
2449        (impl_item
2450            "impl" @context
2451            trait: (_)? @name
2452            "for"? @context
2453            type: (_) @name) @item
2454        (function_item
2455            "fn" @context
2456            name: (_) @name) @item
2457        (mod_item
2458            "mod" @context
2459            name: (_) @name) @item
2460        "#,
2461    )
2462    .unwrap()
2463}
2464
2465fn json_lang() -> Language {
2466    Language::new(
2467        LanguageConfig {
2468            name: "Json".into(),
2469            matcher: LanguageMatcher {
2470                path_suffixes: vec!["js".to_string()],
2471                ..Default::default()
2472            },
2473            ..Default::default()
2474        },
2475        Some(tree_sitter_json::language()),
2476    )
2477}
2478
2479fn javascript_lang() -> Language {
2480    Language::new(
2481        LanguageConfig {
2482            name: "JavaScript".into(),
2483            ..Default::default()
2484        },
2485        Some(tree_sitter_typescript::language_tsx()),
2486    )
2487    .with_brackets_query(
2488        r#"
2489        ("{" @open "}" @close)
2490        ("(" @open ")" @close)
2491        "#,
2492    )
2493    .unwrap()
2494    .with_indents_query(
2495        r#"
2496        (object "}" @end) @indent
2497        "#,
2498    )
2499    .unwrap()
2500}
2501
2502fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2503    buffer.update(cx, |buffer, _| {
2504        let snapshot = buffer.snapshot();
2505        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2506        layers[0].node().to_sexp()
2507    })
2508}
2509
2510// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2511fn assert_bracket_pairs(
2512    selection_text: &'static str,
2513    bracket_pair_texts: Vec<&'static str>,
2514    language: Language,
2515    cx: &mut AppContext,
2516) {
2517    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2518    let buffer = cx.new_model(|cx| {
2519        Buffer::new(
2520            0,
2521            BufferId::new(cx.entity_id().as_u64()).unwrap(),
2522            expected_text.clone(),
2523        )
2524        .with_language(Arc::new(language), cx)
2525    });
2526    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2527
2528    let selection_range = selection_ranges[0].clone();
2529
2530    let bracket_pairs = bracket_pair_texts
2531        .into_iter()
2532        .map(|pair_text| {
2533            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2534            assert_eq!(bracket_text, expected_text);
2535            (ranges[0].clone(), ranges[1].clone())
2536        })
2537        .collect::<Vec<_>>();
2538
2539    assert_set_eq!(
2540        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2541        bracket_pairs
2542    );
2543}
2544
2545fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2546    let settings_store = SettingsStore::test(cx);
2547    cx.set_global(settings_store);
2548    crate::init(cx);
2549    cx.update_global::<SettingsStore, _>(|settings, cx| {
2550        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2551    });
2552}