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