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_with_javascript(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_typescript::language_tsx()),
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_rust(cx: &mut AppContext) {
1723    init_settings(cx, |_| {});
1724
1725    cx.add_model(|cx| {
1726        let language = Language::new(
1727            LanguageConfig {
1728                name: "Rust".into(),
1729                brackets: BracketPairConfig {
1730                    pairs: vec![
1731                        BracketPair {
1732                            start: "{".into(),
1733                            end: "}".into(),
1734                            close: true,
1735                            newline: false,
1736                        },
1737                        BracketPair {
1738                            start: "'".into(),
1739                            end: "'".into(),
1740                            close: true,
1741                            newline: false,
1742                        },
1743                    ],
1744                    disabled_scopes_by_bracket_ix: vec![
1745                        Vec::new(), //
1746                        vec!["string".into()],
1747                    ],
1748                },
1749                ..Default::default()
1750            },
1751            Some(tree_sitter_rust::language()),
1752        )
1753        .with_override_query(
1754            r#"
1755                (string_literal) @string
1756            "#,
1757        )
1758        .unwrap();
1759
1760        let text = r#"
1761            const S: &'static str = "hello";
1762        "#
1763        .unindent();
1764
1765        let buffer = Buffer::new(0, text.clone(), cx).with_language(Arc::new(language), cx);
1766        let snapshot = buffer.snapshot();
1767
1768        // By default, all brackets are enabled
1769        let config = snapshot.language_scope_at(0).unwrap();
1770        assert_eq!(
1771            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1772            &[true, true]
1773        );
1774
1775        // Within a string, the quotation brackets are disabled.
1776        let string_config = snapshot
1777            .language_scope_at(text.find("ello").unwrap())
1778            .unwrap();
1779        assert_eq!(
1780            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1781            &[true, false]
1782        );
1783
1784        buffer
1785    });
1786}
1787
1788#[gpui::test]
1789fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1790    init_settings(cx, |_| {});
1791
1792    cx.add_model(|cx| {
1793        let text = r#"
1794            <ol>
1795            <% people.each do |person| %>
1796                <li>
1797                    <%= person.name %>
1798                </li>
1799            <% end %>
1800            </ol>
1801        "#
1802        .unindent();
1803
1804        let language_registry = Arc::new(LanguageRegistry::test());
1805        language_registry.add(Arc::new(ruby_lang()));
1806        language_registry.add(Arc::new(html_lang()));
1807        language_registry.add(Arc::new(erb_lang()));
1808
1809        let mut buffer = Buffer::new(0, text, cx);
1810        buffer.set_language_registry(language_registry.clone());
1811        buffer.set_language(
1812            language_registry
1813                .language_for_name("ERB")
1814                .now_or_never()
1815                .unwrap()
1816                .ok(),
1817            cx,
1818        );
1819
1820        let snapshot = buffer.snapshot();
1821        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1822        assert_eq!(html_config.line_comment_prefix(), None);
1823        assert_eq!(
1824            html_config.block_comment_delimiters(),
1825            Some((&"<!--".into(), &"-->".into()))
1826        );
1827
1828        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1829        assert_eq!(ruby_config.line_comment_prefix().unwrap().as_ref(), "# ");
1830        assert_eq!(ruby_config.block_comment_delimiters(), None);
1831
1832        buffer
1833    });
1834}
1835
1836#[gpui::test]
1837fn test_serialization(cx: &mut gpui::AppContext) {
1838    let mut now = Instant::now();
1839
1840    let buffer1 = cx.add_model(|cx| {
1841        let mut buffer = Buffer::new(0, "abc", cx);
1842        buffer.edit([(3..3, "D")], None, cx);
1843
1844        now += Duration::from_secs(1);
1845        buffer.start_transaction_at(now);
1846        buffer.edit([(4..4, "E")], None, cx);
1847        buffer.end_transaction_at(now, cx);
1848        assert_eq!(buffer.text(), "abcDE");
1849
1850        buffer.undo(cx);
1851        assert_eq!(buffer.text(), "abcD");
1852
1853        buffer.edit([(4..4, "F")], None, cx);
1854        assert_eq!(buffer.text(), "abcDF");
1855        buffer
1856    });
1857    assert_eq!(buffer1.read(cx).text(), "abcDF");
1858
1859    let state = buffer1.read(cx).to_proto();
1860    let ops = cx
1861        .background()
1862        .block(buffer1.read(cx).serialize_ops(None, cx));
1863    let buffer2 = cx.add_model(|cx| {
1864        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1865        buffer
1866            .apply_ops(
1867                ops.into_iter()
1868                    .map(|op| proto::deserialize_operation(op).unwrap()),
1869                cx,
1870            )
1871            .unwrap();
1872        buffer
1873    });
1874    assert_eq!(buffer2.read(cx).text(), "abcDF");
1875}
1876
1877#[gpui::test(iterations = 100)]
1878fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1879    let min_peers = env::var("MIN_PEERS")
1880        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1881        .unwrap_or(1);
1882    let max_peers = env::var("MAX_PEERS")
1883        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1884        .unwrap_or(5);
1885    let operations = env::var("OPERATIONS")
1886        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1887        .unwrap_or(10);
1888
1889    let base_text_len = rng.gen_range(0..10);
1890    let base_text = RandomCharIter::new(&mut rng)
1891        .take(base_text_len)
1892        .collect::<String>();
1893    let mut replica_ids = Vec::new();
1894    let mut buffers = Vec::new();
1895    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1896    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1897
1898    for i in 0..rng.gen_range(min_peers..=max_peers) {
1899        let buffer = cx.add_model(|cx| {
1900            let state = base_buffer.read(cx).to_proto();
1901            let ops = cx
1902                .background()
1903                .block(base_buffer.read(cx).serialize_ops(None, cx));
1904            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1905            buffer
1906                .apply_ops(
1907                    ops.into_iter()
1908                        .map(|op| proto::deserialize_operation(op).unwrap()),
1909                    cx,
1910                )
1911                .unwrap();
1912            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1913            let network = network.clone();
1914            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1915                if let Event::Operation(op) = event {
1916                    network
1917                        .borrow_mut()
1918                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1919                }
1920            })
1921            .detach();
1922            buffer
1923        });
1924        buffers.push(buffer);
1925        replica_ids.push(i as ReplicaId);
1926        network.borrow_mut().add_peer(i as ReplicaId);
1927        log::info!("Adding initial peer with replica id {}", i);
1928    }
1929
1930    log::info!("initial text: {:?}", base_text);
1931
1932    let mut now = Instant::now();
1933    let mut mutation_count = operations;
1934    let mut next_diagnostic_id = 0;
1935    let mut active_selections = BTreeMap::default();
1936    loop {
1937        let replica_index = rng.gen_range(0..replica_ids.len());
1938        let replica_id = replica_ids[replica_index];
1939        let buffer = &mut buffers[replica_index];
1940        let mut new_buffer = None;
1941        match rng.gen_range(0..100) {
1942            0..=29 if mutation_count != 0 => {
1943                buffer.update(cx, |buffer, cx| {
1944                    buffer.start_transaction_at(now);
1945                    buffer.randomly_edit(&mut rng, 5, cx);
1946                    buffer.end_transaction_at(now, cx);
1947                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1948                });
1949                mutation_count -= 1;
1950            }
1951            30..=39 if mutation_count != 0 => {
1952                buffer.update(cx, |buffer, cx| {
1953                    if rng.gen_bool(0.2) {
1954                        log::info!("peer {} clearing active selections", replica_id);
1955                        active_selections.remove(&replica_id);
1956                        buffer.remove_active_selections(cx);
1957                    } else {
1958                        let mut selections = Vec::new();
1959                        for id in 0..rng.gen_range(1..=5) {
1960                            let range = buffer.random_byte_range(0, &mut rng);
1961                            selections.push(Selection {
1962                                id,
1963                                start: buffer.anchor_before(range.start),
1964                                end: buffer.anchor_before(range.end),
1965                                reversed: false,
1966                                goal: SelectionGoal::None,
1967                            });
1968                        }
1969                        let selections: Arc<[Selection<Anchor>]> = selections.into();
1970                        log::info!(
1971                            "peer {} setting active selections: {:?}",
1972                            replica_id,
1973                            selections
1974                        );
1975                        active_selections.insert(replica_id, selections.clone());
1976                        buffer.set_active_selections(selections, false, Default::default(), cx);
1977                    }
1978                });
1979                mutation_count -= 1;
1980            }
1981            40..=49 if mutation_count != 0 && replica_id == 0 => {
1982                let entry_count = rng.gen_range(1..=5);
1983                buffer.update(cx, |buffer, cx| {
1984                    let diagnostics = DiagnosticSet::new(
1985                        (0..entry_count).map(|_| {
1986                            let range = buffer.random_byte_range(0, &mut rng);
1987                            let range = range.to_point_utf16(buffer);
1988                            let range = range.start..range.end;
1989                            DiagnosticEntry {
1990                                range,
1991                                diagnostic: Diagnostic {
1992                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1993                                    ..Default::default()
1994                                },
1995                            }
1996                        }),
1997                        buffer,
1998                    );
1999                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2000                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2001                });
2002                mutation_count -= 1;
2003            }
2004            50..=59 if replica_ids.len() < max_peers => {
2005                let old_buffer_state = buffer.read(cx).to_proto();
2006                let old_buffer_ops = cx
2007                    .background()
2008                    .block(buffer.read(cx).serialize_ops(None, cx));
2009                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2010                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2011                    .choose(&mut rng)
2012                    .unwrap();
2013                log::info!(
2014                    "Adding new replica {} (replicating from {})",
2015                    new_replica_id,
2016                    replica_id
2017                );
2018                new_buffer = Some(cx.add_model(|cx| {
2019                    let mut new_buffer =
2020                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
2021                    new_buffer
2022                        .apply_ops(
2023                            old_buffer_ops
2024                                .into_iter()
2025                                .map(|op| deserialize_operation(op).unwrap()),
2026                            cx,
2027                        )
2028                        .unwrap();
2029                    log::info!(
2030                        "New replica {} text: {:?}",
2031                        new_buffer.replica_id(),
2032                        new_buffer.text()
2033                    );
2034                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2035                    let network = network.clone();
2036                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2037                        if let Event::Operation(op) = event {
2038                            network.borrow_mut().broadcast(
2039                                buffer.replica_id(),
2040                                vec![proto::serialize_operation(op)],
2041                            );
2042                        }
2043                    })
2044                    .detach();
2045                    new_buffer
2046                }));
2047                network.borrow_mut().replicate(replica_id, new_replica_id);
2048
2049                if new_replica_id as usize == replica_ids.len() {
2050                    replica_ids.push(new_replica_id);
2051                } else {
2052                    let new_buffer = new_buffer.take().unwrap();
2053                    while network.borrow().has_unreceived(new_replica_id) {
2054                        let ops = network
2055                            .borrow_mut()
2056                            .receive(new_replica_id)
2057                            .into_iter()
2058                            .map(|op| proto::deserialize_operation(op).unwrap());
2059                        if ops.len() > 0 {
2060                            log::info!(
2061                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2062                                new_replica_id,
2063                                buffer.read(cx).version(),
2064                                ops.len(),
2065                                ops
2066                            );
2067                            new_buffer.update(cx, |new_buffer, cx| {
2068                                new_buffer.apply_ops(ops, cx).unwrap();
2069                            });
2070                        }
2071                    }
2072                    buffers[new_replica_id as usize] = new_buffer;
2073                }
2074            }
2075            60..=69 if mutation_count != 0 => {
2076                buffer.update(cx, |buffer, cx| {
2077                    buffer.randomly_undo_redo(&mut rng, cx);
2078                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2079                });
2080                mutation_count -= 1;
2081            }
2082            _ if network.borrow().has_unreceived(replica_id) => {
2083                let ops = network
2084                    .borrow_mut()
2085                    .receive(replica_id)
2086                    .into_iter()
2087                    .map(|op| proto::deserialize_operation(op).unwrap());
2088                if ops.len() > 0 {
2089                    log::info!(
2090                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2091                        replica_id,
2092                        buffer.read(cx).version(),
2093                        ops.len(),
2094                        ops
2095                    );
2096                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2097                }
2098            }
2099            _ => {}
2100        }
2101
2102        now += Duration::from_millis(rng.gen_range(0..=200));
2103        buffers.extend(new_buffer);
2104
2105        for buffer in &buffers {
2106            buffer.read(cx).check_invariants();
2107        }
2108
2109        if mutation_count == 0 && network.borrow().is_idle() {
2110            break;
2111        }
2112    }
2113
2114    let first_buffer = buffers[0].read(cx).snapshot();
2115    for buffer in &buffers[1..] {
2116        let buffer = buffer.read(cx).snapshot();
2117        assert_eq!(
2118            buffer.version(),
2119            first_buffer.version(),
2120            "Replica {} version != Replica 0 version",
2121            buffer.replica_id()
2122        );
2123        assert_eq!(
2124            buffer.text(),
2125            first_buffer.text(),
2126            "Replica {} text != Replica 0 text",
2127            buffer.replica_id()
2128        );
2129        assert_eq!(
2130            buffer
2131                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2132                .collect::<Vec<_>>(),
2133            first_buffer
2134                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2135                .collect::<Vec<_>>(),
2136            "Replica {} diagnostics != Replica 0 diagnostics",
2137            buffer.replica_id()
2138        );
2139    }
2140
2141    for buffer in &buffers {
2142        let buffer = buffer.read(cx).snapshot();
2143        let actual_remote_selections = buffer
2144            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2145            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2146            .collect::<Vec<_>>();
2147        let expected_remote_selections = active_selections
2148            .iter()
2149            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2150            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2151            .collect::<Vec<_>>();
2152        assert_eq!(
2153            actual_remote_selections,
2154            expected_remote_selections,
2155            "Replica {} remote selections != expected selections",
2156            buffer.replica_id()
2157        );
2158    }
2159}
2160
2161#[test]
2162fn test_contiguous_ranges() {
2163    assert_eq!(
2164        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2165        &[1..4, 5..7, 9..13]
2166    );
2167
2168    // Respects the `max_len` parameter
2169    assert_eq!(
2170        contiguous_ranges(
2171            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2172            3
2173        )
2174        .collect::<Vec<_>>(),
2175        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2176    );
2177}
2178
2179#[gpui::test(iterations = 500)]
2180fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2181    // Generate a random multi-line string containing
2182    // some lines with trailing whitespace.
2183    let mut text = String::new();
2184    for _ in 0..rng.gen_range(0..16) {
2185        for _ in 0..rng.gen_range(0..36) {
2186            text.push(match rng.gen_range(0..10) {
2187                0..=1 => ' ',
2188                3 => '\t',
2189                _ => rng.gen_range('a'..'z'),
2190            });
2191        }
2192        text.push('\n');
2193    }
2194
2195    match rng.gen_range(0..10) {
2196        // sometimes remove the last newline
2197        0..=1 => drop(text.pop()), //
2198
2199        // sometimes add extra newlines
2200        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2201        _ => {}
2202    }
2203
2204    let rope = Rope::from(text.as_str());
2205    let actual_ranges = trailing_whitespace_ranges(&rope);
2206    let expected_ranges = TRAILING_WHITESPACE_REGEX
2207        .find_iter(&text)
2208        .map(|m| m.range())
2209        .collect::<Vec<_>>();
2210    assert_eq!(
2211        actual_ranges,
2212        expected_ranges,
2213        "wrong ranges for text lines:\n{:?}",
2214        text.split("\n").collect::<Vec<_>>()
2215    );
2216}
2217
2218fn ruby_lang() -> Language {
2219    Language::new(
2220        LanguageConfig {
2221            name: "Ruby".into(),
2222            path_suffixes: vec!["rb".to_string()],
2223            line_comment: Some("# ".into()),
2224            ..Default::default()
2225        },
2226        Some(tree_sitter_ruby::language()),
2227    )
2228    .with_indents_query(
2229        r#"
2230            (class "end" @end) @indent
2231            (method "end" @end) @indent
2232            (rescue) @outdent
2233            (then) @indent
2234        "#,
2235    )
2236    .unwrap()
2237}
2238
2239fn html_lang() -> Language {
2240    Language::new(
2241        LanguageConfig {
2242            name: "HTML".into(),
2243            block_comment: Some(("<!--".into(), "-->".into())),
2244            ..Default::default()
2245        },
2246        Some(tree_sitter_html::language()),
2247    )
2248    .with_indents_query(
2249        "
2250        (element
2251          (start_tag) @start
2252          (end_tag)? @end) @indent
2253        ",
2254    )
2255    .unwrap()
2256    .with_injection_query(
2257        r#"
2258        (script_element
2259            (raw_text) @content
2260            (#set! "language" "javascript"))
2261        "#,
2262    )
2263    .unwrap()
2264}
2265
2266fn erb_lang() -> Language {
2267    Language::new(
2268        LanguageConfig {
2269            name: "ERB".into(),
2270            path_suffixes: vec!["erb".to_string()],
2271            block_comment: Some(("<%#".into(), "%>".into())),
2272            ..Default::default()
2273        },
2274        Some(tree_sitter_embedded_template::language()),
2275    )
2276    .with_injection_query(
2277        r#"
2278            (
2279                (code) @content
2280                (#set! "language" "ruby")
2281                (#set! "combined")
2282            )
2283
2284            (
2285                (content) @content
2286                (#set! "language" "html")
2287                (#set! "combined")
2288            )
2289        "#,
2290    )
2291    .unwrap()
2292}
2293
2294fn rust_lang() -> Language {
2295    Language::new(
2296        LanguageConfig {
2297            name: "Rust".into(),
2298            path_suffixes: vec!["rs".to_string()],
2299            ..Default::default()
2300        },
2301        Some(tree_sitter_rust::language()),
2302    )
2303    .with_indents_query(
2304        r#"
2305        (call_expression) @indent
2306        (field_expression) @indent
2307        (_ "(" ")" @end) @indent
2308        (_ "{" "}" @end) @indent
2309        "#,
2310    )
2311    .unwrap()
2312    .with_brackets_query(
2313        r#"
2314        ("{" @open "}" @close)
2315        "#,
2316    )
2317    .unwrap()
2318    .with_outline_query(
2319        r#"
2320        (struct_item
2321            "struct" @context
2322            name: (_) @name) @item
2323        (enum_item
2324            "enum" @context
2325            name: (_) @name) @item
2326        (enum_variant
2327            name: (_) @name) @item
2328        (field_declaration
2329            name: (_) @name) @item
2330        (impl_item
2331            "impl" @context
2332            trait: (_)? @name
2333            "for"? @context
2334            type: (_) @name) @item
2335        (function_item
2336            "fn" @context
2337            name: (_) @name) @item
2338        (mod_item
2339            "mod" @context
2340            name: (_) @name) @item
2341        "#,
2342    )
2343    .unwrap()
2344}
2345
2346fn json_lang() -> Language {
2347    Language::new(
2348        LanguageConfig {
2349            name: "Json".into(),
2350            path_suffixes: vec!["js".to_string()],
2351            ..Default::default()
2352        },
2353        Some(tree_sitter_json::language()),
2354    )
2355}
2356
2357fn javascript_lang() -> Language {
2358    Language::new(
2359        LanguageConfig {
2360            name: "JavaScript".into(),
2361            ..Default::default()
2362        },
2363        Some(tree_sitter_typescript::language_tsx()),
2364    )
2365    .with_brackets_query(
2366        r#"
2367        ("{" @open "}" @close)
2368        ("(" @open ")" @close)
2369        "#,
2370    )
2371    .unwrap()
2372    .with_indents_query(
2373        r#"
2374        (object "}" @end) @indent
2375        "#,
2376    )
2377    .unwrap()
2378}
2379
2380fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2381    buffer.read_with(cx, |buffer, _| {
2382        let snapshot = buffer.snapshot();
2383        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2384        layers[0].node().to_sexp()
2385    })
2386}
2387
2388// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2389fn assert_bracket_pairs(
2390    selection_text: &'static str,
2391    bracket_pair_texts: Vec<&'static str>,
2392    language: Language,
2393    cx: &mut AppContext,
2394) {
2395    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2396    let buffer = cx.add_model(|cx| {
2397        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
2398    });
2399    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2400
2401    let selection_range = selection_ranges[0].clone();
2402
2403    let bracket_pairs = bracket_pair_texts
2404        .into_iter()
2405        .map(|pair_text| {
2406            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2407            assert_eq!(bracket_text, expected_text);
2408            (ranges[0].clone(), ranges[1].clone())
2409        })
2410        .collect::<Vec<_>>();
2411
2412    assert_set_eq!(
2413        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2414        bracket_pairs
2415    );
2416}
2417
2418fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2419    cx.set_global(SettingsStore::test(cx));
2420    crate::init(cx);
2421    cx.update_global::<SettingsStore, _, _>(|settings, cx| {
2422        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2423    });
2424}