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