buffer_tests.rs

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