buffer_tests.rs

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