buffer_tests.rs

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