buffer_tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use fs::LineEnding;
   5use gpui::{ModelHandle, MutableAppContext};
   6use proto::deserialize_operation;
   7use rand::prelude::*;
   8use settings::Settings;
   9use std::{
  10    cell::RefCell,
  11    env,
  12    ops::Range,
  13    rc::Rc,
  14    time::{Duration, Instant},
  15};
  16use text::network::Network;
  17use unindent::Unindent as _;
  18use util::{post_inc, test::marked_text_ranges, RandomCharIter};
  19
  20#[cfg(test)]
  21#[ctor::ctor]
  22fn init_logger() {
  23    if std::env::var("RUST_LOG").is_ok() {
  24        env_logger::init();
  25    }
  26}
  27
  28#[gpui::test]
  29fn test_line_endings(cx: &mut gpui::MutableAppContext) {
  30    cx.set_global(Settings::test(cx));
  31    cx.add_model(|cx| {
  32        let mut buffer =
  33            Buffer::new(0, "one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  34        assert_eq!(buffer.text(), "one\ntwo\nthree");
  35        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  36
  37        buffer.check_invariants();
  38        buffer.edit(
  39            [(buffer.len()..buffer.len(), "\r\nfour")],
  40            Some(AutoindentMode::EachLine),
  41            cx,
  42        );
  43        buffer.edit([(0..0, "zero\r\n")], None, cx);
  44        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  45        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  46        buffer.check_invariants();
  47
  48        buffer
  49    });
  50}
  51
  52#[gpui::test]
  53fn test_select_language() {
  54    let registry = LanguageRegistry::test();
  55    registry.add(Arc::new(Language::new(
  56        LanguageConfig {
  57            name: "Rust".into(),
  58            path_suffixes: vec!["rs".to_string()],
  59            ..Default::default()
  60        },
  61        Some(tree_sitter_rust::language()),
  62    )));
  63    registry.add(Arc::new(Language::new(
  64        LanguageConfig {
  65            name: "Make".into(),
  66            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  67            ..Default::default()
  68        },
  69        Some(tree_sitter_rust::language()),
  70    )));
  71
  72    // matching file extension
  73    assert_eq!(
  74        registry.select_language("zed/lib.rs").map(|l| l.name()),
  75        Some("Rust".into())
  76    );
  77    assert_eq!(
  78        registry.select_language("zed/lib.mk").map(|l| l.name()),
  79        Some("Make".into())
  80    );
  81
  82    // matching filename
  83    assert_eq!(
  84        registry.select_language("zed/Makefile").map(|l| l.name()),
  85        Some("Make".into())
  86    );
  87
  88    // matching suffix that is not the full file extension or filename
  89    assert_eq!(registry.select_language("zed/cars").map(|l| l.name()), None);
  90    assert_eq!(
  91        registry.select_language("zed/a.cars").map(|l| l.name()),
  92        None
  93    );
  94    assert_eq!(registry.select_language("zed/sumk").map(|l| l.name()), None);
  95}
  96
  97#[gpui::test]
  98fn test_edit_events(cx: &mut gpui::MutableAppContext) {
  99    let mut now = Instant::now();
 100    let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
 101    let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
 102
 103    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
 104    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
 105    let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
 106    buffer1.update(cx, {
 107        let buffer1_ops = buffer1_ops.clone();
 108        |buffer, cx| {
 109            let buffer_1_events = buffer_1_events.clone();
 110            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 111                Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
 112                event => buffer_1_events.borrow_mut().push(event),
 113            })
 114            .detach();
 115            let buffer_2_events = buffer_2_events.clone();
 116            cx.subscribe(&buffer2, move |_, _, event, _| {
 117                buffer_2_events.borrow_mut().push(event.clone())
 118            })
 119            .detach();
 120
 121            // An edit emits an edited event, followed by a dirty changed event,
 122            // since the buffer was previously in a clean state.
 123            buffer.edit([(2..4, "XYZ")], None, cx);
 124
 125            // An empty transaction does not emit any events.
 126            buffer.start_transaction();
 127            buffer.end_transaction(cx);
 128
 129            // A transaction containing two edits emits one edited event.
 130            now += Duration::from_secs(1);
 131            buffer.start_transaction_at(now);
 132            buffer.edit([(5..5, "u")], None, cx);
 133            buffer.edit([(6..6, "w")], None, cx);
 134            buffer.end_transaction_at(now, cx);
 135
 136            // Undoing a transaction emits one edited event.
 137            buffer.undo(cx);
 138        }
 139    });
 140
 141    // Incorporating a set of remote ops emits a single edited event,
 142    // followed by a dirty changed event.
 143    buffer2.update(cx, |buffer, cx| {
 144        buffer
 145            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 146            .unwrap();
 147    });
 148    assert_eq!(
 149        mem::take(&mut *buffer_1_events.borrow_mut()),
 150        vec![
 151            Event::Edited,
 152            Event::DirtyChanged,
 153            Event::Edited,
 154            Event::Edited,
 155        ]
 156    );
 157    assert_eq!(
 158        mem::take(&mut *buffer_2_events.borrow_mut()),
 159        vec![Event::Edited, Event::DirtyChanged]
 160    );
 161
 162    buffer1.update(cx, |buffer, cx| {
 163        // Undoing the first transaction emits edited event, followed by a
 164        // dirty changed event, since the buffer is again in a clean state.
 165        buffer.undo(cx);
 166    });
 167    // Incorporating the remote ops again emits a single edited event,
 168    // followed by a dirty changed event.
 169    buffer2.update(cx, |buffer, cx| {
 170        buffer
 171            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 172            .unwrap();
 173    });
 174    assert_eq!(
 175        mem::take(&mut *buffer_1_events.borrow_mut()),
 176        vec![Event::Edited, Event::DirtyChanged,]
 177    );
 178    assert_eq!(
 179        mem::take(&mut *buffer_2_events.borrow_mut()),
 180        vec![Event::Edited, Event::DirtyChanged]
 181    );
 182}
 183
 184#[gpui::test]
 185async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
 186    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 187    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 188    let anchor = buffer.read_with(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 189
 190    let text = "a\nccc\ndddd\nffffff\n";
 191    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 192    buffer.update(cx, |buffer, cx| {
 193        buffer.apply_diff(diff, cx).unwrap();
 194        assert_eq!(buffer.text(), text);
 195        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 196    });
 197
 198    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 199    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 200    buffer.update(cx, |buffer, cx| {
 201        buffer.apply_diff(diff, cx).unwrap();
 202        assert_eq!(buffer.text(), text);
 203        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 204    });
 205}
 206
 207#[gpui::test]
 208async fn test_reparse(cx: &mut gpui::TestAppContext) {
 209    let text = "fn a() {}";
 210    let buffer =
 211        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 212
 213    // Wait for the initial text to parse
 214    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 215    assert_eq!(
 216        get_tree_sexp(&buffer, cx),
 217        concat!(
 218            "(source_file (function_item name: (identifier) ",
 219            "parameters: (parameters) ",
 220            "body: (block)))"
 221        )
 222    );
 223
 224    buffer.update(cx, |buffer, _| {
 225        buffer.set_sync_parse_timeout(Duration::ZERO)
 226    });
 227
 228    // Perform some edits (add parameter and variable reference)
 229    // Parsing doesn't begin until the transaction is complete
 230    buffer.update(cx, |buf, cx| {
 231        buf.start_transaction();
 232
 233        let offset = buf.text().find(')').unwrap();
 234        buf.edit([(offset..offset, "b: C")], None, cx);
 235        assert!(!buf.is_parsing());
 236
 237        let offset = buf.text().find('}').unwrap();
 238        buf.edit([(offset..offset, " d; ")], None, cx);
 239        assert!(!buf.is_parsing());
 240
 241        buf.end_transaction(cx);
 242        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 243        assert!(buf.is_parsing());
 244    });
 245    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 246    assert_eq!(
 247        get_tree_sexp(&buffer, cx),
 248        concat!(
 249            "(source_file (function_item name: (identifier) ",
 250            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 251            "body: (block (expression_statement (identifier)))))"
 252        )
 253    );
 254
 255    // Perform a series of edits without waiting for the current parse to complete:
 256    // * turn identifier into a field expression
 257    // * turn field expression into a method call
 258    // * add a turbofish to the method call
 259    buffer.update(cx, |buf, cx| {
 260        let offset = buf.text().find(';').unwrap();
 261        buf.edit([(offset..offset, ".e")], None, cx);
 262        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 263        assert!(buf.is_parsing());
 264    });
 265    buffer.update(cx, |buf, cx| {
 266        let offset = buf.text().find(';').unwrap();
 267        buf.edit([(offset..offset, "(f)")], None, cx);
 268        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 269        assert!(buf.is_parsing());
 270    });
 271    buffer.update(cx, |buf, cx| {
 272        let offset = buf.text().find("(f)").unwrap();
 273        buf.edit([(offset..offset, "::<G>")], None, cx);
 274        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 275        assert!(buf.is_parsing());
 276    });
 277    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 278    assert_eq!(
 279        get_tree_sexp(&buffer, cx),
 280        concat!(
 281            "(source_file (function_item name: (identifier) ",
 282            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 283            "body: (block (expression_statement (call_expression ",
 284            "function: (generic_function ",
 285            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 286            "type_arguments: (type_arguments (type_identifier))) ",
 287            "arguments: (arguments (identifier)))))))",
 288        )
 289    );
 290
 291    buffer.update(cx, |buf, cx| {
 292        buf.undo(cx);
 293        assert_eq!(buf.text(), "fn a() {}");
 294        assert!(buf.is_parsing());
 295    });
 296    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 297    assert_eq!(
 298        get_tree_sexp(&buffer, cx),
 299        concat!(
 300            "(source_file (function_item name: (identifier) ",
 301            "parameters: (parameters) ",
 302            "body: (block)))"
 303        )
 304    );
 305
 306    buffer.update(cx, |buf, cx| {
 307        buf.redo(cx);
 308        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 309        assert!(buf.is_parsing());
 310    });
 311    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 312    assert_eq!(
 313        get_tree_sexp(&buffer, cx),
 314        concat!(
 315            "(source_file (function_item name: (identifier) ",
 316            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 317            "body: (block (expression_statement (call_expression ",
 318            "function: (generic_function ",
 319            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 320            "type_arguments: (type_arguments (type_identifier))) ",
 321            "arguments: (arguments (identifier)))))))",
 322        )
 323    );
 324}
 325
 326#[gpui::test]
 327async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 328    let buffer = cx.add_model(|cx| {
 329        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 330        buffer.set_sync_parse_timeout(Duration::ZERO);
 331        buffer
 332    });
 333
 334    // Wait for the initial text to parse
 335    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 336    assert_eq!(
 337        get_tree_sexp(&buffer, cx),
 338        "(source_file (expression_statement (block)))"
 339    );
 340
 341    buffer.update(cx, |buffer, cx| {
 342        buffer.set_language(Some(Arc::new(json_lang())), cx)
 343    });
 344    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 345    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 346}
 347
 348#[gpui::test]
 349async fn test_outline(cx: &mut gpui::TestAppContext) {
 350    let text = r#"
 351        struct Person {
 352            name: String,
 353            age: usize,
 354        }
 355
 356        mod module {
 357            enum LoginState {
 358                LoggedOut,
 359                LoggingOn,
 360                LoggedIn {
 361                    person: Person,
 362                    time: Instant,
 363                }
 364            }
 365        }
 366
 367        impl Eq for Person {}
 368
 369        impl Drop for Person {
 370            fn drop(&mut self) {
 371                println!("bye");
 372            }
 373        }
 374    "#
 375    .unindent();
 376
 377    let buffer =
 378        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 379    let outline = buffer
 380        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 381        .unwrap();
 382
 383    assert_eq!(
 384        outline
 385            .items
 386            .iter()
 387            .map(|item| (item.text.as_str(), item.depth))
 388            .collect::<Vec<_>>(),
 389        &[
 390            ("struct Person", 0),
 391            ("name", 1),
 392            ("age", 1),
 393            ("mod module", 0),
 394            ("enum LoginState", 1),
 395            ("LoggedOut", 2),
 396            ("LoggingOn", 2),
 397            ("LoggedIn", 2),
 398            ("person", 3),
 399            ("time", 3),
 400            ("impl Eq for Person", 0),
 401            ("impl Drop for Person", 0),
 402            ("fn drop", 1),
 403        ]
 404    );
 405
 406    // Without space, we only match on names
 407    assert_eq!(
 408        search(&outline, "oon", cx).await,
 409        &[
 410            ("mod module", vec![]),                    // included as the parent of a match
 411            ("enum LoginState", vec![]),               // included as the parent of a match
 412            ("LoggingOn", vec![1, 7, 8]),              // matches
 413            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 414        ]
 415    );
 416
 417    assert_eq!(
 418        search(&outline, "dp p", cx).await,
 419        &[
 420            ("impl Drop for Person", vec![5, 8, 9, 14]),
 421            ("fn drop", vec![]),
 422        ]
 423    );
 424    assert_eq!(
 425        search(&outline, "dpn", cx).await,
 426        &[("impl Drop for Person", vec![5, 14, 19])]
 427    );
 428    assert_eq!(
 429        search(&outline, "impl ", cx).await,
 430        &[
 431            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 432            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 433            ("fn drop", vec![]),
 434        ]
 435    );
 436
 437    async fn search<'a>(
 438        outline: &'a Outline<Anchor>,
 439        query: &'a str,
 440        cx: &'a gpui::TestAppContext,
 441    ) -> Vec<(&'a str, Vec<usize>)> {
 442        let matches = cx
 443            .read(|cx| outline.search(query, cx.background().clone()))
 444            .await;
 445        matches
 446            .into_iter()
 447            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 448            .collect::<Vec<_>>()
 449    }
 450}
 451
 452#[gpui::test]
 453async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 454    let text = r#"
 455        impl Person {
 456            fn one() {
 457                1
 458            }
 459
 460            fn two() {
 461                2
 462            }fn three() {
 463                3
 464            }
 465        }
 466    "#
 467    .unindent();
 468
 469    let buffer =
 470        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 471    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 472
 473    // point is at the start of an item
 474    assert_eq!(
 475        symbols_containing(Point::new(1, 4), &snapshot),
 476        vec![
 477            (
 478                "impl Person".to_string(),
 479                Point::new(0, 0)..Point::new(10, 1)
 480            ),
 481            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 482        ]
 483    );
 484
 485    // point is in the middle of an item
 486    assert_eq!(
 487        symbols_containing(Point::new(2, 8), &snapshot),
 488        vec![
 489            (
 490                "impl Person".to_string(),
 491                Point::new(0, 0)..Point::new(10, 1)
 492            ),
 493            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 494        ]
 495    );
 496
 497    // point is at the end of an item
 498    assert_eq!(
 499        symbols_containing(Point::new(3, 5), &snapshot),
 500        vec![
 501            (
 502                "impl Person".to_string(),
 503                Point::new(0, 0)..Point::new(10, 1)
 504            ),
 505            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 506        ]
 507    );
 508
 509    // point is in between two adjacent items
 510    assert_eq!(
 511        symbols_containing(Point::new(7, 5), &snapshot),
 512        vec![
 513            (
 514                "impl Person".to_string(),
 515                Point::new(0, 0)..Point::new(10, 1)
 516            ),
 517            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 518        ]
 519    );
 520
 521    fn symbols_containing(
 522        position: Point,
 523        snapshot: &BufferSnapshot,
 524    ) -> Vec<(String, Range<Point>)> {
 525        snapshot
 526            .symbols_containing(position, None)
 527            .unwrap()
 528            .into_iter()
 529            .map(|item| {
 530                (
 531                    item.text,
 532                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 533                )
 534            })
 535            .collect()
 536    }
 537}
 538
 539#[gpui::test]
 540fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 541    cx.set_global(Settings::test(cx));
 542    let buffer = cx.add_model(|cx| {
 543        let text = "
 544            mod x {
 545                mod y {
 546
 547                }
 548            }
 549        "
 550        .unindent();
 551        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
 552    });
 553    let buffer = buffer.read(cx);
 554    assert_eq!(
 555        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
 556        Some((
 557            Point::new(0, 6)..Point::new(0, 7),
 558            Point::new(4, 0)..Point::new(4, 1)
 559        ))
 560    );
 561    assert_eq!(
 562        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
 563        Some((
 564            Point::new(1, 10)..Point::new(1, 11),
 565            Point::new(3, 4)..Point::new(3, 5)
 566        ))
 567    );
 568    assert_eq!(
 569        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
 570        Some((
 571            Point::new(1, 10)..Point::new(1, 11),
 572            Point::new(3, 4)..Point::new(3, 5)
 573        ))
 574    );
 575
 576    // Regression test: avoid crash when querying at the end of the buffer.
 577    assert_eq!(
 578        buffer.enclosing_bracket_point_ranges(buffer.len() - 1..buffer.len()),
 579        Some((
 580            Point::new(0, 6)..Point::new(0, 7),
 581            Point::new(4, 0)..Point::new(4, 1)
 582        ))
 583    );
 584}
 585
 586#[gpui::test]
 587fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 588    cx.add_model(|cx| {
 589        let text = "fn a() { b(|c| {}) }";
 590        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 591        let snapshot = buffer.snapshot();
 592
 593        assert_eq!(
 594            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 595            Some(range_of(text, "|"))
 596        );
 597        assert_eq!(
 598            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 599            Some(range_of(text, "|c|"))
 600        );
 601        assert_eq!(
 602            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 603            Some(range_of(text, "|c| {}"))
 604        );
 605        assert_eq!(
 606            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 607            Some(range_of(text, "(|c| {})"))
 608        );
 609
 610        buffer
 611    });
 612
 613    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 614        let start = text.find(part).unwrap();
 615        start..start
 616    }
 617
 618    fn range_of(text: &str, part: &str) -> Range<usize> {
 619        let start = text.find(part).unwrap();
 620        start..start + part.len()
 621    }
 622}
 623
 624#[gpui::test]
 625fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 626    let settings = Settings::test(cx);
 627    cx.set_global(settings);
 628
 629    cx.add_model(|cx| {
 630        let text = "fn a() {}";
 631        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 632
 633        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 634        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 635
 636        buffer.edit(
 637            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 638            Some(AutoindentMode::EachLine),
 639            cx,
 640        );
 641        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 642
 643        // Create a field expression on a new line, causing that line
 644        // to be indented.
 645        buffer.edit(
 646            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 647            Some(AutoindentMode::EachLine),
 648            cx,
 649        );
 650        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 651
 652        // Remove the dot so that the line is no longer a field expression,
 653        // causing the line to be outdented.
 654        buffer.edit(
 655            [(Point::new(2, 8)..Point::new(2, 9), "")],
 656            Some(AutoindentMode::EachLine),
 657            cx,
 658        );
 659        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 660
 661        buffer
 662    });
 663}
 664
 665#[gpui::test]
 666fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 667    let mut settings = Settings::test(cx);
 668    settings.editor_overrides.hard_tabs = Some(true);
 669    cx.set_global(settings);
 670
 671    cx.add_model(|cx| {
 672        let text = "fn a() {}";
 673        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 674
 675        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 676        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 677
 678        buffer.edit(
 679            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 680            Some(AutoindentMode::EachLine),
 681            cx,
 682        );
 683        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 684
 685        // Create a field expression on a new line, causing that line
 686        // to be indented.
 687        buffer.edit(
 688            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 689            Some(AutoindentMode::EachLine),
 690            cx,
 691        );
 692        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 693
 694        // Remove the dot so that the line is no longer a field expression,
 695        // causing the line to be outdented.
 696        buffer.edit(
 697            [(Point::new(2, 2)..Point::new(2, 3), "")],
 698            Some(AutoindentMode::EachLine),
 699            cx,
 700        );
 701        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 702
 703        buffer
 704    });
 705}
 706
 707#[gpui::test]
 708fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 709    let settings = Settings::test(cx);
 710    cx.set_global(settings);
 711
 712    cx.add_model(|cx| {
 713        let text = "
 714            fn a() {
 715            c;
 716            d;
 717            }
 718        "
 719        .unindent();
 720
 721        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 722
 723        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 724        // their indentation is not adjusted.
 725        buffer.edit(
 726            [
 727                (empty(Point::new(1, 1)), "()"),
 728                (empty(Point::new(2, 1)), "()"),
 729            ],
 730            Some(AutoindentMode::EachLine),
 731            cx,
 732        );
 733        assert_eq!(
 734            buffer.text(),
 735            "
 736            fn a() {
 737            c();
 738            d();
 739            }
 740            "
 741            .unindent()
 742        );
 743
 744        // When appending new content after these lines, the indentation is based on the
 745        // preceding lines' actual indentation.
 746        buffer.edit(
 747            [
 748                (empty(Point::new(1, 1)), "\n.f\n.g"),
 749                (empty(Point::new(2, 1)), "\n.f\n.g"),
 750            ],
 751            Some(AutoindentMode::EachLine),
 752            cx,
 753        );
 754        assert_eq!(
 755            buffer.text(),
 756            "
 757            fn a() {
 758            c
 759                .f
 760                .g();
 761            d
 762                .f
 763                .g();
 764            }
 765            "
 766            .unindent()
 767        );
 768        buffer
 769    });
 770
 771    cx.add_model(|cx| {
 772        let text = "
 773            fn a() {
 774                {
 775                    b()?
 776                }
 777                Ok(())
 778            }
 779        "
 780        .unindent();
 781        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 782
 783        // Delete a closing curly brace changes the suggested indent for the line.
 784        buffer.edit(
 785            [(Point::new(3, 4)..Point::new(3, 5), "")],
 786            Some(AutoindentMode::EachLine),
 787            cx,
 788        );
 789        assert_eq!(
 790            buffer.text(),
 791            "
 792            fn a() {
 793                {
 794                    b()?
 795                        |
 796                Ok(())
 797            }
 798            "
 799            .replace('|', "") // included in the string to preserve trailing whites
 800            .unindent()
 801        );
 802
 803        // Manually editing the leading whitespace
 804        buffer.edit(
 805            [(Point::new(3, 0)..Point::new(3, 12), "")],
 806            Some(AutoindentMode::EachLine),
 807            cx,
 808        );
 809        assert_eq!(
 810            buffer.text(),
 811            "
 812            fn a() {
 813                {
 814                    b()?
 815
 816                Ok(())
 817            }
 818            "
 819            .unindent()
 820        );
 821        buffer
 822    });
 823}
 824
 825#[gpui::test]
 826fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 827    cx.set_global(Settings::test(cx));
 828    cx.add_model(|cx| {
 829        let text = "
 830            fn a() {}
 831        "
 832        .unindent();
 833
 834        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 835
 836        buffer.edit([(5..5, "\nb")], Some(AutoindentMode::EachLine), cx);
 837        assert_eq!(
 838            buffer.text(),
 839            "
 840                fn a(
 841                    b) {}
 842            "
 843            .unindent()
 844        );
 845
 846        // The indentation suggestion changed because `@end` node (a close paren)
 847        // is now at the beginning of the line.
 848        buffer.edit(
 849            [(Point::new(1, 4)..Point::new(1, 5), "")],
 850            Some(AutoindentMode::EachLine),
 851            cx,
 852        );
 853        assert_eq!(
 854            buffer.text(),
 855            "
 856                fn a(
 857                ) {}
 858            "
 859            .unindent()
 860        );
 861
 862        buffer
 863    });
 864}
 865
 866#[gpui::test]
 867fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 868    cx.set_global(Settings::test(cx));
 869    cx.add_model(|cx| {
 870        let text = "a\nb";
 871        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 872        buffer.edit(
 873            [(0..1, "\n"), (2..3, "\n")],
 874            Some(AutoindentMode::EachLine),
 875            cx,
 876        );
 877        assert_eq!(buffer.text(), "\n\n\n");
 878        buffer
 879    });
 880}
 881
 882#[gpui::test]
 883fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 884    cx.set_global(Settings::test(cx));
 885    cx.add_model(|cx| {
 886        let text = "
 887            const a: usize = 1;
 888            fn b() {
 889                if c {
 890                    let d = 2;
 891                }
 892            }
 893        "
 894        .unindent();
 895
 896        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 897        buffer.edit(
 898            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
 899            Some(AutoindentMode::EachLine),
 900            cx,
 901        );
 902        assert_eq!(
 903            buffer.text(),
 904            "
 905                const a: usize = 1;
 906                fn b() {
 907                    if c {
 908                        e(
 909                            f()
 910                        );
 911                        let d = 2;
 912                    }
 913                }
 914            "
 915            .unindent()
 916        );
 917
 918        buffer
 919    });
 920}
 921
 922#[gpui::test]
 923fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
 924    cx.set_global(Settings::test(cx));
 925    cx.add_model(|cx| {
 926        let text = r#"
 927            fn a() {
 928                b();
 929            }
 930        "#
 931        .unindent();
 932        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 933
 934        let inserted_text = r#"
 935            "
 936              c
 937                d
 938                  e
 939            "
 940        "#
 941        .unindent();
 942
 943        // Insert the block at column zero. The entire block is indented
 944        // so that the first line matches the previous line's indentation.
 945        buffer.edit(
 946            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
 947            Some(AutoindentMode::Block {
 948                original_indent_columns: vec![0],
 949            }),
 950            cx,
 951        );
 952        assert_eq!(
 953            buffer.text(),
 954            r#"
 955            fn a() {
 956                b();
 957                "
 958                  c
 959                    d
 960                      e
 961                "
 962            }
 963            "#
 964            .unindent()
 965        );
 966
 967        // Insert the block at a deeper indent level. The entire block is outdented.
 968        buffer.undo(cx);
 969        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
 970        buffer.edit(
 971            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
 972            Some(AutoindentMode::Block {
 973                original_indent_columns: vec![0],
 974            }),
 975            cx,
 976        );
 977        assert_eq!(
 978            buffer.text(),
 979            r#"
 980            fn a() {
 981                b();
 982                "
 983                  c
 984                    d
 985                      e
 986                "
 987            }
 988            "#
 989            .unindent()
 990        );
 991
 992        buffer
 993    });
 994}
 995
 996#[gpui::test]
 997fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
 998    cx.set_global(Settings::test(cx));
 999    cx.add_model(|cx| {
1000        let text = "
1001            * one
1002                - a
1003                - b
1004            * two
1005        "
1006        .unindent();
1007
1008        let mut buffer = Buffer::new(0, text, cx).with_language(
1009            Arc::new(Language::new(
1010                LanguageConfig {
1011                    name: "Markdown".into(),
1012                    auto_indent_using_last_non_empty_line: false,
1013                    ..Default::default()
1014                },
1015                Some(tree_sitter_json::language()),
1016            )),
1017            cx,
1018        );
1019        buffer.edit(
1020            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1021            Some(AutoindentMode::EachLine),
1022            cx,
1023        );
1024        assert_eq!(
1025            buffer.text(),
1026            "
1027            * one
1028                - a
1029                - b
1030
1031            * two
1032            "
1033            .unindent()
1034        );
1035        buffer
1036    });
1037}
1038
1039#[gpui::test]
1040fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
1041    cx.set_global({
1042        let mut settings = Settings::test(cx);
1043        settings.language_overrides.extend([
1044            (
1045                "HTML".into(),
1046                settings::EditorSettings {
1047                    tab_size: Some(2.try_into().unwrap()),
1048                    ..Default::default()
1049                },
1050            ),
1051            (
1052                "JavaScript".into(),
1053                settings::EditorSettings {
1054                    tab_size: Some(8.try_into().unwrap()),
1055                    ..Default::default()
1056                },
1057            ),
1058        ]);
1059        settings
1060    });
1061
1062    let html_language = Arc::new(
1063        Language::new(
1064            LanguageConfig {
1065                name: "HTML".into(),
1066                ..Default::default()
1067            },
1068            Some(tree_sitter_html::language()),
1069        )
1070        .with_indents_query(
1071            "
1072            (element
1073              (start_tag) @start
1074              (end_tag)? @end) @indent
1075            ",
1076        )
1077        .unwrap()
1078        .with_injection_query(
1079            r#"
1080            (script_element
1081                (raw_text) @content
1082                (#set! "language" "javascript"))
1083            "#,
1084        )
1085        .unwrap(),
1086    );
1087
1088    let javascript_language = Arc::new(
1089        Language::new(
1090            LanguageConfig {
1091                name: "JavaScript".into(),
1092                ..Default::default()
1093            },
1094            Some(tree_sitter_javascript::language()),
1095        )
1096        .with_indents_query(
1097            r#"
1098            (object "}" @end) @indent
1099            "#,
1100        )
1101        .unwrap(),
1102    );
1103
1104    let language_registry = Arc::new(LanguageRegistry::test());
1105    language_registry.add(html_language.clone());
1106    language_registry.add(javascript_language.clone());
1107
1108    cx.add_model(|cx| {
1109        let (text, ranges) = marked_text_ranges(
1110            &"
1111                <div>ˇ
1112                </div>
1113                <script>
1114                    init({ˇ
1115                    })
1116                </script>
1117                <span>ˇ
1118                </span>
1119            "
1120            .unindent(),
1121            false,
1122        );
1123
1124        let mut buffer = Buffer::new(0, text, cx);
1125        buffer.set_language_registry(language_registry);
1126        buffer.set_language(Some(html_language), cx);
1127        buffer.edit(
1128            ranges.into_iter().map(|range| (range, "\na")),
1129            Some(AutoindentMode::EachLine),
1130            cx,
1131        );
1132        assert_eq!(
1133            buffer.text(),
1134            "
1135                <div>
1136                  a
1137                </div>
1138                <script>
1139                    init({
1140                            a
1141                    })
1142                </script>
1143                <span>
1144                  a
1145                </span>
1146            "
1147            .unindent()
1148        );
1149        buffer
1150    });
1151}
1152
1153#[gpui::test]
1154fn test_serialization(cx: &mut gpui::MutableAppContext) {
1155    let mut now = Instant::now();
1156
1157    let buffer1 = cx.add_model(|cx| {
1158        let mut buffer = Buffer::new(0, "abc", cx);
1159        buffer.edit([(3..3, "D")], None, cx);
1160
1161        now += Duration::from_secs(1);
1162        buffer.start_transaction_at(now);
1163        buffer.edit([(4..4, "E")], None, cx);
1164        buffer.end_transaction_at(now, cx);
1165        assert_eq!(buffer.text(), "abcDE");
1166
1167        buffer.undo(cx);
1168        assert_eq!(buffer.text(), "abcD");
1169
1170        buffer.edit([(4..4, "F")], None, cx);
1171        assert_eq!(buffer.text(), "abcDF");
1172        buffer
1173    });
1174    assert_eq!(buffer1.read(cx).text(), "abcDF");
1175
1176    let state = buffer1.read(cx).to_proto();
1177    let ops = cx.background().block(buffer1.read(cx).serialize_ops(cx));
1178    let buffer2 = cx.add_model(|cx| {
1179        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1180        buffer
1181            .apply_ops(
1182                ops.into_iter()
1183                    .map(|op| proto::deserialize_operation(op).unwrap()),
1184                cx,
1185            )
1186            .unwrap();
1187        buffer
1188    });
1189    assert_eq!(buffer2.read(cx).text(), "abcDF");
1190}
1191
1192#[gpui::test(iterations = 100)]
1193fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1194    let min_peers = env::var("MIN_PEERS")
1195        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1196        .unwrap_or(1);
1197    let max_peers = env::var("MAX_PEERS")
1198        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1199        .unwrap_or(5);
1200    let operations = env::var("OPERATIONS")
1201        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1202        .unwrap_or(10);
1203
1204    let base_text_len = rng.gen_range(0..10);
1205    let base_text = RandomCharIter::new(&mut rng)
1206        .take(base_text_len)
1207        .collect::<String>();
1208    let mut replica_ids = Vec::new();
1209    let mut buffers = Vec::new();
1210    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1211    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1212
1213    for i in 0..rng.gen_range(min_peers..=max_peers) {
1214        let buffer = cx.add_model(|cx| {
1215            let state = base_buffer.read(cx).to_proto();
1216            let ops = cx
1217                .background()
1218                .block(base_buffer.read(cx).serialize_ops(cx));
1219            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1220            buffer
1221                .apply_ops(
1222                    ops.into_iter()
1223                        .map(|op| proto::deserialize_operation(op).unwrap()),
1224                    cx,
1225                )
1226                .unwrap();
1227            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1228            let network = network.clone();
1229            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1230                if let Event::Operation(op) = event {
1231                    network
1232                        .borrow_mut()
1233                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1234                }
1235            })
1236            .detach();
1237            buffer
1238        });
1239        buffers.push(buffer);
1240        replica_ids.push(i as ReplicaId);
1241        network.borrow_mut().add_peer(i as ReplicaId);
1242        log::info!("Adding initial peer with replica id {}", i);
1243    }
1244
1245    log::info!("initial text: {:?}", base_text);
1246
1247    let mut now = Instant::now();
1248    let mut mutation_count = operations;
1249    let mut next_diagnostic_id = 0;
1250    let mut active_selections = BTreeMap::default();
1251    loop {
1252        let replica_index = rng.gen_range(0..replica_ids.len());
1253        let replica_id = replica_ids[replica_index];
1254        let buffer = &mut buffers[replica_index];
1255        let mut new_buffer = None;
1256        match rng.gen_range(0..100) {
1257            0..=29 if mutation_count != 0 => {
1258                buffer.update(cx, |buffer, cx| {
1259                    buffer.start_transaction_at(now);
1260                    buffer.randomly_edit(&mut rng, 5, cx);
1261                    buffer.end_transaction_at(now, cx);
1262                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1263                });
1264                mutation_count -= 1;
1265            }
1266            30..=39 if mutation_count != 0 => {
1267                buffer.update(cx, |buffer, cx| {
1268                    let mut selections = Vec::new();
1269                    for id in 0..rng.gen_range(1..=5) {
1270                        let range = buffer.random_byte_range(0, &mut rng);
1271                        selections.push(Selection {
1272                            id,
1273                            start: buffer.anchor_before(range.start),
1274                            end: buffer.anchor_before(range.end),
1275                            reversed: false,
1276                            goal: SelectionGoal::None,
1277                        });
1278                    }
1279                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1280                    log::info!(
1281                        "peer {} setting active selections: {:?}",
1282                        replica_id,
1283                        selections
1284                    );
1285                    active_selections.insert(replica_id, selections.clone());
1286                    buffer.set_active_selections(selections, false, Default::default(), cx);
1287                });
1288                mutation_count -= 1;
1289            }
1290            40..=49 if mutation_count != 0 && replica_id == 0 => {
1291                let entry_count = rng.gen_range(1..=5);
1292                buffer.update(cx, |buffer, cx| {
1293                    let diagnostics = DiagnosticSet::new(
1294                        (0..entry_count).map(|_| {
1295                            let range = buffer.random_byte_range(0, &mut rng);
1296                            let range = range.to_point_utf16(buffer);
1297                            DiagnosticEntry {
1298                                range,
1299                                diagnostic: Diagnostic {
1300                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1301                                    ..Default::default()
1302                                },
1303                            }
1304                        }),
1305                        buffer,
1306                    );
1307                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1308                    buffer.update_diagnostics(diagnostics, cx);
1309                });
1310                mutation_count -= 1;
1311            }
1312            50..=59 if replica_ids.len() < max_peers => {
1313                let old_buffer_state = buffer.read(cx).to_proto();
1314                let old_buffer_ops = cx.background().block(buffer.read(cx).serialize_ops(cx));
1315                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1316                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1317                    .choose(&mut rng)
1318                    .unwrap();
1319                log::info!(
1320                    "Adding new replica {} (replicating from {})",
1321                    new_replica_id,
1322                    replica_id
1323                );
1324                new_buffer = Some(cx.add_model(|cx| {
1325                    let mut new_buffer =
1326                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1327                    new_buffer
1328                        .apply_ops(
1329                            old_buffer_ops
1330                                .into_iter()
1331                                .map(|op| deserialize_operation(op).unwrap()),
1332                            cx,
1333                        )
1334                        .unwrap();
1335                    log::info!(
1336                        "New replica {} text: {:?}",
1337                        new_buffer.replica_id(),
1338                        new_buffer.text()
1339                    );
1340                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1341                    let network = network.clone();
1342                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1343                        if let Event::Operation(op) = event {
1344                            network.borrow_mut().broadcast(
1345                                buffer.replica_id(),
1346                                vec![proto::serialize_operation(op)],
1347                            );
1348                        }
1349                    })
1350                    .detach();
1351                    new_buffer
1352                }));
1353                network.borrow_mut().replicate(replica_id, new_replica_id);
1354
1355                if new_replica_id as usize == replica_ids.len() {
1356                    replica_ids.push(new_replica_id);
1357                } else {
1358                    let new_buffer = new_buffer.take().unwrap();
1359                    while network.borrow().has_unreceived(new_replica_id) {
1360                        let ops = network
1361                            .borrow_mut()
1362                            .receive(new_replica_id)
1363                            .into_iter()
1364                            .map(|op| proto::deserialize_operation(op).unwrap());
1365                        if ops.len() > 0 {
1366                            log::info!(
1367                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1368                                new_replica_id,
1369                                buffer.read(cx).version(),
1370                                ops.len(),
1371                                ops
1372                            );
1373                            new_buffer.update(cx, |new_buffer, cx| {
1374                                new_buffer.apply_ops(ops, cx).unwrap();
1375                            });
1376                        }
1377                    }
1378                    buffers[new_replica_id as usize] = new_buffer;
1379                }
1380            }
1381            60..=69 if mutation_count != 0 => {
1382                buffer.update(cx, |buffer, cx| {
1383                    buffer.randomly_undo_redo(&mut rng, cx);
1384                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1385                });
1386                mutation_count -= 1;
1387            }
1388            _ if network.borrow().has_unreceived(replica_id) => {
1389                let ops = network
1390                    .borrow_mut()
1391                    .receive(replica_id)
1392                    .into_iter()
1393                    .map(|op| proto::deserialize_operation(op).unwrap());
1394                if ops.len() > 0 {
1395                    log::info!(
1396                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1397                        replica_id,
1398                        buffer.read(cx).version(),
1399                        ops.len(),
1400                        ops
1401                    );
1402                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1403                }
1404            }
1405            _ => {}
1406        }
1407
1408        now += Duration::from_millis(rng.gen_range(0..=200));
1409        buffers.extend(new_buffer);
1410
1411        for buffer in &buffers {
1412            buffer.read(cx).check_invariants();
1413        }
1414
1415        if mutation_count == 0 && network.borrow().is_idle() {
1416            break;
1417        }
1418    }
1419
1420    let first_buffer = buffers[0].read(cx).snapshot();
1421    for buffer in &buffers[1..] {
1422        let buffer = buffer.read(cx).snapshot();
1423        assert_eq!(
1424            buffer.version(),
1425            first_buffer.version(),
1426            "Replica {} version != Replica 0 version",
1427            buffer.replica_id()
1428        );
1429        assert_eq!(
1430            buffer.text(),
1431            first_buffer.text(),
1432            "Replica {} text != Replica 0 text",
1433            buffer.replica_id()
1434        );
1435        assert_eq!(
1436            buffer
1437                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1438                .collect::<Vec<_>>(),
1439            first_buffer
1440                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1441                .collect::<Vec<_>>(),
1442            "Replica {} diagnostics != Replica 0 diagnostics",
1443            buffer.replica_id()
1444        );
1445    }
1446
1447    for buffer in &buffers {
1448        let buffer = buffer.read(cx).snapshot();
1449        let actual_remote_selections = buffer
1450            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1451            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1452            .collect::<Vec<_>>();
1453        let expected_remote_selections = active_selections
1454            .iter()
1455            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1456            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1457            .collect::<Vec<_>>();
1458        assert_eq!(
1459            actual_remote_selections,
1460            expected_remote_selections,
1461            "Replica {} remote selections != expected selections",
1462            buffer.replica_id()
1463        );
1464    }
1465}
1466
1467#[test]
1468fn test_contiguous_ranges() {
1469    assert_eq!(
1470        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1471        &[1..4, 5..7, 9..13]
1472    );
1473
1474    // Respects the `max_len` parameter
1475    assert_eq!(
1476        contiguous_ranges(
1477            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1478            3
1479        )
1480        .collect::<Vec<_>>(),
1481        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1482    );
1483}
1484
1485impl Buffer {
1486    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1487        &self,
1488        range: Range<T>,
1489    ) -> Option<(Range<Point>, Range<Point>)> {
1490        self.snapshot()
1491            .enclosing_bracket_ranges(range)
1492            .map(|(start, end)| {
1493                let point_start = start.start.to_point(self)..start.end.to_point(self);
1494                let point_end = end.start.to_point(self)..end.end.to_point(self);
1495                (point_start, point_end)
1496            })
1497    }
1498}
1499
1500fn rust_lang() -> Language {
1501    Language::new(
1502        LanguageConfig {
1503            name: "Rust".into(),
1504            path_suffixes: vec!["rs".to_string()],
1505            ..Default::default()
1506        },
1507        Some(tree_sitter_rust::language()),
1508    )
1509    .with_indents_query(
1510        r#"
1511        (call_expression) @indent
1512        (field_expression) @indent
1513        (_ "(" ")" @end) @indent
1514        (_ "{" "}" @end) @indent
1515        "#,
1516    )
1517    .unwrap()
1518    .with_brackets_query(
1519        r#"
1520        ("{" @open "}" @close)
1521        "#,
1522    )
1523    .unwrap()
1524    .with_outline_query(
1525        r#"
1526        (struct_item
1527            "struct" @context
1528            name: (_) @name) @item
1529        (enum_item
1530            "enum" @context
1531            name: (_) @name) @item
1532        (enum_variant
1533            name: (_) @name) @item
1534        (field_declaration
1535            name: (_) @name) @item
1536        (impl_item
1537            "impl" @context
1538            trait: (_)? @name
1539            "for"? @context
1540            type: (_) @name) @item
1541        (function_item
1542            "fn" @context
1543            name: (_) @name) @item
1544        (mod_item
1545            "mod" @context
1546            name: (_) @name) @item
1547        "#,
1548    )
1549    .unwrap()
1550}
1551
1552fn json_lang() -> Language {
1553    Language::new(
1554        LanguageConfig {
1555            name: "Json".into(),
1556            path_suffixes: vec!["js".to_string()],
1557            ..Default::default()
1558        },
1559        Some(tree_sitter_json::language()),
1560    )
1561}
1562
1563fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1564    buffer.read_with(cx, |buffer, _| {
1565        let snapshot = buffer.snapshot();
1566        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
1567        layers[0].node.to_sexp()
1568    })
1569}
1570
1571fn empty(point: Point) -> Range<Point> {
1572    point..point
1573}