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