buffer_tests.rs

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