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 mut buffer = Buffer::new(
 804            0,
 805            "
 806            fn a() {
 807            c;
 808            d;
 809            }
 810            "
 811            .unindent(),
 812            cx,
 813        )
 814        .with_language(Arc::new(rust_lang()), cx);
 815
 816        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 817        // their indentation is not adjusted.
 818        buffer.edit_via_marked_text(
 819            &"
 820            fn a() {
 821            c«()»;
 822            d«()»;
 823            }
 824            "
 825            .unindent(),
 826            Some(AutoindentMode::EachLine),
 827            cx,
 828        );
 829        assert_eq!(
 830            buffer.text(),
 831            "
 832            fn a() {
 833            c();
 834            d();
 835            }
 836            "
 837            .unindent()
 838        );
 839
 840        // When appending new content after these lines, the indentation is based on the
 841        // preceding lines' actual indentation.
 842        buffer.edit_via_marked_text(
 843            &"
 844            fn a() {
 845 846            .f
 847            .g()»;
 848 849            .f
 850            .g()»;
 851            }
 852            "
 853            .unindent(),
 854            Some(AutoindentMode::EachLine),
 855            cx,
 856        );
 857
 858        assert_eq!(
 859            buffer.text(),
 860            "
 861            fn a() {
 862            c
 863                .f
 864                .g();
 865            d
 866                .f
 867                .g();
 868            }
 869            "
 870            .unindent()
 871        );
 872        buffer
 873    });
 874
 875    cx.add_model(|cx| {
 876        let mut buffer = Buffer::new(
 877            0,
 878            "
 879            fn a() {
 880                b();
 881                |
 882            "
 883            .replace("|", "") // marker to preserve trailing whitespace
 884            .unindent(),
 885            cx,
 886        )
 887        .with_language(Arc::new(rust_lang()), cx);
 888
 889        // Insert a closing brace. It is outdented.
 890        buffer.edit_via_marked_text(
 891            &"
 892            fn a() {
 893                b();
 894                «}»
 895            "
 896            .unindent(),
 897            Some(AutoindentMode::EachLine),
 898            cx,
 899        );
 900        assert_eq!(
 901            buffer.text(),
 902            "
 903            fn a() {
 904                b();
 905            }
 906            "
 907            .unindent()
 908        );
 909
 910        // Manually edit the leading whitespace. The edit is preserved.
 911        buffer.edit_via_marked_text(
 912            &"
 913            fn a() {
 914                b();
 915            «    »}
 916            "
 917            .unindent(),
 918            Some(AutoindentMode::EachLine),
 919            cx,
 920        );
 921        assert_eq!(
 922            buffer.text(),
 923            "
 924            fn a() {
 925                b();
 926                }
 927            "
 928            .unindent()
 929        );
 930        buffer
 931    });
 932}
 933
 934#[gpui::test]
 935fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut MutableAppContext) {
 936    let settings = Settings::test(cx);
 937    cx.set_global(settings);
 938
 939    cx.add_model(|cx| {
 940        let mut buffer = Buffer::new(
 941            0,
 942            "
 943            fn a() {
 944                i
 945            }
 946            "
 947            .unindent(),
 948            cx,
 949        )
 950        .with_language(Arc::new(rust_lang()), cx);
 951
 952        // Regression test: line does not get outdented due to syntax error
 953        buffer.edit_via_marked_text(
 954            &"
 955            fn a() {
 956                i«f let Some(x) = y»
 957            }
 958            "
 959            .unindent(),
 960            Some(AutoindentMode::EachLine),
 961            cx,
 962        );
 963        assert_eq!(
 964            buffer.text(),
 965            "
 966            fn a() {
 967                if let Some(x) = y
 968            }
 969            "
 970            .unindent()
 971        );
 972
 973        buffer.edit_via_marked_text(
 974            &"
 975            fn a() {
 976                if let Some(x) = y« {»
 977            }
 978            "
 979            .unindent(),
 980            Some(AutoindentMode::EachLine),
 981            cx,
 982        );
 983        assert_eq!(
 984            buffer.text(),
 985            "
 986            fn a() {
 987                if let Some(x) = y {
 988            }
 989            "
 990            .unindent()
 991        );
 992
 993        buffer
 994    });
 995}
 996
 997#[gpui::test]
 998fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 999    cx.set_global(Settings::test(cx));
1000    cx.add_model(|cx| {
1001        let mut buffer = Buffer::new(
1002            0,
1003            "
1004            fn a() {}
1005            "
1006            .unindent(),
1007            cx,
1008        )
1009        .with_language(Arc::new(rust_lang()), cx);
1010
1011        buffer.edit_via_marked_text(
1012            &"
1013            fn a(«
1014            b») {}
1015            "
1016            .unindent(),
1017            Some(AutoindentMode::EachLine),
1018            cx,
1019        );
1020        assert_eq!(
1021            buffer.text(),
1022            "
1023            fn a(
1024                b) {}
1025            "
1026            .unindent()
1027        );
1028
1029        // The indentation suggestion changed because `@end` node (a close paren)
1030        // is now at the beginning of the line.
1031        buffer.edit_via_marked_text(
1032            &"
1033            fn a(
1034                ˇ) {}
1035            "
1036            .unindent(),
1037            Some(AutoindentMode::EachLine),
1038            cx,
1039        );
1040        assert_eq!(
1041            buffer.text(),
1042            "
1043                fn a(
1044                ) {}
1045            "
1046            .unindent()
1047        );
1048
1049        buffer
1050    });
1051}
1052
1053#[gpui::test]
1054fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
1055    cx.set_global(Settings::test(cx));
1056    cx.add_model(|cx| {
1057        let text = "a\nb";
1058        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1059        buffer.edit(
1060            [(0..1, "\n"), (2..3, "\n")],
1061            Some(AutoindentMode::EachLine),
1062            cx,
1063        );
1064        assert_eq!(buffer.text(), "\n\n\n");
1065        buffer
1066    });
1067}
1068
1069#[gpui::test]
1070fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
1071    cx.set_global(Settings::test(cx));
1072    cx.add_model(|cx| {
1073        let text = "
1074            const a: usize = 1;
1075            fn b() {
1076                if c {
1077                    let d = 2;
1078                }
1079            }
1080        "
1081        .unindent();
1082
1083        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1084        buffer.edit(
1085            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1086            Some(AutoindentMode::EachLine),
1087            cx,
1088        );
1089        assert_eq!(
1090            buffer.text(),
1091            "
1092                const a: usize = 1;
1093                fn b() {
1094                    if c {
1095                        e(
1096                            f()
1097                        );
1098                        let d = 2;
1099                    }
1100                }
1101            "
1102            .unindent()
1103        );
1104
1105        buffer
1106    });
1107}
1108
1109#[gpui::test]
1110fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
1111    cx.set_global(Settings::test(cx));
1112    cx.add_model(|cx| {
1113        let text = r#"
1114            fn a() {
1115                b();
1116            }
1117        "#
1118        .unindent();
1119        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1120
1121        // When this text was copied, both of the quotation marks were at the same
1122        // indent level, but the indentation of the first line was not included in
1123        // the copied text. This information is retained in the
1124        // 'original_indent_columns' vector.
1125        let original_indent_columns = vec![4];
1126        let inserted_text = r#"
1127            "
1128                  c
1129                    d
1130                      e
1131                "
1132        "#
1133        .unindent();
1134
1135        // Insert the block at column zero. The entire block is indented
1136        // so that the first line matches the previous line's indentation.
1137        buffer.edit(
1138            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1139            Some(AutoindentMode::Block {
1140                original_indent_columns: original_indent_columns.clone(),
1141            }),
1142            cx,
1143        );
1144        assert_eq!(
1145            buffer.text(),
1146            r#"
1147            fn a() {
1148                b();
1149                "
1150                  c
1151                    d
1152                      e
1153                "
1154            }
1155            "#
1156            .unindent()
1157        );
1158
1159        // Grouping is disabled in tests, so we need 2 undos
1160        buffer.undo(cx); // Undo the auto-indent
1161        buffer.undo(cx); // Undo the original edit
1162
1163        // Insert the block at a deeper indent level. The entire block is outdented.
1164        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1165        buffer.edit(
1166            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1167            Some(AutoindentMode::Block {
1168                original_indent_columns: original_indent_columns.clone(),
1169            }),
1170            cx,
1171        );
1172        assert_eq!(
1173            buffer.text(),
1174            r#"
1175            fn a() {
1176                b();
1177                "
1178                  c
1179                    d
1180                      e
1181                "
1182            }
1183            "#
1184            .unindent()
1185        );
1186
1187        buffer
1188    });
1189}
1190
1191#[gpui::test]
1192fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut MutableAppContext) {
1193    cx.set_global(Settings::test(cx));
1194    cx.add_model(|cx| {
1195        let text = r#"
1196            fn a() {
1197                if b() {
1198
1199                }
1200            }
1201        "#
1202        .unindent();
1203        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1204
1205        // The original indent columns are not known, so this text is
1206        // auto-indented in a block as if the first line was copied in
1207        // its entirety.
1208        let original_indent_columns = Vec::new();
1209        let inserted_text = "    c\n        .d()\n        .e();";
1210
1211        // Insert the block at column zero. The entire block is indented
1212        // so that the first line matches the previous line's indentation.
1213        buffer.edit(
1214            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1215            Some(AutoindentMode::Block {
1216                original_indent_columns: original_indent_columns.clone(),
1217            }),
1218            cx,
1219        );
1220        assert_eq!(
1221            buffer.text(),
1222            r#"
1223            fn a() {
1224                if b() {
1225                    c
1226                        .d()
1227                        .e();
1228                }
1229            }
1230            "#
1231            .unindent()
1232        );
1233
1234        // Grouping is disabled in tests, so we need 2 undos
1235        buffer.undo(cx); // Undo the auto-indent
1236        buffer.undo(cx); // Undo the original edit
1237
1238        // Insert the block at a deeper indent level. The entire block is outdented.
1239        buffer.edit(
1240            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1241            None,
1242            cx,
1243        );
1244        buffer.edit(
1245            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1246            Some(AutoindentMode::Block {
1247                original_indent_columns: Vec::new(),
1248            }),
1249            cx,
1250        );
1251        assert_eq!(
1252            buffer.text(),
1253            r#"
1254            fn a() {
1255                if b() {
1256                    c
1257                        .d()
1258                        .e();
1259                }
1260            }
1261            "#
1262            .unindent()
1263        );
1264
1265        buffer
1266    });
1267}
1268
1269#[gpui::test]
1270fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
1271    cx.set_global(Settings::test(cx));
1272    cx.add_model(|cx| {
1273        let text = "
1274            * one
1275                - a
1276                - b
1277            * two
1278        "
1279        .unindent();
1280
1281        let mut buffer = Buffer::new(0, text, cx).with_language(
1282            Arc::new(Language::new(
1283                LanguageConfig {
1284                    name: "Markdown".into(),
1285                    auto_indent_using_last_non_empty_line: false,
1286                    ..Default::default()
1287                },
1288                Some(tree_sitter_json::language()),
1289            )),
1290            cx,
1291        );
1292        buffer.edit(
1293            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1294            Some(AutoindentMode::EachLine),
1295            cx,
1296        );
1297        assert_eq!(
1298            buffer.text(),
1299            "
1300            * one
1301                - a
1302                - b
1303
1304            * two
1305            "
1306            .unindent()
1307        );
1308        buffer
1309    });
1310}
1311
1312#[gpui::test]
1313fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
1314    cx.set_global({
1315        let mut settings = Settings::test(cx);
1316        settings.language_overrides.extend([
1317            (
1318                "HTML".into(),
1319                settings::EditorSettings {
1320                    tab_size: Some(2.try_into().unwrap()),
1321                    ..Default::default()
1322                },
1323            ),
1324            (
1325                "JavaScript".into(),
1326                settings::EditorSettings {
1327                    tab_size: Some(8.try_into().unwrap()),
1328                    ..Default::default()
1329                },
1330            ),
1331        ]);
1332        settings
1333    });
1334
1335    let html_language = Arc::new(
1336        Language::new(
1337            LanguageConfig {
1338                name: "HTML".into(),
1339                ..Default::default()
1340            },
1341            Some(tree_sitter_html::language()),
1342        )
1343        .with_indents_query(
1344            "
1345            (element
1346              (start_tag) @start
1347              (end_tag)? @end) @indent
1348            ",
1349        )
1350        .unwrap()
1351        .with_injection_query(
1352            r#"
1353            (script_element
1354                (raw_text) @content
1355                (#set! "language" "javascript"))
1356            "#,
1357        )
1358        .unwrap(),
1359    );
1360
1361    let javascript_language = Arc::new(
1362        Language::new(
1363            LanguageConfig {
1364                name: "JavaScript".into(),
1365                ..Default::default()
1366            },
1367            Some(tree_sitter_javascript::language()),
1368        )
1369        .with_indents_query(
1370            r#"
1371            (object "}" @end) @indent
1372            "#,
1373        )
1374        .unwrap(),
1375    );
1376
1377    let language_registry = Arc::new(LanguageRegistry::test());
1378    language_registry.add(html_language.clone());
1379    language_registry.add(javascript_language.clone());
1380
1381    cx.add_model(|cx| {
1382        let (text, ranges) = marked_text_ranges(
1383            &"
1384                <div>ˇ
1385                </div>
1386                <script>
1387                    init({ˇ
1388                    })
1389                </script>
1390                <span>ˇ
1391                </span>
1392            "
1393            .unindent(),
1394            false,
1395        );
1396
1397        let mut buffer = Buffer::new(0, text, cx);
1398        buffer.set_language_registry(language_registry);
1399        buffer.set_language(Some(html_language), cx);
1400        buffer.edit(
1401            ranges.into_iter().map(|range| (range, "\na")),
1402            Some(AutoindentMode::EachLine),
1403            cx,
1404        );
1405        assert_eq!(
1406            buffer.text(),
1407            "
1408                <div>
1409                  a
1410                </div>
1411                <script>
1412                    init({
1413                            a
1414                    })
1415                </script>
1416                <span>
1417                  a
1418                </span>
1419            "
1420            .unindent()
1421        );
1422        buffer
1423    });
1424}
1425
1426#[gpui::test]
1427fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
1428    let mut settings = Settings::test(cx);
1429    settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
1430    cx.set_global(settings);
1431    cx.add_model(|cx| {
1432        let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(ruby_lang()), cx);
1433
1434        let text = r#"
1435            class C
1436            def a(b, c)
1437            puts b
1438            puts c
1439            rescue
1440            puts "errored"
1441            exit 1
1442            end
1443            end
1444        "#
1445        .unindent();
1446
1447        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1448
1449        assert_eq!(
1450            buffer.text(),
1451            r#"
1452                class C
1453                  def a(b, c)
1454                    puts b
1455                    puts c
1456                  rescue
1457                    puts "errored"
1458                    exit 1
1459                  end
1460                end
1461            "#
1462            .unindent()
1463        );
1464
1465        buffer
1466    });
1467}
1468
1469#[gpui::test]
1470fn test_language_config_at(cx: &mut MutableAppContext) {
1471    cx.set_global(Settings::test(cx));
1472    cx.add_model(|cx| {
1473        let language = Language::new(
1474            LanguageConfig {
1475                name: "JavaScript".into(),
1476                line_comment: Some("// ".into()),
1477                brackets: vec![
1478                    BracketPair {
1479                        start: "{".into(),
1480                        end: "}".into(),
1481                        close: true,
1482                        newline: false,
1483                    },
1484                    BracketPair {
1485                        start: "'".into(),
1486                        end: "'".into(),
1487                        close: true,
1488                        newline: false,
1489                    },
1490                ],
1491                overrides: [
1492                    (
1493                        "element".into(),
1494                        LanguageConfigOverride {
1495                            line_comment: Override::Remove { remove: true },
1496                            block_comment: Override::Set(("{/*".into(), "*/}".into())),
1497                            ..Default::default()
1498                        },
1499                    ),
1500                    (
1501                        "string".into(),
1502                        LanguageConfigOverride {
1503                            brackets: Override::Set(vec![BracketPair {
1504                                start: "{".into(),
1505                                end: "}".into(),
1506                                close: true,
1507                                newline: false,
1508                            }]),
1509                            ..Default::default()
1510                        },
1511                    ),
1512                ]
1513                .into_iter()
1514                .collect(),
1515                ..Default::default()
1516            },
1517            Some(tree_sitter_javascript::language()),
1518        )
1519        .with_override_query(
1520            r#"
1521                (jsx_element) @element
1522                (string) @string
1523            "#,
1524        )
1525        .unwrap();
1526
1527        let text = r#"a["b"] = <C d="e"></C>;"#;
1528
1529        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
1530        let snapshot = buffer.snapshot();
1531
1532        let config = snapshot.language_scope_at(0).unwrap();
1533        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1534        assert_eq!(config.brackets().len(), 2);
1535
1536        let string_config = snapshot.language_scope_at(3).unwrap();
1537        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1538        assert_eq!(string_config.brackets().len(), 1);
1539
1540        let element_config = snapshot.language_scope_at(10).unwrap();
1541        assert_eq!(element_config.line_comment_prefix(), None);
1542        assert_eq!(
1543            element_config.block_comment_delimiters(),
1544            Some((&"{/*".into(), &"*/}".into()))
1545        );
1546        assert_eq!(element_config.brackets().len(), 2);
1547
1548        buffer
1549    });
1550}
1551
1552#[gpui::test]
1553fn test_serialization(cx: &mut gpui::MutableAppContext) {
1554    let mut now = Instant::now();
1555
1556    let buffer1 = cx.add_model(|cx| {
1557        let mut buffer = Buffer::new(0, "abc", cx);
1558        buffer.edit([(3..3, "D")], None, cx);
1559
1560        now += Duration::from_secs(1);
1561        buffer.start_transaction_at(now);
1562        buffer.edit([(4..4, "E")], None, cx);
1563        buffer.end_transaction_at(now, cx);
1564        assert_eq!(buffer.text(), "abcDE");
1565
1566        buffer.undo(cx);
1567        assert_eq!(buffer.text(), "abcD");
1568
1569        buffer.edit([(4..4, "F")], None, cx);
1570        assert_eq!(buffer.text(), "abcDF");
1571        buffer
1572    });
1573    assert_eq!(buffer1.read(cx).text(), "abcDF");
1574
1575    let state = buffer1.read(cx).to_proto();
1576    let ops = cx
1577        .background()
1578        .block(buffer1.read(cx).serialize_ops(None, cx));
1579    let buffer2 = cx.add_model(|cx| {
1580        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1581        buffer
1582            .apply_ops(
1583                ops.into_iter()
1584                    .map(|op| proto::deserialize_operation(op).unwrap()),
1585                cx,
1586            )
1587            .unwrap();
1588        buffer
1589    });
1590    assert_eq!(buffer2.read(cx).text(), "abcDF");
1591}
1592
1593#[gpui::test(iterations = 100)]
1594fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1595    let min_peers = env::var("MIN_PEERS")
1596        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1597        .unwrap_or(1);
1598    let max_peers = env::var("MAX_PEERS")
1599        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1600        .unwrap_or(5);
1601    let operations = env::var("OPERATIONS")
1602        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1603        .unwrap_or(10);
1604
1605    let base_text_len = rng.gen_range(0..10);
1606    let base_text = RandomCharIter::new(&mut rng)
1607        .take(base_text_len)
1608        .collect::<String>();
1609    let mut replica_ids = Vec::new();
1610    let mut buffers = Vec::new();
1611    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1612    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1613
1614    for i in 0..rng.gen_range(min_peers..=max_peers) {
1615        let buffer = cx.add_model(|cx| {
1616            let state = base_buffer.read(cx).to_proto();
1617            let ops = cx
1618                .background()
1619                .block(base_buffer.read(cx).serialize_ops(None, cx));
1620            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1621            buffer
1622                .apply_ops(
1623                    ops.into_iter()
1624                        .map(|op| proto::deserialize_operation(op).unwrap()),
1625                    cx,
1626                )
1627                .unwrap();
1628            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1629            let network = network.clone();
1630            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1631                if let Event::Operation(op) = event {
1632                    network
1633                        .borrow_mut()
1634                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1635                }
1636            })
1637            .detach();
1638            buffer
1639        });
1640        buffers.push(buffer);
1641        replica_ids.push(i as ReplicaId);
1642        network.borrow_mut().add_peer(i as ReplicaId);
1643        log::info!("Adding initial peer with replica id {}", i);
1644    }
1645
1646    log::info!("initial text: {:?}", base_text);
1647
1648    let mut now = Instant::now();
1649    let mut mutation_count = operations;
1650    let mut next_diagnostic_id = 0;
1651    let mut active_selections = BTreeMap::default();
1652    loop {
1653        let replica_index = rng.gen_range(0..replica_ids.len());
1654        let replica_id = replica_ids[replica_index];
1655        let buffer = &mut buffers[replica_index];
1656        let mut new_buffer = None;
1657        match rng.gen_range(0..100) {
1658            0..=29 if mutation_count != 0 => {
1659                buffer.update(cx, |buffer, cx| {
1660                    buffer.start_transaction_at(now);
1661                    buffer.randomly_edit(&mut rng, 5, cx);
1662                    buffer.end_transaction_at(now, cx);
1663                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1664                });
1665                mutation_count -= 1;
1666            }
1667            30..=39 if mutation_count != 0 => {
1668                buffer.update(cx, |buffer, cx| {
1669                    let mut selections = Vec::new();
1670                    for id in 0..rng.gen_range(1..=5) {
1671                        let range = buffer.random_byte_range(0, &mut rng);
1672                        selections.push(Selection {
1673                            id,
1674                            start: buffer.anchor_before(range.start),
1675                            end: buffer.anchor_before(range.end),
1676                            reversed: false,
1677                            goal: SelectionGoal::None,
1678                        });
1679                    }
1680                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1681                    log::info!(
1682                        "peer {} setting active selections: {:?}",
1683                        replica_id,
1684                        selections
1685                    );
1686                    active_selections.insert(replica_id, selections.clone());
1687                    buffer.set_active_selections(selections, false, Default::default(), cx);
1688                });
1689                mutation_count -= 1;
1690            }
1691            40..=49 if mutation_count != 0 && replica_id == 0 => {
1692                let entry_count = rng.gen_range(1..=5);
1693                buffer.update(cx, |buffer, cx| {
1694                    let diagnostics = DiagnosticSet::new(
1695                        (0..entry_count).map(|_| {
1696                            let range = buffer.random_byte_range(0, &mut rng);
1697                            let range = range.to_point_utf16(buffer);
1698                            let range = range.start..range.end;
1699                            DiagnosticEntry {
1700                                range,
1701                                diagnostic: Diagnostic {
1702                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1703                                    ..Default::default()
1704                                },
1705                            }
1706                        }),
1707                        buffer,
1708                    );
1709                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1710                    buffer.update_diagnostics(diagnostics, cx);
1711                });
1712                mutation_count -= 1;
1713            }
1714            50..=59 if replica_ids.len() < max_peers => {
1715                let old_buffer_state = buffer.read(cx).to_proto();
1716                let old_buffer_ops = cx
1717                    .background()
1718                    .block(buffer.read(cx).serialize_ops(None, cx));
1719                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1720                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1721                    .choose(&mut rng)
1722                    .unwrap();
1723                log::info!(
1724                    "Adding new replica {} (replicating from {})",
1725                    new_replica_id,
1726                    replica_id
1727                );
1728                new_buffer = Some(cx.add_model(|cx| {
1729                    let mut new_buffer =
1730                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1731                    new_buffer
1732                        .apply_ops(
1733                            old_buffer_ops
1734                                .into_iter()
1735                                .map(|op| deserialize_operation(op).unwrap()),
1736                            cx,
1737                        )
1738                        .unwrap();
1739                    log::info!(
1740                        "New replica {} text: {:?}",
1741                        new_buffer.replica_id(),
1742                        new_buffer.text()
1743                    );
1744                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1745                    let network = network.clone();
1746                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1747                        if let Event::Operation(op) = event {
1748                            network.borrow_mut().broadcast(
1749                                buffer.replica_id(),
1750                                vec![proto::serialize_operation(op)],
1751                            );
1752                        }
1753                    })
1754                    .detach();
1755                    new_buffer
1756                }));
1757                network.borrow_mut().replicate(replica_id, new_replica_id);
1758
1759                if new_replica_id as usize == replica_ids.len() {
1760                    replica_ids.push(new_replica_id);
1761                } else {
1762                    let new_buffer = new_buffer.take().unwrap();
1763                    while network.borrow().has_unreceived(new_replica_id) {
1764                        let ops = network
1765                            .borrow_mut()
1766                            .receive(new_replica_id)
1767                            .into_iter()
1768                            .map(|op| proto::deserialize_operation(op).unwrap());
1769                        if ops.len() > 0 {
1770                            log::info!(
1771                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1772                                new_replica_id,
1773                                buffer.read(cx).version(),
1774                                ops.len(),
1775                                ops
1776                            );
1777                            new_buffer.update(cx, |new_buffer, cx| {
1778                                new_buffer.apply_ops(ops, cx).unwrap();
1779                            });
1780                        }
1781                    }
1782                    buffers[new_replica_id as usize] = new_buffer;
1783                }
1784            }
1785            60..=69 if mutation_count != 0 => {
1786                buffer.update(cx, |buffer, cx| {
1787                    buffer.randomly_undo_redo(&mut rng, cx);
1788                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1789                });
1790                mutation_count -= 1;
1791            }
1792            _ if network.borrow().has_unreceived(replica_id) => {
1793                let ops = network
1794                    .borrow_mut()
1795                    .receive(replica_id)
1796                    .into_iter()
1797                    .map(|op| proto::deserialize_operation(op).unwrap());
1798                if ops.len() > 0 {
1799                    log::info!(
1800                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1801                        replica_id,
1802                        buffer.read(cx).version(),
1803                        ops.len(),
1804                        ops
1805                    );
1806                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1807                }
1808            }
1809            _ => {}
1810        }
1811
1812        now += Duration::from_millis(rng.gen_range(0..=200));
1813        buffers.extend(new_buffer);
1814
1815        for buffer in &buffers {
1816            buffer.read(cx).check_invariants();
1817        }
1818
1819        if mutation_count == 0 && network.borrow().is_idle() {
1820            break;
1821        }
1822    }
1823
1824    let first_buffer = buffers[0].read(cx).snapshot();
1825    for buffer in &buffers[1..] {
1826        let buffer = buffer.read(cx).snapshot();
1827        assert_eq!(
1828            buffer.version(),
1829            first_buffer.version(),
1830            "Replica {} version != Replica 0 version",
1831            buffer.replica_id()
1832        );
1833        assert_eq!(
1834            buffer.text(),
1835            first_buffer.text(),
1836            "Replica {} text != Replica 0 text",
1837            buffer.replica_id()
1838        );
1839        assert_eq!(
1840            buffer
1841                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1842                .collect::<Vec<_>>(),
1843            first_buffer
1844                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1845                .collect::<Vec<_>>(),
1846            "Replica {} diagnostics != Replica 0 diagnostics",
1847            buffer.replica_id()
1848        );
1849    }
1850
1851    for buffer in &buffers {
1852        let buffer = buffer.read(cx).snapshot();
1853        let actual_remote_selections = buffer
1854            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1855            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1856            .collect::<Vec<_>>();
1857        let expected_remote_selections = active_selections
1858            .iter()
1859            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1860            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1861            .collect::<Vec<_>>();
1862        assert_eq!(
1863            actual_remote_selections,
1864            expected_remote_selections,
1865            "Replica {} remote selections != expected selections",
1866            buffer.replica_id()
1867        );
1868    }
1869}
1870
1871#[test]
1872fn test_contiguous_ranges() {
1873    assert_eq!(
1874        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1875        &[1..4, 5..7, 9..13]
1876    );
1877
1878    // Respects the `max_len` parameter
1879    assert_eq!(
1880        contiguous_ranges(
1881            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1882            3
1883        )
1884        .collect::<Vec<_>>(),
1885        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1886    );
1887}
1888
1889impl Buffer {
1890    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1891        &self,
1892        range: Range<T>,
1893    ) -> Option<(Range<Point>, Range<Point>)> {
1894        self.snapshot()
1895            .enclosing_bracket_ranges(range)
1896            .map(|(start, end)| {
1897                let point_start = start.start.to_point(self)..start.end.to_point(self);
1898                let point_end = end.start.to_point(self)..end.end.to_point(self);
1899                (point_start, point_end)
1900            })
1901    }
1902}
1903
1904fn ruby_lang() -> Language {
1905    Language::new(
1906        LanguageConfig {
1907            name: "Ruby".into(),
1908            path_suffixes: vec!["rb".to_string()],
1909            ..Default::default()
1910        },
1911        Some(tree_sitter_ruby::language()),
1912    )
1913    .with_indents_query(
1914        r#"
1915            (class "end" @end) @indent
1916            (method "end" @end) @indent
1917            (rescue) @outdent
1918            (then) @indent
1919        "#,
1920    )
1921    .unwrap()
1922}
1923
1924fn rust_lang() -> Language {
1925    Language::new(
1926        LanguageConfig {
1927            name: "Rust".into(),
1928            path_suffixes: vec!["rs".to_string()],
1929            ..Default::default()
1930        },
1931        Some(tree_sitter_rust::language()),
1932    )
1933    .with_indents_query(
1934        r#"
1935        (call_expression) @indent
1936        (field_expression) @indent
1937        (_ "(" ")" @end) @indent
1938        (_ "{" "}" @end) @indent
1939        "#,
1940    )
1941    .unwrap()
1942    .with_brackets_query(
1943        r#"
1944        ("{" @open "}" @close)
1945        "#,
1946    )
1947    .unwrap()
1948    .with_outline_query(
1949        r#"
1950        (struct_item
1951            "struct" @context
1952            name: (_) @name) @item
1953        (enum_item
1954            "enum" @context
1955            name: (_) @name) @item
1956        (enum_variant
1957            name: (_) @name) @item
1958        (field_declaration
1959            name: (_) @name) @item
1960        (impl_item
1961            "impl" @context
1962            trait: (_)? @name
1963            "for"? @context
1964            type: (_) @name) @item
1965        (function_item
1966            "fn" @context
1967            name: (_) @name) @item
1968        (mod_item
1969            "mod" @context
1970            name: (_) @name) @item
1971        "#,
1972    )
1973    .unwrap()
1974}
1975
1976fn json_lang() -> Language {
1977    Language::new(
1978        LanguageConfig {
1979            name: "Json".into(),
1980            path_suffixes: vec!["js".to_string()],
1981            ..Default::default()
1982        },
1983        Some(tree_sitter_json::language()),
1984    )
1985}
1986
1987fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1988    buffer.read_with(cx, |buffer, _| {
1989        let snapshot = buffer.snapshot();
1990        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
1991        layers[0].node.to_sexp()
1992    })
1993}