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