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        buf.undo(cx);
 294        buf.undo(cx);
 295        buf.undo(cx);
 296        assert_eq!(buf.text(), "fn a() {}");
 297        assert!(buf.is_parsing());
 298    });
 299    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 300    assert_eq!(
 301        get_tree_sexp(&buffer, cx),
 302        concat!(
 303            "(source_file (function_item name: (identifier) ",
 304            "parameters: (parameters) ",
 305            "body: (block)))"
 306        )
 307    );
 308
 309    buffer.update(cx, |buf, cx| {
 310        buf.redo(cx);
 311        buf.redo(cx);
 312        buf.redo(cx);
 313        buf.redo(cx);
 314        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 315        assert!(buf.is_parsing());
 316    });
 317    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 318    assert_eq!(
 319        get_tree_sexp(&buffer, cx),
 320        concat!(
 321            "(source_file (function_item name: (identifier) ",
 322            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 323            "body: (block (expression_statement (call_expression ",
 324            "function: (generic_function ",
 325            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 326            "type_arguments: (type_arguments (type_identifier))) ",
 327            "arguments: (arguments (identifier)))))))",
 328        )
 329    );
 330}
 331
 332#[gpui::test]
 333async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 334    let buffer = cx.add_model(|cx| {
 335        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 336        buffer.set_sync_parse_timeout(Duration::ZERO);
 337        buffer
 338    });
 339
 340    // Wait for the initial text to parse
 341    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 342    assert_eq!(
 343        get_tree_sexp(&buffer, cx),
 344        "(source_file (expression_statement (block)))"
 345    );
 346
 347    buffer.update(cx, |buffer, cx| {
 348        buffer.set_language(Some(Arc::new(json_lang())), cx)
 349    });
 350    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 351    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 352}
 353
 354#[gpui::test]
 355async fn test_outline(cx: &mut gpui::TestAppContext) {
 356    let text = r#"
 357        struct Person {
 358            name: String,
 359            age: usize,
 360        }
 361
 362        mod module {
 363            enum LoginState {
 364                LoggedOut,
 365                LoggingOn,
 366                LoggedIn {
 367                    person: Person,
 368                    time: Instant,
 369                }
 370            }
 371        }
 372
 373        impl Eq for Person {}
 374
 375        impl Drop for Person {
 376            fn drop(&mut self) {
 377                println!("bye");
 378            }
 379        }
 380    "#
 381    .unindent();
 382
 383    let buffer =
 384        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 385    let outline = buffer
 386        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 387        .unwrap();
 388
 389    assert_eq!(
 390        outline
 391            .items
 392            .iter()
 393            .map(|item| (item.text.as_str(), item.depth))
 394            .collect::<Vec<_>>(),
 395        &[
 396            ("struct Person", 0),
 397            ("name", 1),
 398            ("age", 1),
 399            ("mod module", 0),
 400            ("enum LoginState", 1),
 401            ("LoggedOut", 2),
 402            ("LoggingOn", 2),
 403            ("LoggedIn", 2),
 404            ("person", 3),
 405            ("time", 3),
 406            ("impl Eq for Person", 0),
 407            ("impl Drop for Person", 0),
 408            ("fn drop", 1),
 409        ]
 410    );
 411
 412    // Without space, we only match on names
 413    assert_eq!(
 414        search(&outline, "oon", cx).await,
 415        &[
 416            ("mod module", vec![]),                    // included as the parent of a match
 417            ("enum LoginState", vec![]),               // included as the parent of a match
 418            ("LoggingOn", vec![1, 7, 8]),              // matches
 419            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 420        ]
 421    );
 422
 423    assert_eq!(
 424        search(&outline, "dp p", cx).await,
 425        &[
 426            ("impl Drop for Person", vec![5, 8, 9, 14]),
 427            ("fn drop", vec![]),
 428        ]
 429    );
 430    assert_eq!(
 431        search(&outline, "dpn", cx).await,
 432        &[("impl Drop for Person", vec![5, 14, 19])]
 433    );
 434    assert_eq!(
 435        search(&outline, "impl ", cx).await,
 436        &[
 437            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 438            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 439            ("fn drop", vec![]),
 440        ]
 441    );
 442
 443    async fn search<'a>(
 444        outline: &'a Outline<Anchor>,
 445        query: &'a str,
 446        cx: &'a gpui::TestAppContext,
 447    ) -> Vec<(&'a str, Vec<usize>)> {
 448        let matches = cx
 449            .read(|cx| outline.search(query, cx.background().clone()))
 450            .await;
 451        matches
 452            .into_iter()
 453            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 454            .collect::<Vec<_>>()
 455    }
 456}
 457
 458#[gpui::test]
 459async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 460    let text = r#"
 461        impl Person {
 462            fn one() {
 463                1
 464            }
 465
 466            fn two() {
 467                2
 468            }fn three() {
 469                3
 470            }
 471        }
 472    "#
 473    .unindent();
 474
 475    let buffer =
 476        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 477    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 478
 479    // point is at the start of an item
 480    assert_eq!(
 481        symbols_containing(Point::new(1, 4), &snapshot),
 482        vec![
 483            (
 484                "impl Person".to_string(),
 485                Point::new(0, 0)..Point::new(10, 1)
 486            ),
 487            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 488        ]
 489    );
 490
 491    // point is in the middle of an item
 492    assert_eq!(
 493        symbols_containing(Point::new(2, 8), &snapshot),
 494        vec![
 495            (
 496                "impl Person".to_string(),
 497                Point::new(0, 0)..Point::new(10, 1)
 498            ),
 499            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 500        ]
 501    );
 502
 503    // point is at the end of an item
 504    assert_eq!(
 505        symbols_containing(Point::new(3, 5), &snapshot),
 506        vec![
 507            (
 508                "impl Person".to_string(),
 509                Point::new(0, 0)..Point::new(10, 1)
 510            ),
 511            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 512        ]
 513    );
 514
 515    // point is in between two adjacent items
 516    assert_eq!(
 517        symbols_containing(Point::new(7, 5), &snapshot),
 518        vec![
 519            (
 520                "impl Person".to_string(),
 521                Point::new(0, 0)..Point::new(10, 1)
 522            ),
 523            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 524        ]
 525    );
 526
 527    fn symbols_containing(
 528        position: Point,
 529        snapshot: &BufferSnapshot,
 530    ) -> Vec<(String, Range<Point>)> {
 531        snapshot
 532            .symbols_containing(position, None)
 533            .unwrap()
 534            .into_iter()
 535            .map(|item| {
 536                (
 537                    item.text,
 538                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 539                )
 540            })
 541            .collect()
 542    }
 543}
 544
 545#[gpui::test]
 546fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 547    cx.set_global(Settings::test(cx));
 548    let buffer = cx.add_model(|cx| {
 549        let text = "
 550            mod x {
 551                mod y {
 552
 553                }
 554            }
 555        "
 556        .unindent();
 557        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
 558    });
 559    let buffer = buffer.read(cx);
 560    assert_eq!(
 561        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
 562        Some((
 563            Point::new(0, 6)..Point::new(0, 7),
 564            Point::new(4, 0)..Point::new(4, 1)
 565        ))
 566    );
 567    assert_eq!(
 568        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
 569        Some((
 570            Point::new(1, 10)..Point::new(1, 11),
 571            Point::new(3, 4)..Point::new(3, 5)
 572        ))
 573    );
 574    assert_eq!(
 575        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
 576        Some((
 577            Point::new(1, 10)..Point::new(1, 11),
 578            Point::new(3, 4)..Point::new(3, 5)
 579        ))
 580    );
 581
 582    assert_eq!(
 583        buffer.enclosing_bracket_point_ranges(Point::new(4, 1)..Point::new(4, 1)),
 584        Some((
 585            Point::new(0, 6)..Point::new(0, 7),
 586            Point::new(4, 0)..Point::new(4, 1)
 587        ))
 588    );
 589
 590    // Regression test: avoid crash when querying at the end of the buffer.
 591    assert_eq!(
 592        buffer.enclosing_bracket_point_ranges(Point::new(4, 1)..Point::new(5, 0)),
 593        None
 594    );
 595}
 596
 597#[gpui::test]
 598fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(
 599    cx: &mut MutableAppContext,
 600) {
 601    let javascript_language = Arc::new(
 602        Language::new(
 603            LanguageConfig {
 604                name: "JavaScript".into(),
 605                ..Default::default()
 606            },
 607            Some(tree_sitter_javascript::language()),
 608        )
 609        .with_brackets_query(
 610            r#"
 611            ("{" @open "}" @close)
 612            ("(" @open ")" @close)
 613            "#,
 614        )
 615        .unwrap(),
 616    );
 617
 618    cx.set_global(Settings::test(cx));
 619    let buffer = cx.add_model(|cx| {
 620        let text = "
 621            for (const a in b) {
 622                // a comment that's longer than the for-loop header
 623            }
 624        "
 625        .unindent();
 626        Buffer::new(0, text, cx).with_language(javascript_language, cx)
 627    });
 628
 629    let buffer = buffer.read(cx);
 630    assert_eq!(
 631        buffer.enclosing_bracket_point_ranges(Point::new(0, 18)..Point::new(0, 18)),
 632        Some((
 633            Point::new(0, 4)..Point::new(0, 5),
 634            Point::new(0, 17)..Point::new(0, 18)
 635        ))
 636    );
 637
 638    // Regression test: even though the parent node of the parentheses (the for loop) does
 639    // intersect the given range, the parentheses themselves do not contain the range, so
 640    // they should not be returned. Only the curly braces contain the range.
 641    assert_eq!(
 642        buffer.enclosing_bracket_point_ranges(Point::new(0, 20)..Point::new(0, 20)),
 643        Some((
 644            Point::new(0, 19)..Point::new(0, 20),
 645            Point::new(2, 0)..Point::new(2, 1)
 646        ))
 647    );
 648}
 649
 650#[gpui::test]
 651fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 652    cx.add_model(|cx| {
 653        let text = "fn a() { b(|c| {}) }";
 654        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 655        let snapshot = buffer.snapshot();
 656
 657        assert_eq!(
 658            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 659            Some(range_of(text, "|"))
 660        );
 661        assert_eq!(
 662            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 663            Some(range_of(text, "|c|"))
 664        );
 665        assert_eq!(
 666            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 667            Some(range_of(text, "|c| {}"))
 668        );
 669        assert_eq!(
 670            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 671            Some(range_of(text, "(|c| {})"))
 672        );
 673
 674        buffer
 675    });
 676
 677    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 678        let start = text.find(part).unwrap();
 679        start..start
 680    }
 681
 682    fn range_of(text: &str, part: &str) -> Range<usize> {
 683        let start = text.find(part).unwrap();
 684        start..start + part.len()
 685    }
 686}
 687
 688#[gpui::test]
 689fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 690    let settings = Settings::test(cx);
 691    cx.set_global(settings);
 692
 693    cx.add_model(|cx| {
 694        let text = "fn a() {}";
 695        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 696
 697        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 698        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 699
 700        buffer.edit(
 701            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 702            Some(AutoindentMode::EachLine),
 703            cx,
 704        );
 705        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 706
 707        // Create a field expression on a new line, causing that line
 708        // to be indented.
 709        buffer.edit(
 710            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 711            Some(AutoindentMode::EachLine),
 712            cx,
 713        );
 714        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 715
 716        // Remove the dot so that the line is no longer a field expression,
 717        // causing the line to be outdented.
 718        buffer.edit(
 719            [(Point::new(2, 8)..Point::new(2, 9), "")],
 720            Some(AutoindentMode::EachLine),
 721            cx,
 722        );
 723        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 724
 725        buffer
 726    });
 727}
 728
 729#[gpui::test]
 730fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 731    let mut settings = Settings::test(cx);
 732    settings.editor_overrides.hard_tabs = Some(true);
 733    cx.set_global(settings);
 734
 735    cx.add_model(|cx| {
 736        let text = "fn a() {}";
 737        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 738
 739        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 740        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 741
 742        buffer.edit(
 743            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 744            Some(AutoindentMode::EachLine),
 745            cx,
 746        );
 747        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 748
 749        // Create a field expression on a new line, causing that line
 750        // to be indented.
 751        buffer.edit(
 752            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 753            Some(AutoindentMode::EachLine),
 754            cx,
 755        );
 756        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 757
 758        // Remove the dot so that the line is no longer a field expression,
 759        // causing the line to be outdented.
 760        buffer.edit(
 761            [(Point::new(2, 2)..Point::new(2, 3), "")],
 762            Some(AutoindentMode::EachLine),
 763            cx,
 764        );
 765        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 766
 767        buffer
 768    });
 769}
 770
 771#[gpui::test]
 772fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 773    let settings = Settings::test(cx);
 774    cx.set_global(settings);
 775
 776    cx.add_model(|cx| {
 777        let text = "
 778            fn a() {
 779            c;
 780            d;
 781            }
 782        "
 783        .unindent();
 784
 785        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 786
 787        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 788        // their indentation is not adjusted.
 789        buffer.edit(
 790            [
 791                (empty(Point::new(1, 1)), "()"),
 792                (empty(Point::new(2, 1)), "()"),
 793            ],
 794            Some(AutoindentMode::EachLine),
 795            cx,
 796        );
 797        assert_eq!(
 798            buffer.text(),
 799            "
 800            fn a() {
 801            c();
 802            d();
 803            }
 804            "
 805            .unindent()
 806        );
 807
 808        // When appending new content after these lines, the indentation is based on the
 809        // preceding lines' actual indentation.
 810        buffer.edit(
 811            [
 812                (empty(Point::new(1, 1)), "\n.f\n.g"),
 813                (empty(Point::new(2, 1)), "\n.f\n.g"),
 814            ],
 815            Some(AutoindentMode::EachLine),
 816            cx,
 817        );
 818        assert_eq!(
 819            buffer.text(),
 820            "
 821            fn a() {
 822            c
 823                .f
 824                .g();
 825            d
 826                .f
 827                .g();
 828            }
 829            "
 830            .unindent()
 831        );
 832        buffer
 833    });
 834
 835    cx.add_model(|cx| {
 836        let text = "
 837            fn a() {
 838                {
 839                    b()?
 840                }
 841                Ok(())
 842            }
 843        "
 844        .unindent();
 845        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 846
 847        // Delete a closing curly brace changes the suggested indent for the line.
 848        buffer.edit(
 849            [(Point::new(3, 4)..Point::new(3, 5), "")],
 850            Some(AutoindentMode::EachLine),
 851            cx,
 852        );
 853        assert_eq!(
 854            buffer.text(),
 855            "
 856            fn a() {
 857                {
 858                    b()?
 859                        |
 860                Ok(())
 861            }
 862            "
 863            .replace('|', "") // included in the string to preserve trailing whites
 864            .unindent()
 865        );
 866
 867        // Manually editing the leading whitespace
 868        buffer.edit(
 869            [(Point::new(3, 0)..Point::new(3, 12), "")],
 870            Some(AutoindentMode::EachLine),
 871            cx,
 872        );
 873        assert_eq!(
 874            buffer.text(),
 875            "
 876            fn a() {
 877                {
 878                    b()?
 879
 880                Ok(())
 881            }
 882            "
 883            .unindent()
 884        );
 885        buffer
 886    });
 887}
 888
 889#[gpui::test]
 890fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 891    cx.set_global(Settings::test(cx));
 892    cx.add_model(|cx| {
 893        let text = "
 894            fn a() {}
 895        "
 896        .unindent();
 897
 898        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 899
 900        buffer.edit([(5..5, "\nb")], Some(AutoindentMode::EachLine), cx);
 901        assert_eq!(
 902            buffer.text(),
 903            "
 904                fn a(
 905                    b) {}
 906            "
 907            .unindent()
 908        );
 909
 910        // The indentation suggestion changed because `@end` node (a close paren)
 911        // is now at the beginning of the line.
 912        buffer.edit(
 913            [(Point::new(1, 4)..Point::new(1, 5), "")],
 914            Some(AutoindentMode::EachLine),
 915            cx,
 916        );
 917        assert_eq!(
 918            buffer.text(),
 919            "
 920                fn a(
 921                ) {}
 922            "
 923            .unindent()
 924        );
 925
 926        buffer
 927    });
 928}
 929
 930#[gpui::test]
 931fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 932    cx.set_global(Settings::test(cx));
 933    cx.add_model(|cx| {
 934        let text = "a\nb";
 935        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 936        buffer.edit(
 937            [(0..1, "\n"), (2..3, "\n")],
 938            Some(AutoindentMode::EachLine),
 939            cx,
 940        );
 941        assert_eq!(buffer.text(), "\n\n\n");
 942        buffer
 943    });
 944}
 945
 946#[gpui::test]
 947fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 948    cx.set_global(Settings::test(cx));
 949    cx.add_model(|cx| {
 950        let text = "
 951            const a: usize = 1;
 952            fn b() {
 953                if c {
 954                    let d = 2;
 955                }
 956            }
 957        "
 958        .unindent();
 959
 960        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 961        buffer.edit(
 962            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
 963            Some(AutoindentMode::EachLine),
 964            cx,
 965        );
 966        assert_eq!(
 967            buffer.text(),
 968            "
 969                const a: usize = 1;
 970                fn b() {
 971                    if c {
 972                        e(
 973                            f()
 974                        );
 975                        let d = 2;
 976                    }
 977                }
 978            "
 979            .unindent()
 980        );
 981
 982        buffer
 983    });
 984}
 985
 986#[gpui::test]
 987fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
 988    cx.set_global(Settings::test(cx));
 989    cx.add_model(|cx| {
 990        let text = r#"
 991            fn a() {
 992                b();
 993            }
 994        "#
 995        .unindent();
 996        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 997
 998        let inserted_text = r#"
 999            "
1000              c
1001                d
1002                  e
1003            "
1004        "#
1005        .unindent();
1006
1007        // Insert the block at column zero. The entire block is indented
1008        // so that the first line matches the previous line's indentation.
1009        buffer.edit(
1010            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1011            Some(AutoindentMode::Block {
1012                original_indent_columns: vec![0],
1013            }),
1014            cx,
1015        );
1016        assert_eq!(
1017            buffer.text(),
1018            r#"
1019            fn a() {
1020                b();
1021                "
1022                  c
1023                    d
1024                      e
1025                "
1026            }
1027            "#
1028            .unindent()
1029        );
1030
1031        // Grouping is disabled in tests, so we need 2 undos
1032        buffer.undo(cx); // Undo the auto-indent
1033        buffer.undo(cx); // Undo the original edit
1034
1035        // Insert the block at a deeper indent level. The entire block is outdented.
1036        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1037        buffer.edit(
1038            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1039            Some(AutoindentMode::Block {
1040                original_indent_columns: vec![0],
1041            }),
1042            cx,
1043        );
1044        assert_eq!(
1045            buffer.text(),
1046            r#"
1047            fn a() {
1048                b();
1049                "
1050                  c
1051                    d
1052                      e
1053                "
1054            }
1055            "#
1056            .unindent()
1057        );
1058
1059        buffer
1060    });
1061}
1062
1063#[gpui::test]
1064fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
1065    cx.set_global(Settings::test(cx));
1066    cx.add_model(|cx| {
1067        let text = "
1068            * one
1069                - a
1070                - b
1071            * two
1072        "
1073        .unindent();
1074
1075        let mut buffer = Buffer::new(0, text, cx).with_language(
1076            Arc::new(Language::new(
1077                LanguageConfig {
1078                    name: "Markdown".into(),
1079                    auto_indent_using_last_non_empty_line: false,
1080                    ..Default::default()
1081                },
1082                Some(tree_sitter_json::language()),
1083            )),
1084            cx,
1085        );
1086        buffer.edit(
1087            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1088            Some(AutoindentMode::EachLine),
1089            cx,
1090        );
1091        assert_eq!(
1092            buffer.text(),
1093            "
1094            * one
1095                - a
1096                - b
1097
1098            * two
1099            "
1100            .unindent()
1101        );
1102        buffer
1103    });
1104}
1105
1106#[gpui::test]
1107fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
1108    cx.set_global({
1109        let mut settings = Settings::test(cx);
1110        settings.language_overrides.extend([
1111            (
1112                "HTML".into(),
1113                settings::EditorSettings {
1114                    tab_size: Some(2.try_into().unwrap()),
1115                    ..Default::default()
1116                },
1117            ),
1118            (
1119                "JavaScript".into(),
1120                settings::EditorSettings {
1121                    tab_size: Some(8.try_into().unwrap()),
1122                    ..Default::default()
1123                },
1124            ),
1125        ]);
1126        settings
1127    });
1128
1129    let html_language = Arc::new(
1130        Language::new(
1131            LanguageConfig {
1132                name: "HTML".into(),
1133                ..Default::default()
1134            },
1135            Some(tree_sitter_html::language()),
1136        )
1137        .with_indents_query(
1138            "
1139            (element
1140              (start_tag) @start
1141              (end_tag)? @end) @indent
1142            ",
1143        )
1144        .unwrap()
1145        .with_injection_query(
1146            r#"
1147            (script_element
1148                (raw_text) @content
1149                (#set! "language" "javascript"))
1150            "#,
1151        )
1152        .unwrap(),
1153    );
1154
1155    let javascript_language = Arc::new(
1156        Language::new(
1157            LanguageConfig {
1158                name: "JavaScript".into(),
1159                ..Default::default()
1160            },
1161            Some(tree_sitter_javascript::language()),
1162        )
1163        .with_indents_query(
1164            r#"
1165            (object "}" @end) @indent
1166            "#,
1167        )
1168        .unwrap(),
1169    );
1170
1171    let language_registry = Arc::new(LanguageRegistry::test());
1172    language_registry.add(html_language.clone());
1173    language_registry.add(javascript_language.clone());
1174
1175    cx.add_model(|cx| {
1176        let (text, ranges) = marked_text_ranges(
1177            &"
1178                <div>ˇ
1179                </div>
1180                <script>
1181                    init({ˇ
1182                    })
1183                </script>
1184                <span>ˇ
1185                </span>
1186            "
1187            .unindent(),
1188            false,
1189        );
1190
1191        let mut buffer = Buffer::new(0, text, cx);
1192        buffer.set_language_registry(language_registry);
1193        buffer.set_language(Some(html_language), cx);
1194        buffer.edit(
1195            ranges.into_iter().map(|range| (range, "\na")),
1196            Some(AutoindentMode::EachLine),
1197            cx,
1198        );
1199        assert_eq!(
1200            buffer.text(),
1201            "
1202                <div>
1203                  a
1204                </div>
1205                <script>
1206                    init({
1207                            a
1208                    })
1209                </script>
1210                <span>
1211                  a
1212                </span>
1213            "
1214            .unindent()
1215        );
1216        buffer
1217    });
1218}
1219
1220#[gpui::test]
1221fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
1222    let mut settings = Settings::test(cx);
1223    settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
1224    cx.set_global(settings);
1225    cx.add_model(|cx| {
1226        let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(ruby_lang()), cx);
1227
1228        let text = r#"
1229            class C
1230            def a(b, c)
1231            puts b
1232            puts c
1233            rescue
1234            puts "errored"
1235            exit 1
1236            end
1237            end
1238        "#
1239        .unindent();
1240
1241        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1242
1243        assert_eq!(
1244            buffer.text(),
1245            r#"
1246                class C
1247                  def a(b, c)
1248                    puts b
1249                    puts c
1250                  rescue
1251                    puts "errored"
1252                    exit 1
1253                  end
1254                end
1255            "#
1256            .unindent()
1257        );
1258
1259        buffer
1260    });
1261}
1262
1263#[gpui::test]
1264fn test_serialization(cx: &mut gpui::MutableAppContext) {
1265    let mut now = Instant::now();
1266
1267    let buffer1 = cx.add_model(|cx| {
1268        let mut buffer = Buffer::new(0, "abc", cx);
1269        buffer.edit([(3..3, "D")], None, cx);
1270
1271        now += Duration::from_secs(1);
1272        buffer.start_transaction_at(now);
1273        buffer.edit([(4..4, "E")], None, cx);
1274        buffer.end_transaction_at(now, cx);
1275        assert_eq!(buffer.text(), "abcDE");
1276
1277        buffer.undo(cx);
1278        assert_eq!(buffer.text(), "abcD");
1279
1280        buffer.edit([(4..4, "F")], None, cx);
1281        assert_eq!(buffer.text(), "abcDF");
1282        buffer
1283    });
1284    assert_eq!(buffer1.read(cx).text(), "abcDF");
1285
1286    let state = buffer1.read(cx).to_proto();
1287    let ops = cx
1288        .background()
1289        .block(buffer1.read(cx).serialize_ops(None, cx));
1290    let buffer2 = cx.add_model(|cx| {
1291        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1292        buffer
1293            .apply_ops(
1294                ops.into_iter()
1295                    .map(|op| proto::deserialize_operation(op).unwrap()),
1296                cx,
1297            )
1298            .unwrap();
1299        buffer
1300    });
1301    assert_eq!(buffer2.read(cx).text(), "abcDF");
1302}
1303
1304#[gpui::test(iterations = 100)]
1305fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1306    let min_peers = env::var("MIN_PEERS")
1307        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1308        .unwrap_or(1);
1309    let max_peers = env::var("MAX_PEERS")
1310        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1311        .unwrap_or(5);
1312    let operations = env::var("OPERATIONS")
1313        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1314        .unwrap_or(10);
1315
1316    let base_text_len = rng.gen_range(0..10);
1317    let base_text = RandomCharIter::new(&mut rng)
1318        .take(base_text_len)
1319        .collect::<String>();
1320    let mut replica_ids = Vec::new();
1321    let mut buffers = Vec::new();
1322    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1323    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1324
1325    for i in 0..rng.gen_range(min_peers..=max_peers) {
1326        let buffer = cx.add_model(|cx| {
1327            let state = base_buffer.read(cx).to_proto();
1328            let ops = cx
1329                .background()
1330                .block(base_buffer.read(cx).serialize_ops(None, cx));
1331            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1332            buffer
1333                .apply_ops(
1334                    ops.into_iter()
1335                        .map(|op| proto::deserialize_operation(op).unwrap()),
1336                    cx,
1337                )
1338                .unwrap();
1339            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1340            let network = network.clone();
1341            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1342                if let Event::Operation(op) = event {
1343                    network
1344                        .borrow_mut()
1345                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1346                }
1347            })
1348            .detach();
1349            buffer
1350        });
1351        buffers.push(buffer);
1352        replica_ids.push(i as ReplicaId);
1353        network.borrow_mut().add_peer(i as ReplicaId);
1354        log::info!("Adding initial peer with replica id {}", i);
1355    }
1356
1357    log::info!("initial text: {:?}", base_text);
1358
1359    let mut now = Instant::now();
1360    let mut mutation_count = operations;
1361    let mut next_diagnostic_id = 0;
1362    let mut active_selections = BTreeMap::default();
1363    loop {
1364        let replica_index = rng.gen_range(0..replica_ids.len());
1365        let replica_id = replica_ids[replica_index];
1366        let buffer = &mut buffers[replica_index];
1367        let mut new_buffer = None;
1368        match rng.gen_range(0..100) {
1369            0..=29 if mutation_count != 0 => {
1370                buffer.update(cx, |buffer, cx| {
1371                    buffer.start_transaction_at(now);
1372                    buffer.randomly_edit(&mut rng, 5, cx);
1373                    buffer.end_transaction_at(now, cx);
1374                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1375                });
1376                mutation_count -= 1;
1377            }
1378            30..=39 if mutation_count != 0 => {
1379                buffer.update(cx, |buffer, cx| {
1380                    let mut selections = Vec::new();
1381                    for id in 0..rng.gen_range(1..=5) {
1382                        let range = buffer.random_byte_range(0, &mut rng);
1383                        selections.push(Selection {
1384                            id,
1385                            start: buffer.anchor_before(range.start),
1386                            end: buffer.anchor_before(range.end),
1387                            reversed: false,
1388                            goal: SelectionGoal::None,
1389                        });
1390                    }
1391                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1392                    log::info!(
1393                        "peer {} setting active selections: {:?}",
1394                        replica_id,
1395                        selections
1396                    );
1397                    active_selections.insert(replica_id, selections.clone());
1398                    buffer.set_active_selections(selections, false, Default::default(), cx);
1399                });
1400                mutation_count -= 1;
1401            }
1402            40..=49 if mutation_count != 0 && replica_id == 0 => {
1403                let entry_count = rng.gen_range(1..=5);
1404                buffer.update(cx, |buffer, cx| {
1405                    let diagnostics = DiagnosticSet::new(
1406                        (0..entry_count).map(|_| {
1407                            let range = buffer.random_byte_range(0, &mut rng);
1408                            let range = range.to_point_utf16(buffer);
1409                            let range = range.start..range.end;
1410                            DiagnosticEntry {
1411                                range,
1412                                diagnostic: Diagnostic {
1413                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1414                                    ..Default::default()
1415                                },
1416                            }
1417                        }),
1418                        buffer,
1419                    );
1420                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1421                    buffer.update_diagnostics(diagnostics, cx);
1422                });
1423                mutation_count -= 1;
1424            }
1425            50..=59 if replica_ids.len() < max_peers => {
1426                let old_buffer_state = buffer.read(cx).to_proto();
1427                let old_buffer_ops = cx
1428                    .background()
1429                    .block(buffer.read(cx).serialize_ops(None, cx));
1430                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1431                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1432                    .choose(&mut rng)
1433                    .unwrap();
1434                log::info!(
1435                    "Adding new replica {} (replicating from {})",
1436                    new_replica_id,
1437                    replica_id
1438                );
1439                new_buffer = Some(cx.add_model(|cx| {
1440                    let mut new_buffer =
1441                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1442                    new_buffer
1443                        .apply_ops(
1444                            old_buffer_ops
1445                                .into_iter()
1446                                .map(|op| deserialize_operation(op).unwrap()),
1447                            cx,
1448                        )
1449                        .unwrap();
1450                    log::info!(
1451                        "New replica {} text: {:?}",
1452                        new_buffer.replica_id(),
1453                        new_buffer.text()
1454                    );
1455                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1456                    let network = network.clone();
1457                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1458                        if let Event::Operation(op) = event {
1459                            network.borrow_mut().broadcast(
1460                                buffer.replica_id(),
1461                                vec![proto::serialize_operation(op)],
1462                            );
1463                        }
1464                    })
1465                    .detach();
1466                    new_buffer
1467                }));
1468                network.borrow_mut().replicate(replica_id, new_replica_id);
1469
1470                if new_replica_id as usize == replica_ids.len() {
1471                    replica_ids.push(new_replica_id);
1472                } else {
1473                    let new_buffer = new_buffer.take().unwrap();
1474                    while network.borrow().has_unreceived(new_replica_id) {
1475                        let ops = network
1476                            .borrow_mut()
1477                            .receive(new_replica_id)
1478                            .into_iter()
1479                            .map(|op| proto::deserialize_operation(op).unwrap());
1480                        if ops.len() > 0 {
1481                            log::info!(
1482                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1483                                new_replica_id,
1484                                buffer.read(cx).version(),
1485                                ops.len(),
1486                                ops
1487                            );
1488                            new_buffer.update(cx, |new_buffer, cx| {
1489                                new_buffer.apply_ops(ops, cx).unwrap();
1490                            });
1491                        }
1492                    }
1493                    buffers[new_replica_id as usize] = new_buffer;
1494                }
1495            }
1496            60..=69 if mutation_count != 0 => {
1497                buffer.update(cx, |buffer, cx| {
1498                    buffer.randomly_undo_redo(&mut rng, cx);
1499                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1500                });
1501                mutation_count -= 1;
1502            }
1503            _ if network.borrow().has_unreceived(replica_id) => {
1504                let ops = network
1505                    .borrow_mut()
1506                    .receive(replica_id)
1507                    .into_iter()
1508                    .map(|op| proto::deserialize_operation(op).unwrap());
1509                if ops.len() > 0 {
1510                    log::info!(
1511                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1512                        replica_id,
1513                        buffer.read(cx).version(),
1514                        ops.len(),
1515                        ops
1516                    );
1517                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1518                }
1519            }
1520            _ => {}
1521        }
1522
1523        now += Duration::from_millis(rng.gen_range(0..=200));
1524        buffers.extend(new_buffer);
1525
1526        for buffer in &buffers {
1527            buffer.read(cx).check_invariants();
1528        }
1529
1530        if mutation_count == 0 && network.borrow().is_idle() {
1531            break;
1532        }
1533    }
1534
1535    let first_buffer = buffers[0].read(cx).snapshot();
1536    for buffer in &buffers[1..] {
1537        let buffer = buffer.read(cx).snapshot();
1538        assert_eq!(
1539            buffer.version(),
1540            first_buffer.version(),
1541            "Replica {} version != Replica 0 version",
1542            buffer.replica_id()
1543        );
1544        assert_eq!(
1545            buffer.text(),
1546            first_buffer.text(),
1547            "Replica {} text != Replica 0 text",
1548            buffer.replica_id()
1549        );
1550        assert_eq!(
1551            buffer
1552                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1553                .collect::<Vec<_>>(),
1554            first_buffer
1555                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1556                .collect::<Vec<_>>(),
1557            "Replica {} diagnostics != Replica 0 diagnostics",
1558            buffer.replica_id()
1559        );
1560    }
1561
1562    for buffer in &buffers {
1563        let buffer = buffer.read(cx).snapshot();
1564        let actual_remote_selections = buffer
1565            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1566            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1567            .collect::<Vec<_>>();
1568        let expected_remote_selections = active_selections
1569            .iter()
1570            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1571            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1572            .collect::<Vec<_>>();
1573        assert_eq!(
1574            actual_remote_selections,
1575            expected_remote_selections,
1576            "Replica {} remote selections != expected selections",
1577            buffer.replica_id()
1578        );
1579    }
1580}
1581
1582#[test]
1583fn test_contiguous_ranges() {
1584    assert_eq!(
1585        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1586        &[1..4, 5..7, 9..13]
1587    );
1588
1589    // Respects the `max_len` parameter
1590    assert_eq!(
1591        contiguous_ranges(
1592            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1593            3
1594        )
1595        .collect::<Vec<_>>(),
1596        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1597    );
1598}
1599
1600impl Buffer {
1601    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1602        &self,
1603        range: Range<T>,
1604    ) -> Option<(Range<Point>, Range<Point>)> {
1605        self.snapshot()
1606            .enclosing_bracket_ranges(range)
1607            .map(|(start, end)| {
1608                let point_start = start.start.to_point(self)..start.end.to_point(self);
1609                let point_end = end.start.to_point(self)..end.end.to_point(self);
1610                (point_start, point_end)
1611            })
1612    }
1613}
1614
1615fn ruby_lang() -> Language {
1616    Language::new(
1617        LanguageConfig {
1618            name: "Ruby".into(),
1619            path_suffixes: vec!["rb".to_string()],
1620            ..Default::default()
1621        },
1622        Some(tree_sitter_ruby::language()),
1623    )
1624    .with_indents_query(
1625        r#"
1626            (class "end" @end) @indent
1627            (method "end" @end) @indent
1628            (rescue) @outdent
1629            (then) @indent
1630        "#,
1631    )
1632    .unwrap()
1633}
1634
1635fn rust_lang() -> Language {
1636    Language::new(
1637        LanguageConfig {
1638            name: "Rust".into(),
1639            path_suffixes: vec!["rs".to_string()],
1640            ..Default::default()
1641        },
1642        Some(tree_sitter_rust::language()),
1643    )
1644    .with_indents_query(
1645        r#"
1646        (call_expression) @indent
1647        (field_expression) @indent
1648        (_ "(" ")" @end) @indent
1649        (_ "{" "}" @end) @indent
1650        "#,
1651    )
1652    .unwrap()
1653    .with_brackets_query(
1654        r#"
1655        ("{" @open "}" @close)
1656        "#,
1657    )
1658    .unwrap()
1659    .with_outline_query(
1660        r#"
1661        (struct_item
1662            "struct" @context
1663            name: (_) @name) @item
1664        (enum_item
1665            "enum" @context
1666            name: (_) @name) @item
1667        (enum_variant
1668            name: (_) @name) @item
1669        (field_declaration
1670            name: (_) @name) @item
1671        (impl_item
1672            "impl" @context
1673            trait: (_)? @name
1674            "for"? @context
1675            type: (_) @name) @item
1676        (function_item
1677            "fn" @context
1678            name: (_) @name) @item
1679        (mod_item
1680            "mod" @context
1681            name: (_) @name) @item
1682        "#,
1683    )
1684    .unwrap()
1685}
1686
1687fn json_lang() -> Language {
1688    Language::new(
1689        LanguageConfig {
1690            name: "Json".into(),
1691            path_suffixes: vec!["js".to_string()],
1692            ..Default::default()
1693        },
1694        Some(tree_sitter_json::language()),
1695    )
1696}
1697
1698fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1699    buffer.read_with(cx, |buffer, _| {
1700        let snapshot = buffer.snapshot();
1701        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
1702        layers[0].node.to_sexp()
1703    })
1704}
1705
1706fn empty(point: Point) -> Range<Point> {
1707    point..point
1708}