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