buffer_tests.rs

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