buffer_tests.rs

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