buffer_tests.rs

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