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