buffer_tests.rs

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