buffer_tests.rs

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