buffer_tests.rs

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