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: vec![
1531                    BracketPair {
1532                        start: "{".into(),
1533                        end: "}".into(),
1534                        close: true,
1535                        newline: false,
1536                    },
1537                    BracketPair {
1538                        start: "'".into(),
1539                        end: "'".into(),
1540                        close: true,
1541                        newline: false,
1542                    },
1543                ],
1544                overrides: [
1545                    (
1546                        "element".into(),
1547                        LanguageConfigOverride {
1548                            line_comment: Override::Remove { remove: true },
1549                            block_comment: Override::Set(("{/*".into(), "*/}".into())),
1550                            ..Default::default()
1551                        },
1552                    ),
1553                    (
1554                        "string".into(),
1555                        LanguageConfigOverride {
1556                            brackets: Override::Set(vec![BracketPair {
1557                                start: "{".into(),
1558                                end: "}".into(),
1559                                close: true,
1560                                newline: false,
1561                            }]),
1562                            ..Default::default()
1563                        },
1564                    ),
1565                ]
1566                .into_iter()
1567                .collect(),
1568                ..Default::default()
1569            },
1570            Some(tree_sitter_javascript::language()),
1571        )
1572        .with_override_query(
1573            r#"
1574                (jsx_element) @element
1575                (string) @string
1576            "#,
1577        )
1578        .unwrap();
1579
1580        let text = r#"a["b"] = <C d="e"></C>;"#;
1581
1582        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
1583        let snapshot = buffer.snapshot();
1584
1585        let config = snapshot.language_scope_at(0).unwrap();
1586        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1587        assert_eq!(config.brackets().len(), 2);
1588
1589        let string_config = snapshot.language_scope_at(3).unwrap();
1590        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1591        assert_eq!(string_config.brackets().len(), 1);
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        assert_eq!(element_config.brackets().len(), 2);
1600
1601        buffer
1602    });
1603}
1604
1605#[gpui::test]
1606fn test_serialization(cx: &mut gpui::MutableAppContext) {
1607    let mut now = Instant::now();
1608
1609    let buffer1 = cx.add_model(|cx| {
1610        let mut buffer = Buffer::new(0, "abc", cx);
1611        buffer.edit([(3..3, "D")], None, cx);
1612
1613        now += Duration::from_secs(1);
1614        buffer.start_transaction_at(now);
1615        buffer.edit([(4..4, "E")], None, cx);
1616        buffer.end_transaction_at(now, cx);
1617        assert_eq!(buffer.text(), "abcDE");
1618
1619        buffer.undo(cx);
1620        assert_eq!(buffer.text(), "abcD");
1621
1622        buffer.edit([(4..4, "F")], None, cx);
1623        assert_eq!(buffer.text(), "abcDF");
1624        buffer
1625    });
1626    assert_eq!(buffer1.read(cx).text(), "abcDF");
1627
1628    let state = buffer1.read(cx).to_proto();
1629    let ops = cx
1630        .background()
1631        .block(buffer1.read(cx).serialize_ops(None, cx));
1632    let buffer2 = cx.add_model(|cx| {
1633        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1634        buffer
1635            .apply_ops(
1636                ops.into_iter()
1637                    .map(|op| proto::deserialize_operation(op).unwrap()),
1638                cx,
1639            )
1640            .unwrap();
1641        buffer
1642    });
1643    assert_eq!(buffer2.read(cx).text(), "abcDF");
1644}
1645
1646#[gpui::test(iterations = 100)]
1647fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1648    let min_peers = env::var("MIN_PEERS")
1649        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1650        .unwrap_or(1);
1651    let max_peers = env::var("MAX_PEERS")
1652        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1653        .unwrap_or(5);
1654    let operations = env::var("OPERATIONS")
1655        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1656        .unwrap_or(10);
1657
1658    let base_text_len = rng.gen_range(0..10);
1659    let base_text = RandomCharIter::new(&mut rng)
1660        .take(base_text_len)
1661        .collect::<String>();
1662    let mut replica_ids = Vec::new();
1663    let mut buffers = Vec::new();
1664    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1665    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1666
1667    for i in 0..rng.gen_range(min_peers..=max_peers) {
1668        let buffer = cx.add_model(|cx| {
1669            let state = base_buffer.read(cx).to_proto();
1670            let ops = cx
1671                .background()
1672                .block(base_buffer.read(cx).serialize_ops(None, cx));
1673            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1674            buffer
1675                .apply_ops(
1676                    ops.into_iter()
1677                        .map(|op| proto::deserialize_operation(op).unwrap()),
1678                    cx,
1679                )
1680                .unwrap();
1681            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1682            let network = network.clone();
1683            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1684                if let Event::Operation(op) = event {
1685                    network
1686                        .borrow_mut()
1687                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1688                }
1689            })
1690            .detach();
1691            buffer
1692        });
1693        buffers.push(buffer);
1694        replica_ids.push(i as ReplicaId);
1695        network.borrow_mut().add_peer(i as ReplicaId);
1696        log::info!("Adding initial peer with replica id {}", i);
1697    }
1698
1699    log::info!("initial text: {:?}", base_text);
1700
1701    let mut now = Instant::now();
1702    let mut mutation_count = operations;
1703    let mut next_diagnostic_id = 0;
1704    let mut active_selections = BTreeMap::default();
1705    loop {
1706        let replica_index = rng.gen_range(0..replica_ids.len());
1707        let replica_id = replica_ids[replica_index];
1708        let buffer = &mut buffers[replica_index];
1709        let mut new_buffer = None;
1710        match rng.gen_range(0..100) {
1711            0..=29 if mutation_count != 0 => {
1712                buffer.update(cx, |buffer, cx| {
1713                    buffer.start_transaction_at(now);
1714                    buffer.randomly_edit(&mut rng, 5, cx);
1715                    buffer.end_transaction_at(now, cx);
1716                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1717                });
1718                mutation_count -= 1;
1719            }
1720            30..=39 if mutation_count != 0 => {
1721                buffer.update(cx, |buffer, cx| {
1722                    let mut selections = Vec::new();
1723                    for id in 0..rng.gen_range(1..=5) {
1724                        let range = buffer.random_byte_range(0, &mut rng);
1725                        selections.push(Selection {
1726                            id,
1727                            start: buffer.anchor_before(range.start),
1728                            end: buffer.anchor_before(range.end),
1729                            reversed: false,
1730                            goal: SelectionGoal::None,
1731                        });
1732                    }
1733                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1734                    log::info!(
1735                        "peer {} setting active selections: {:?}",
1736                        replica_id,
1737                        selections
1738                    );
1739                    active_selections.insert(replica_id, selections.clone());
1740                    buffer.set_active_selections(selections, false, Default::default(), cx);
1741                });
1742                mutation_count -= 1;
1743            }
1744            40..=49 if mutation_count != 0 && replica_id == 0 => {
1745                let entry_count = rng.gen_range(1..=5);
1746                buffer.update(cx, |buffer, cx| {
1747                    let diagnostics = DiagnosticSet::new(
1748                        (0..entry_count).map(|_| {
1749                            let range = buffer.random_byte_range(0, &mut rng);
1750                            let range = range.to_point_utf16(buffer);
1751                            let range = range.start..range.end;
1752                            DiagnosticEntry {
1753                                range,
1754                                diagnostic: Diagnostic {
1755                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1756                                    ..Default::default()
1757                                },
1758                            }
1759                        }),
1760                        buffer,
1761                    );
1762                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1763                    buffer.update_diagnostics(diagnostics, cx);
1764                });
1765                mutation_count -= 1;
1766            }
1767            50..=59 if replica_ids.len() < max_peers => {
1768                let old_buffer_state = buffer.read(cx).to_proto();
1769                let old_buffer_ops = cx
1770                    .background()
1771                    .block(buffer.read(cx).serialize_ops(None, cx));
1772                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1773                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1774                    .choose(&mut rng)
1775                    .unwrap();
1776                log::info!(
1777                    "Adding new replica {} (replicating from {})",
1778                    new_replica_id,
1779                    replica_id
1780                );
1781                new_buffer = Some(cx.add_model(|cx| {
1782                    let mut new_buffer =
1783                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1784                    new_buffer
1785                        .apply_ops(
1786                            old_buffer_ops
1787                                .into_iter()
1788                                .map(|op| deserialize_operation(op).unwrap()),
1789                            cx,
1790                        )
1791                        .unwrap();
1792                    log::info!(
1793                        "New replica {} text: {:?}",
1794                        new_buffer.replica_id(),
1795                        new_buffer.text()
1796                    );
1797                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1798                    let network = network.clone();
1799                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1800                        if let Event::Operation(op) = event {
1801                            network.borrow_mut().broadcast(
1802                                buffer.replica_id(),
1803                                vec![proto::serialize_operation(op)],
1804                            );
1805                        }
1806                    })
1807                    .detach();
1808                    new_buffer
1809                }));
1810                network.borrow_mut().replicate(replica_id, new_replica_id);
1811
1812                if new_replica_id as usize == replica_ids.len() {
1813                    replica_ids.push(new_replica_id);
1814                } else {
1815                    let new_buffer = new_buffer.take().unwrap();
1816                    while network.borrow().has_unreceived(new_replica_id) {
1817                        let ops = network
1818                            .borrow_mut()
1819                            .receive(new_replica_id)
1820                            .into_iter()
1821                            .map(|op| proto::deserialize_operation(op).unwrap());
1822                        if ops.len() > 0 {
1823                            log::info!(
1824                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1825                                new_replica_id,
1826                                buffer.read(cx).version(),
1827                                ops.len(),
1828                                ops
1829                            );
1830                            new_buffer.update(cx, |new_buffer, cx| {
1831                                new_buffer.apply_ops(ops, cx).unwrap();
1832                            });
1833                        }
1834                    }
1835                    buffers[new_replica_id as usize] = new_buffer;
1836                }
1837            }
1838            60..=69 if mutation_count != 0 => {
1839                buffer.update(cx, |buffer, cx| {
1840                    buffer.randomly_undo_redo(&mut rng, cx);
1841                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1842                });
1843                mutation_count -= 1;
1844            }
1845            _ if network.borrow().has_unreceived(replica_id) => {
1846                let ops = network
1847                    .borrow_mut()
1848                    .receive(replica_id)
1849                    .into_iter()
1850                    .map(|op| proto::deserialize_operation(op).unwrap());
1851                if ops.len() > 0 {
1852                    log::info!(
1853                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1854                        replica_id,
1855                        buffer.read(cx).version(),
1856                        ops.len(),
1857                        ops
1858                    );
1859                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1860                }
1861            }
1862            _ => {}
1863        }
1864
1865        now += Duration::from_millis(rng.gen_range(0..=200));
1866        buffers.extend(new_buffer);
1867
1868        for buffer in &buffers {
1869            buffer.read(cx).check_invariants();
1870        }
1871
1872        if mutation_count == 0 && network.borrow().is_idle() {
1873            break;
1874        }
1875    }
1876
1877    let first_buffer = buffers[0].read(cx).snapshot();
1878    for buffer in &buffers[1..] {
1879        let buffer = buffer.read(cx).snapshot();
1880        assert_eq!(
1881            buffer.version(),
1882            first_buffer.version(),
1883            "Replica {} version != Replica 0 version",
1884            buffer.replica_id()
1885        );
1886        assert_eq!(
1887            buffer.text(),
1888            first_buffer.text(),
1889            "Replica {} text != Replica 0 text",
1890            buffer.replica_id()
1891        );
1892        assert_eq!(
1893            buffer
1894                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1895                .collect::<Vec<_>>(),
1896            first_buffer
1897                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1898                .collect::<Vec<_>>(),
1899            "Replica {} diagnostics != Replica 0 diagnostics",
1900            buffer.replica_id()
1901        );
1902    }
1903
1904    for buffer in &buffers {
1905        let buffer = buffer.read(cx).snapshot();
1906        let actual_remote_selections = buffer
1907            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1908            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1909            .collect::<Vec<_>>();
1910        let expected_remote_selections = active_selections
1911            .iter()
1912            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1913            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1914            .collect::<Vec<_>>();
1915        assert_eq!(
1916            actual_remote_selections,
1917            expected_remote_selections,
1918            "Replica {} remote selections != expected selections",
1919            buffer.replica_id()
1920        );
1921    }
1922}
1923
1924#[test]
1925fn test_contiguous_ranges() {
1926    assert_eq!(
1927        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1928        &[1..4, 5..7, 9..13]
1929    );
1930
1931    // Respects the `max_len` parameter
1932    assert_eq!(
1933        contiguous_ranges(
1934            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1935            3
1936        )
1937        .collect::<Vec<_>>(),
1938        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1939    );
1940}
1941
1942fn ruby_lang() -> Language {
1943    Language::new(
1944        LanguageConfig {
1945            name: "Ruby".into(),
1946            path_suffixes: vec!["rb".to_string()],
1947            ..Default::default()
1948        },
1949        Some(tree_sitter_ruby::language()),
1950    )
1951    .with_indents_query(
1952        r#"
1953            (class "end" @end) @indent
1954            (method "end" @end) @indent
1955            (rescue) @outdent
1956            (then) @indent
1957        "#,
1958    )
1959    .unwrap()
1960}
1961
1962fn rust_lang() -> Language {
1963    Language::new(
1964        LanguageConfig {
1965            name: "Rust".into(),
1966            path_suffixes: vec!["rs".to_string()],
1967            ..Default::default()
1968        },
1969        Some(tree_sitter_rust::language()),
1970    )
1971    .with_indents_query(
1972        r#"
1973        (call_expression) @indent
1974        (field_expression) @indent
1975        (_ "(" ")" @end) @indent
1976        (_ "{" "}" @end) @indent
1977        "#,
1978    )
1979    .unwrap()
1980    .with_brackets_query(
1981        r#"
1982        ("{" @open "}" @close)
1983        "#,
1984    )
1985    .unwrap()
1986    .with_outline_query(
1987        r#"
1988        (struct_item
1989            "struct" @context
1990            name: (_) @name) @item
1991        (enum_item
1992            "enum" @context
1993            name: (_) @name) @item
1994        (enum_variant
1995            name: (_) @name) @item
1996        (field_declaration
1997            name: (_) @name) @item
1998        (impl_item
1999            "impl" @context
2000            trait: (_)? @name
2001            "for"? @context
2002            type: (_) @name) @item
2003        (function_item
2004            "fn" @context
2005            name: (_) @name) @item
2006        (mod_item
2007            "mod" @context
2008            name: (_) @name) @item
2009        "#,
2010    )
2011    .unwrap()
2012}
2013
2014fn json_lang() -> Language {
2015    Language::new(
2016        LanguageConfig {
2017            name: "Json".into(),
2018            path_suffixes: vec!["js".to_string()],
2019            ..Default::default()
2020        },
2021        Some(tree_sitter_json::language()),
2022    )
2023}
2024
2025fn javascript_lang() -> Language {
2026    Language::new(
2027        LanguageConfig {
2028            name: "JavaScript".into(),
2029            ..Default::default()
2030        },
2031        Some(tree_sitter_javascript::language()),
2032    )
2033    .with_brackets_query(
2034        r#"
2035        ("{" @open "}" @close)
2036        ("(" @open ")" @close)
2037        "#,
2038    )
2039    .unwrap()
2040}
2041
2042fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2043    buffer.read_with(cx, |buffer, _| {
2044        let snapshot = buffer.snapshot();
2045        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2046        layers[0].node.to_sexp()
2047    })
2048}
2049
2050// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2051fn assert_bracket_pairs(
2052    selection_text: &'static str,
2053    bracket_pair_texts: Vec<&'static str>,
2054    language: Language,
2055    cx: &mut MutableAppContext,
2056) {
2057    cx.set_global(Settings::test(cx));
2058    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2059    let buffer = cx.add_model(|cx| {
2060        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
2061    });
2062    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2063
2064    let selection_range = selection_ranges[0].clone();
2065
2066    let bracket_pairs = bracket_pair_texts
2067        .into_iter()
2068        .map(|pair_text| {
2069            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2070            assert_eq!(bracket_text, expected_text);
2071            (ranges[0].clone(), ranges[1].clone())
2072        })
2073        .collect::<Vec<_>>();
2074
2075    assert_set_eq!(
2076        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2077        bracket_pairs
2078    );
2079}