tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use gpui::{ModelHandle, MutableAppContext};
   5use rand::prelude::*;
   6use settings::Settings;
   7use std::{
   8    cell::RefCell,
   9    env,
  10    ops::Range,
  11    rc::Rc,
  12    time::{Duration, Instant},
  13};
  14use text::network::Network;
  15use unindent::Unindent as _;
  16use util::post_inc;
  17
  18#[cfg(test)]
  19#[ctor::ctor]
  20fn init_logger() {
  21    if std::env::var("RUST_LOG").is_ok() {
  22        env_logger::init();
  23    }
  24}
  25
  26#[gpui::test]
  27fn test_line_endings(cx: &mut gpui::MutableAppContext) {
  28    cx.set_global(Settings::test(cx));
  29    cx.add_model(|cx| {
  30        let mut buffer =
  31            Buffer::new(0, "one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  32        assert_eq!(buffer.text(), "one\ntwo\nthree");
  33        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  34
  35        buffer.check_invariants();
  36        buffer.edit_with_autoindent([(buffer.len()..buffer.len(), "\r\nfour")], cx);
  37        buffer.edit([(0..0, "zero\r\n")], cx);
  38        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  39        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  40        buffer.check_invariants();
  41
  42        buffer
  43    });
  44}
  45
  46#[gpui::test]
  47fn test_select_language() {
  48    let registry = LanguageRegistry::test();
  49    registry.add(Arc::new(Language::new(
  50        LanguageConfig {
  51            name: "Rust".into(),
  52            path_suffixes: vec!["rs".to_string()],
  53            ..Default::default()
  54        },
  55        Some(tree_sitter_rust::language()),
  56    )));
  57    registry.add(Arc::new(Language::new(
  58        LanguageConfig {
  59            name: "Make".into(),
  60            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  61            ..Default::default()
  62        },
  63        Some(tree_sitter_rust::language()),
  64    )));
  65
  66    // matching file extension
  67    assert_eq!(
  68        registry.select_language("zed/lib.rs").map(|l| l.name()),
  69        Some("Rust".into())
  70    );
  71    assert_eq!(
  72        registry.select_language("zed/lib.mk").map(|l| l.name()),
  73        Some("Make".into())
  74    );
  75
  76    // matching filename
  77    assert_eq!(
  78        registry.select_language("zed/Makefile").map(|l| l.name()),
  79        Some("Make".into())
  80    );
  81
  82    // matching suffix that is not the full file extension or filename
  83    assert_eq!(registry.select_language("zed/cars").map(|l| l.name()), None);
  84    assert_eq!(
  85        registry.select_language("zed/a.cars").map(|l| l.name()),
  86        None
  87    );
  88    assert_eq!(registry.select_language("zed/sumk").map(|l| l.name()), None);
  89}
  90
  91#[gpui::test]
  92fn test_edit_events(cx: &mut gpui::MutableAppContext) {
  93    let mut now = Instant::now();
  94    let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
  95    let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
  96
  97    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
  98    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
  99    let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
 100    buffer1.update(cx, {
 101        let buffer1_ops = buffer1_ops.clone();
 102        |buffer, cx| {
 103            let buffer_1_events = buffer_1_events.clone();
 104            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 105                Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
 106                event @ _ => buffer_1_events.borrow_mut().push(event),
 107            })
 108            .detach();
 109            let buffer_2_events = buffer_2_events.clone();
 110            cx.subscribe(&buffer2, move |_, _, event, _| {
 111                buffer_2_events.borrow_mut().push(event.clone())
 112            })
 113            .detach();
 114
 115            // An edit emits an edited event, followed by a dirty changed event,
 116            // since the buffer was previously in a clean state.
 117            buffer.edit([(2..4, "XYZ")], cx);
 118
 119            // An empty transaction does not emit any events.
 120            buffer.start_transaction();
 121            buffer.end_transaction(cx);
 122
 123            // A transaction containing two edits emits one edited event.
 124            now += Duration::from_secs(1);
 125            buffer.start_transaction_at(now);
 126            buffer.edit([(5..5, "u")], cx);
 127            buffer.edit([(6..6, "w")], cx);
 128            buffer.end_transaction_at(now, cx);
 129
 130            // Undoing a transaction emits one edited event.
 131            buffer.undo(cx);
 132        }
 133    });
 134
 135    // Incorporating a set of remote ops emits a single edited event,
 136    // followed by a dirty changed event.
 137    buffer2.update(cx, |buffer, cx| {
 138        buffer
 139            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 140            .unwrap();
 141    });
 142    assert_eq!(
 143        mem::take(&mut *buffer_1_events.borrow_mut()),
 144        vec![
 145            Event::Edited,
 146            Event::DirtyChanged,
 147            Event::Edited,
 148            Event::Edited,
 149        ]
 150    );
 151    assert_eq!(
 152        mem::take(&mut *buffer_2_events.borrow_mut()),
 153        vec![Event::Edited, Event::DirtyChanged]
 154    );
 155
 156    buffer1.update(cx, |buffer, cx| {
 157        // Undoing the first transaction emits edited event, followed by a
 158        // dirty changed event, since the buffer is again in a clean state.
 159        buffer.undo(cx);
 160    });
 161    // Incorporating the remote ops again emits a single edited event,
 162    // followed by a dirty changed event.
 163    buffer2.update(cx, |buffer, cx| {
 164        buffer
 165            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 166            .unwrap();
 167    });
 168    assert_eq!(
 169        mem::take(&mut *buffer_1_events.borrow_mut()),
 170        vec![Event::Edited, Event::DirtyChanged,]
 171    );
 172    assert_eq!(
 173        mem::take(&mut *buffer_2_events.borrow_mut()),
 174        vec![Event::Edited, Event::DirtyChanged]
 175    );
 176}
 177
 178#[gpui::test]
 179async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
 180    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 181    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 182
 183    let text = "a\nccc\ndddd\nffffff\n";
 184    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 185    buffer.update(cx, |buffer, cx| {
 186        buffer.apply_diff(diff, cx).unwrap();
 187    });
 188    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
 189
 190    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 191    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 192    buffer.update(cx, |buffer, cx| {
 193        buffer.apply_diff(diff, cx).unwrap();
 194    });
 195    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
 196}
 197
 198#[gpui::test]
 199async fn test_reparse(cx: &mut gpui::TestAppContext) {
 200    let text = "fn a() {}";
 201    let buffer =
 202        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 203
 204    // Wait for the initial text to parse
 205    buffer
 206        .condition(&cx, |buffer, _| !buffer.is_parsing())
 207        .await;
 208    assert_eq!(
 209        get_tree_sexp(&buffer, &cx),
 210        concat!(
 211            "(source_file (function_item name: (identifier) ",
 212            "parameters: (parameters) ",
 213            "body: (block)))"
 214        )
 215    );
 216
 217    buffer.update(cx, |buffer, _| {
 218        buffer.set_sync_parse_timeout(Duration::ZERO)
 219    });
 220
 221    // Perform some edits (add parameter and variable reference)
 222    // Parsing doesn't begin until the transaction is complete
 223    buffer.update(cx, |buf, cx| {
 224        buf.start_transaction();
 225
 226        let offset = buf.text().find(")").unwrap();
 227        buf.edit([(offset..offset, "b: C")], cx);
 228        assert!(!buf.is_parsing());
 229
 230        let offset = buf.text().find("}").unwrap();
 231        buf.edit([(offset..offset, " d; ")], cx);
 232        assert!(!buf.is_parsing());
 233
 234        buf.end_transaction(cx);
 235        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 236        assert!(buf.is_parsing());
 237    });
 238    buffer
 239        .condition(&cx, |buffer, _| !buffer.is_parsing())
 240        .await;
 241    assert_eq!(
 242        get_tree_sexp(&buffer, &cx),
 243        concat!(
 244            "(source_file (function_item name: (identifier) ",
 245            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 246            "body: (block (expression_statement (identifier)))))"
 247        )
 248    );
 249
 250    // Perform a series of edits without waiting for the current parse to complete:
 251    // * turn identifier into a field expression
 252    // * turn field expression into a method call
 253    // * add a turbofish to the method call
 254    buffer.update(cx, |buf, cx| {
 255        let offset = buf.text().find(";").unwrap();
 256        buf.edit([(offset..offset, ".e")], cx);
 257        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 258        assert!(buf.is_parsing());
 259    });
 260    buffer.update(cx, |buf, cx| {
 261        let offset = buf.text().find(";").unwrap();
 262        buf.edit([(offset..offset, "(f)")], cx);
 263        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 264        assert!(buf.is_parsing());
 265    });
 266    buffer.update(cx, |buf, cx| {
 267        let offset = buf.text().find("(f)").unwrap();
 268        buf.edit([(offset..offset, "::<G>")], cx);
 269        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 270        assert!(buf.is_parsing());
 271    });
 272    buffer
 273        .condition(&cx, |buffer, _| !buffer.is_parsing())
 274        .await;
 275    assert_eq!(
 276        get_tree_sexp(&buffer, &cx),
 277        concat!(
 278            "(source_file (function_item name: (identifier) ",
 279            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 280            "body: (block (expression_statement (call_expression ",
 281            "function: (generic_function ",
 282            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 283            "type_arguments: (type_arguments (type_identifier))) ",
 284            "arguments: (arguments (identifier)))))))",
 285        )
 286    );
 287
 288    buffer.update(cx, |buf, cx| {
 289        buf.undo(cx);
 290        assert_eq!(buf.text(), "fn a() {}");
 291        assert!(buf.is_parsing());
 292    });
 293    buffer
 294        .condition(&cx, |buffer, _| !buffer.is_parsing())
 295        .await;
 296    assert_eq!(
 297        get_tree_sexp(&buffer, &cx),
 298        concat!(
 299            "(source_file (function_item name: (identifier) ",
 300            "parameters: (parameters) ",
 301            "body: (block)))"
 302        )
 303    );
 304
 305    buffer.update(cx, |buf, cx| {
 306        buf.redo(cx);
 307        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 308        assert!(buf.is_parsing());
 309    });
 310    buffer
 311        .condition(&cx, |buffer, _| !buffer.is_parsing())
 312        .await;
 313    assert_eq!(
 314        get_tree_sexp(&buffer, &cx),
 315        concat!(
 316            "(source_file (function_item name: (identifier) ",
 317            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 318            "body: (block (expression_statement (call_expression ",
 319            "function: (generic_function ",
 320            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 321            "type_arguments: (type_arguments (type_identifier))) ",
 322            "arguments: (arguments (identifier)))))))",
 323        )
 324    );
 325}
 326
 327#[gpui::test]
 328async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 329    let buffer = cx.add_model(|cx| {
 330        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 331        buffer.set_sync_parse_timeout(Duration::ZERO);
 332        buffer
 333    });
 334
 335    // Wait for the initial text to parse
 336    buffer
 337        .condition(&cx, |buffer, _| !buffer.is_parsing())
 338        .await;
 339    assert_eq!(
 340        get_tree_sexp(&buffer, &cx),
 341        "(source_file (expression_statement (block)))"
 342    );
 343
 344    buffer.update(cx, |buffer, cx| {
 345        buffer.set_language(Some(Arc::new(json_lang())), cx)
 346    });
 347    buffer
 348        .condition(&cx, |buffer, _| !buffer.is_parsing())
 349        .await;
 350    assert_eq!(get_tree_sexp(&buffer, &cx), "(document (object))");
 351}
 352
 353#[gpui::test]
 354async fn test_outline(cx: &mut gpui::TestAppContext) {
 355    let text = r#"
 356        struct Person {
 357            name: String,
 358            age: usize,
 359        }
 360
 361        mod module {
 362            enum LoginState {
 363                LoggedOut,
 364                LoggingOn,
 365                LoggedIn {
 366                    person: Person,
 367                    time: Instant,
 368                }
 369            }
 370        }
 371
 372        impl Eq for Person {}
 373
 374        impl Drop for Person {
 375            fn drop(&mut self) {
 376                println!("bye");
 377            }
 378        }
 379    "#
 380    .unindent();
 381
 382    let buffer =
 383        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 384    let outline = buffer
 385        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 386        .unwrap();
 387
 388    assert_eq!(
 389        outline
 390            .items
 391            .iter()
 392            .map(|item| (item.text.as_str(), item.depth))
 393            .collect::<Vec<_>>(),
 394        &[
 395            ("struct Person", 0),
 396            ("name", 1),
 397            ("age", 1),
 398            ("mod module", 0),
 399            ("enum LoginState", 1),
 400            ("LoggedOut", 2),
 401            ("LoggingOn", 2),
 402            ("LoggedIn", 2),
 403            ("person", 3),
 404            ("time", 3),
 405            ("impl Eq for Person", 0),
 406            ("impl Drop for Person", 0),
 407            ("fn drop", 1),
 408        ]
 409    );
 410
 411    // Without space, we only match on names
 412    assert_eq!(
 413        search(&outline, "oon", &cx).await,
 414        &[
 415            ("mod module", vec![]),                    // included as the parent of a match
 416            ("enum LoginState", vec![]),               // included as the parent of a match
 417            ("LoggingOn", vec![1, 7, 8]),              // matches
 418            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 419        ]
 420    );
 421
 422    assert_eq!(
 423        search(&outline, "dp p", &cx).await,
 424        &[
 425            ("impl Drop for Person", vec![5, 8, 9, 14]),
 426            ("fn drop", vec![]),
 427        ]
 428    );
 429    assert_eq!(
 430        search(&outline, "dpn", &cx).await,
 431        &[("impl Drop for Person", vec![5, 14, 19])]
 432    );
 433    assert_eq!(
 434        search(&outline, "impl ", &cx).await,
 435        &[
 436            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 437            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 438            ("fn drop", vec![]),
 439        ]
 440    );
 441
 442    async fn search<'a>(
 443        outline: &'a Outline<Anchor>,
 444        query: &'a str,
 445        cx: &'a gpui::TestAppContext,
 446    ) -> Vec<(&'a str, Vec<usize>)> {
 447        let matches = cx
 448            .read(|cx| outline.search(query, cx.background().clone()))
 449            .await;
 450        matches
 451            .into_iter()
 452            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 453            .collect::<Vec<_>>()
 454    }
 455}
 456
 457#[gpui::test]
 458async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 459    let text = r#"
 460        impl Person {
 461            fn one() {
 462                1
 463            }
 464
 465            fn two() {
 466                2
 467            }fn three() {
 468                3
 469            }
 470        }
 471    "#
 472    .unindent();
 473
 474    let buffer =
 475        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 476    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 477
 478    // point is at the start of an item
 479    assert_eq!(
 480        symbols_containing(Point::new(1, 4), &snapshot),
 481        vec![
 482            (
 483                "impl Person".to_string(),
 484                Point::new(0, 0)..Point::new(10, 1)
 485            ),
 486            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 487        ]
 488    );
 489
 490    // point is in the middle of an item
 491    assert_eq!(
 492        symbols_containing(Point::new(2, 8), &snapshot),
 493        vec![
 494            (
 495                "impl Person".to_string(),
 496                Point::new(0, 0)..Point::new(10, 1)
 497            ),
 498            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 499        ]
 500    );
 501
 502    // point is at the end of an item
 503    assert_eq!(
 504        symbols_containing(Point::new(3, 5), &snapshot),
 505        vec![
 506            (
 507                "impl Person".to_string(),
 508                Point::new(0, 0)..Point::new(10, 1)
 509            ),
 510            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 511        ]
 512    );
 513
 514    // point is in between two adjacent items
 515    assert_eq!(
 516        symbols_containing(Point::new(7, 5), &snapshot),
 517        vec![
 518            (
 519                "impl Person".to_string(),
 520                Point::new(0, 0)..Point::new(10, 1)
 521            ),
 522            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 523        ]
 524    );
 525
 526    fn symbols_containing<'a>(
 527        position: Point,
 528        snapshot: &'a BufferSnapshot,
 529    ) -> Vec<(String, Range<Point>)> {
 530        snapshot
 531            .symbols_containing(position, None)
 532            .unwrap()
 533            .into_iter()
 534            .map(|item| {
 535                (
 536                    item.text,
 537                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 538                )
 539            })
 540            .collect()
 541    }
 542}
 543
 544#[gpui::test]
 545fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 546    cx.set_global(Settings::test(cx));
 547    let buffer = cx.add_model(|cx| {
 548        let text = "
 549            mod x {
 550                mod y {
 551
 552                }
 553            }
 554        "
 555        .unindent();
 556        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
 557    });
 558    let buffer = buffer.read(cx);
 559    assert_eq!(
 560        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
 561        Some((
 562            Point::new(0, 6)..Point::new(0, 7),
 563            Point::new(4, 0)..Point::new(4, 1)
 564        ))
 565    );
 566    assert_eq!(
 567        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
 568        Some((
 569            Point::new(1, 10)..Point::new(1, 11),
 570            Point::new(3, 4)..Point::new(3, 5)
 571        ))
 572    );
 573    assert_eq!(
 574        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
 575        Some((
 576            Point::new(1, 10)..Point::new(1, 11),
 577            Point::new(3, 4)..Point::new(3, 5)
 578        ))
 579    );
 580}
 581
 582#[gpui::test]
 583fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 584    cx.add_model(|cx| {
 585        let text = "fn a() { b(|c| {}) }";
 586        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 587        let snapshot = buffer.snapshot();
 588
 589        assert_eq!(
 590            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 591            Some(range_of(text, "|"))
 592        );
 593        assert_eq!(
 594            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 595            Some(range_of(text, "|c|"))
 596        );
 597        assert_eq!(
 598            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 599            Some(range_of(text, "|c| {}"))
 600        );
 601        assert_eq!(
 602            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 603            Some(range_of(text, "(|c| {})"))
 604        );
 605
 606        buffer
 607    });
 608
 609    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 610        let start = text.find(part).unwrap();
 611        start..start
 612    }
 613
 614    fn range_of(text: &str, part: &str) -> Range<usize> {
 615        let start = text.find(part).unwrap();
 616        start..start + part.len()
 617    }
 618}
 619
 620#[gpui::test]
 621fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 622    let settings = Settings::test(cx);
 623    cx.set_global(settings);
 624
 625    cx.add_model(|cx| {
 626        let text = "fn a() {}";
 627        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 628
 629        buffer.edit_with_autoindent([(8..8, "\n\n")], cx);
 630        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 631
 632        buffer.edit_with_autoindent([(Point::new(1, 4)..Point::new(1, 4), "b()\n")], cx);
 633        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 634
 635        // Create a field expression on a new line, causing that line
 636        // to be indented.
 637        buffer.edit_with_autoindent([(Point::new(2, 4)..Point::new(2, 4), ".c")], cx);
 638        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 639
 640        // Remove the dot so that the line is no longer a field expression,
 641        // causing the line to be outdented.
 642        buffer.edit_with_autoindent([(Point::new(2, 8)..Point::new(2, 9), "")], cx);
 643        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 644
 645        buffer
 646    });
 647}
 648
 649#[gpui::test]
 650fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 651    let mut settings = Settings::test(cx);
 652    settings.editor_overrides.hard_tabs = Some(true);
 653    cx.set_global(settings);
 654
 655    cx.add_model(|cx| {
 656        let text = "fn a() {}";
 657        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 658
 659        buffer.edit_with_autoindent([(8..8, "\n\n")], cx);
 660        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 661
 662        buffer.edit_with_autoindent([(Point::new(1, 1)..Point::new(1, 1), "b()\n")], cx);
 663        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 664
 665        // Create a field expression on a new line, causing that line
 666        // to be indented.
 667        buffer.edit_with_autoindent([(Point::new(2, 1)..Point::new(2, 1), ".c")], cx);
 668        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 669
 670        // Remove the dot so that the line is no longer a field expression,
 671        // causing the line to be outdented.
 672        buffer.edit_with_autoindent([(Point::new(2, 2)..Point::new(2, 3), "")], cx);
 673        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 674
 675        buffer
 676    });
 677}
 678
 679#[gpui::test]
 680fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 681    let settings = Settings::test(cx);
 682    cx.set_global(settings);
 683
 684    cx.add_model(|cx| {
 685        let text = "
 686            fn a() {
 687            c;
 688            d;
 689            }
 690        "
 691        .unindent();
 692
 693        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 694
 695        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 696        // their indentation is not adjusted.
 697        buffer.edit_with_autoindent(
 698            [
 699                (empty(Point::new(1, 1)), "()"),
 700                (empty(Point::new(2, 1)), "()"),
 701            ],
 702            cx,
 703        );
 704        assert_eq!(
 705            buffer.text(),
 706            "
 707            fn a() {
 708            c();
 709            d();
 710            }
 711            "
 712            .unindent()
 713        );
 714
 715        // When appending new content after these lines, the indentation is based on the
 716        // preceding lines' actual indentation.
 717        buffer.edit_with_autoindent(
 718            [
 719                (empty(Point::new(1, 1)), "\n.f\n.g"),
 720                (empty(Point::new(2, 1)), "\n.f\n.g"),
 721            ],
 722            cx,
 723        );
 724        assert_eq!(
 725            buffer.text(),
 726            "
 727            fn a() {
 728            c
 729                .f
 730                .g();
 731            d
 732                .f
 733                .g();
 734            }
 735            "
 736            .unindent()
 737        );
 738        buffer
 739    });
 740
 741    cx.add_model(|cx| {
 742        let text = "
 743            fn a() {
 744                {
 745                    b()?
 746                }
 747                Ok(())
 748            }
 749        "
 750        .unindent();
 751        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 752
 753        // Delete a closing curly brace changes the suggested indent for the line.
 754        buffer.edit_with_autoindent([(Point::new(3, 4)..Point::new(3, 5), "")], cx);
 755        assert_eq!(
 756            buffer.text(),
 757            "
 758            fn a() {
 759                {
 760                    b()?
 761                        |
 762                Ok(())
 763            }
 764            "
 765            .replace("|", "") // included in the string to preserve trailing whites
 766            .unindent()
 767        );
 768
 769        // Manually editing the leading whitespace
 770        buffer.edit_with_autoindent([(Point::new(3, 0)..Point::new(3, 12), "")], cx);
 771        assert_eq!(
 772            buffer.text(),
 773            "
 774            fn a() {
 775                {
 776                    b()?
 777
 778                Ok(())
 779            }
 780            "
 781            .unindent()
 782        );
 783        buffer
 784    });
 785}
 786
 787#[gpui::test]
 788fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 789    cx.set_global(Settings::test(cx));
 790    cx.add_model(|cx| {
 791        let text = "
 792            fn a() {}
 793        "
 794        .unindent();
 795
 796        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 797
 798        buffer.edit_with_autoindent([(5..5, "\nb")], cx);
 799        assert_eq!(
 800            buffer.text(),
 801            "
 802                fn a(
 803                    b) {}
 804            "
 805            .unindent()
 806        );
 807
 808        // The indentation suggestion changed because `@end` node (a close paren)
 809        // is now at the beginning of the line.
 810        buffer.edit_with_autoindent([(Point::new(1, 4)..Point::new(1, 5), "")], cx);
 811        assert_eq!(
 812            buffer.text(),
 813            "
 814                fn a(
 815                ) {}
 816            "
 817            .unindent()
 818        );
 819
 820        buffer
 821    });
 822}
 823
 824#[gpui::test]
 825fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 826    cx.set_global(Settings::test(cx));
 827    cx.add_model(|cx| {
 828        let text = "a\nb";
 829        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 830        buffer.edit_with_autoindent([(0..1, "\n"), (2..3, "\n")], cx);
 831        assert_eq!(buffer.text(), "\n\n\n");
 832        buffer
 833    });
 834}
 835
 836#[gpui::test]
 837fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 838    cx.set_global(Settings::test(cx));
 839    cx.add_model(|cx| {
 840        let text = "
 841            const a: usize = 1;
 842            fn b() {
 843                if c {
 844                    let d = 2;
 845                }
 846            }
 847        "
 848        .unindent();
 849
 850        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 851        buffer.edit_with_autoindent(
 852            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
 853            cx,
 854        );
 855        assert_eq!(
 856            buffer.text(),
 857            "
 858                const a: usize = 1;
 859                fn b() {
 860                    if c {
 861                        e(
 862                            f()
 863                        );
 864                        let d = 2;
 865                    }
 866                }
 867            "
 868            .unindent()
 869        );
 870
 871        buffer
 872    });
 873}
 874
 875#[gpui::test]
 876fn test_autoindent_preserves_relative_indentation_in_multi_line_insertion(
 877    cx: &mut MutableAppContext,
 878) {
 879    cx.set_global(Settings::test(cx));
 880    cx.add_model(|cx| {
 881        let text = "
 882            fn a() {
 883                b();
 884            }
 885        "
 886        .unindent();
 887        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 888
 889        let pasted_text = r#"
 890            "
 891              c
 892                d
 893                  e
 894            "
 895        "#
 896        .unindent();
 897
 898        // insert at the beginning of a line
 899        buffer.edit_with_autoindent(
 900            [(Point::new(2, 0)..Point::new(2, 0), pasted_text.clone())],
 901            cx,
 902        );
 903        assert_eq!(
 904            buffer.text(),
 905            r#"
 906            fn a() {
 907                b();
 908                "
 909                  c
 910                    d
 911                      e
 912                "
 913            }
 914            "#
 915            .unindent()
 916        );
 917
 918        buffer
 919    });
 920}
 921
 922#[gpui::test]
 923fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
 924    cx.set_global(Settings::test(cx));
 925    cx.add_model(|cx| {
 926        let text = "
 927            * one
 928                - a
 929                - b
 930            * two
 931        "
 932        .unindent();
 933
 934        let mut buffer = Buffer::new(0, text, cx).with_language(
 935            Arc::new(Language::new(
 936                LanguageConfig {
 937                    name: "Markdown".into(),
 938                    ..Default::default()
 939                },
 940                Some(tree_sitter_json::language()),
 941            )),
 942            cx,
 943        );
 944        buffer.edit_with_autoindent([(Point::new(3, 0)..Point::new(3, 0), "\n")], cx);
 945        assert_eq!(
 946            buffer.text(),
 947            "
 948            * one
 949                - a
 950                - b
 951
 952            * two
 953            "
 954            .unindent()
 955        );
 956        buffer
 957    });
 958}
 959
 960#[gpui::test]
 961fn test_serialization(cx: &mut gpui::MutableAppContext) {
 962    let mut now = Instant::now();
 963
 964    let buffer1 = cx.add_model(|cx| {
 965        let mut buffer = Buffer::new(0, "abc", cx);
 966        buffer.edit([(3..3, "D")], cx);
 967
 968        now += Duration::from_secs(1);
 969        buffer.start_transaction_at(now);
 970        buffer.edit([(4..4, "E")], cx);
 971        buffer.end_transaction_at(now, cx);
 972        assert_eq!(buffer.text(), "abcDE");
 973
 974        buffer.undo(cx);
 975        assert_eq!(buffer.text(), "abcD");
 976
 977        buffer.edit([(4..4, "F")], cx);
 978        assert_eq!(buffer.text(), "abcDF");
 979        buffer
 980    });
 981    assert_eq!(buffer1.read(cx).text(), "abcDF");
 982
 983    let message = buffer1.read(cx).to_proto();
 984    let buffer2 = cx.add_model(|cx| Buffer::from_proto(1, message, None, cx).unwrap());
 985    assert_eq!(buffer2.read(cx).text(), "abcDF");
 986}
 987
 988#[gpui::test(iterations = 100)]
 989fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
 990    let min_peers = env::var("MIN_PEERS")
 991        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
 992        .unwrap_or(1);
 993    let max_peers = env::var("MAX_PEERS")
 994        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
 995        .unwrap_or(5);
 996    let operations = env::var("OPERATIONS")
 997        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
 998        .unwrap_or(10);
 999
1000    let base_text_len = rng.gen_range(0..10);
1001    let base_text = RandomCharIter::new(&mut rng)
1002        .take(base_text_len)
1003        .collect::<String>();
1004    let mut replica_ids = Vec::new();
1005    let mut buffers = Vec::new();
1006    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1007    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1008
1009    for i in 0..rng.gen_range(min_peers..=max_peers) {
1010        let buffer = cx.add_model(|cx| {
1011            let mut buffer =
1012                Buffer::from_proto(i as ReplicaId, base_buffer.read(cx).to_proto(), None, cx)
1013                    .unwrap();
1014            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1015            let network = network.clone();
1016            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1017                if let Event::Operation(op) = event {
1018                    network
1019                        .borrow_mut()
1020                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(&op)]);
1021                }
1022            })
1023            .detach();
1024            buffer
1025        });
1026        buffers.push(buffer);
1027        replica_ids.push(i as ReplicaId);
1028        network.borrow_mut().add_peer(i as ReplicaId);
1029        log::info!("Adding initial peer with replica id {}", i);
1030    }
1031
1032    log::info!("initial text: {:?}", base_text);
1033
1034    let mut now = Instant::now();
1035    let mut mutation_count = operations;
1036    let mut next_diagnostic_id = 0;
1037    let mut active_selections = BTreeMap::default();
1038    loop {
1039        let replica_index = rng.gen_range(0..replica_ids.len());
1040        let replica_id = replica_ids[replica_index];
1041        let buffer = &mut buffers[replica_index];
1042        let mut new_buffer = None;
1043        match rng.gen_range(0..100) {
1044            0..=29 if mutation_count != 0 => {
1045                buffer.update(cx, |buffer, cx| {
1046                    buffer.start_transaction_at(now);
1047                    buffer.randomly_edit(&mut rng, 5, cx);
1048                    buffer.end_transaction_at(now, cx);
1049                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1050                });
1051                mutation_count -= 1;
1052            }
1053            30..=39 if mutation_count != 0 => {
1054                buffer.update(cx, |buffer, cx| {
1055                    let mut selections = Vec::new();
1056                    for id in 0..rng.gen_range(1..=5) {
1057                        let range = buffer.random_byte_range(0, &mut rng);
1058                        selections.push(Selection {
1059                            id,
1060                            start: buffer.anchor_before(range.start),
1061                            end: buffer.anchor_before(range.end),
1062                            reversed: false,
1063                            goal: SelectionGoal::None,
1064                        });
1065                    }
1066                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1067                    log::info!(
1068                        "peer {} setting active selections: {:?}",
1069                        replica_id,
1070                        selections
1071                    );
1072                    active_selections.insert(replica_id, selections.clone());
1073                    buffer.set_active_selections(selections, false, cx);
1074                });
1075                mutation_count -= 1;
1076            }
1077            40..=49 if mutation_count != 0 && replica_id == 0 => {
1078                let entry_count = rng.gen_range(1..=5);
1079                buffer.update(cx, |buffer, cx| {
1080                    let diagnostics = DiagnosticSet::new(
1081                        (0..entry_count).map(|_| {
1082                            let range = buffer.random_byte_range(0, &mut rng);
1083                            let range = range.to_point_utf16(buffer);
1084                            DiagnosticEntry {
1085                                range,
1086                                diagnostic: Diagnostic {
1087                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1088                                    ..Default::default()
1089                                },
1090                            }
1091                        }),
1092                        buffer,
1093                    );
1094                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1095                    buffer.update_diagnostics(diagnostics, cx);
1096                });
1097                mutation_count -= 1;
1098            }
1099            50..=59 if replica_ids.len() < max_peers => {
1100                let old_buffer = buffer.read(cx).to_proto();
1101                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1102                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1103                    .choose(&mut rng)
1104                    .unwrap();
1105                log::info!(
1106                    "Adding new replica {} (replicating from {})",
1107                    new_replica_id,
1108                    replica_id
1109                );
1110                new_buffer = Some(cx.add_model(|cx| {
1111                    let mut new_buffer =
1112                        Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap();
1113                    log::info!(
1114                        "New replica {} text: {:?}",
1115                        new_buffer.replica_id(),
1116                        new_buffer.text()
1117                    );
1118                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1119                    let network = network.clone();
1120                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1121                        if let Event::Operation(op) = event {
1122                            network.borrow_mut().broadcast(
1123                                buffer.replica_id(),
1124                                vec![proto::serialize_operation(&op)],
1125                            );
1126                        }
1127                    })
1128                    .detach();
1129                    new_buffer
1130                }));
1131                network.borrow_mut().replicate(replica_id, new_replica_id);
1132
1133                if new_replica_id as usize == replica_ids.len() {
1134                    replica_ids.push(new_replica_id);
1135                } else {
1136                    let new_buffer = new_buffer.take().unwrap();
1137                    while network.borrow().has_unreceived(new_replica_id) {
1138                        let ops = network
1139                            .borrow_mut()
1140                            .receive(new_replica_id)
1141                            .into_iter()
1142                            .map(|op| proto::deserialize_operation(op).unwrap());
1143                        if ops.len() > 0 {
1144                            log::info!(
1145                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1146                                new_replica_id,
1147                                buffer.read(cx).version(),
1148                                ops.len(),
1149                                ops
1150                            );
1151                            new_buffer.update(cx, |new_buffer, cx| {
1152                                new_buffer.apply_ops(ops, cx).unwrap();
1153                            });
1154                        }
1155                    }
1156                    buffers[new_replica_id as usize] = new_buffer;
1157                }
1158            }
1159            60..=69 if mutation_count != 0 => {
1160                buffer.update(cx, |buffer, cx| {
1161                    buffer.randomly_undo_redo(&mut rng, cx);
1162                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1163                });
1164                mutation_count -= 1;
1165            }
1166            _ if network.borrow().has_unreceived(replica_id) => {
1167                let ops = network
1168                    .borrow_mut()
1169                    .receive(replica_id)
1170                    .into_iter()
1171                    .map(|op| proto::deserialize_operation(op).unwrap());
1172                if ops.len() > 0 {
1173                    log::info!(
1174                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1175                        replica_id,
1176                        buffer.read(cx).version(),
1177                        ops.len(),
1178                        ops
1179                    );
1180                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1181                }
1182            }
1183            _ => {}
1184        }
1185
1186        now += Duration::from_millis(rng.gen_range(0..=200));
1187        buffers.extend(new_buffer);
1188
1189        for buffer in &buffers {
1190            buffer.read(cx).check_invariants();
1191        }
1192
1193        if mutation_count == 0 && network.borrow().is_idle() {
1194            break;
1195        }
1196    }
1197
1198    let first_buffer = buffers[0].read(cx).snapshot();
1199    for buffer in &buffers[1..] {
1200        let buffer = buffer.read(cx).snapshot();
1201        assert_eq!(
1202            buffer.version(),
1203            first_buffer.version(),
1204            "Replica {} version != Replica 0 version",
1205            buffer.replica_id()
1206        );
1207        assert_eq!(
1208            buffer.text(),
1209            first_buffer.text(),
1210            "Replica {} text != Replica 0 text",
1211            buffer.replica_id()
1212        );
1213        assert_eq!(
1214            buffer
1215                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1216                .collect::<Vec<_>>(),
1217            first_buffer
1218                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1219                .collect::<Vec<_>>(),
1220            "Replica {} diagnostics != Replica 0 diagnostics",
1221            buffer.replica_id()
1222        );
1223    }
1224
1225    for buffer in &buffers {
1226        let buffer = buffer.read(cx).snapshot();
1227        let actual_remote_selections = buffer
1228            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1229            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1230            .collect::<Vec<_>>();
1231        let expected_remote_selections = active_selections
1232            .iter()
1233            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1234            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1235            .collect::<Vec<_>>();
1236        assert_eq!(
1237            actual_remote_selections,
1238            expected_remote_selections,
1239            "Replica {} remote selections != expected selections",
1240            buffer.replica_id()
1241        );
1242    }
1243}
1244
1245#[test]
1246fn test_contiguous_ranges() {
1247    assert_eq!(
1248        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1249        &[1..4, 5..7, 9..13]
1250    );
1251
1252    // Respects the `max_len` parameter
1253    assert_eq!(
1254        contiguous_ranges(
1255            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1256            3
1257        )
1258        .collect::<Vec<_>>(),
1259        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1260    );
1261}
1262
1263impl Buffer {
1264    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1265        &self,
1266        range: Range<T>,
1267    ) -> Option<(Range<Point>, Range<Point>)> {
1268        self.snapshot()
1269            .enclosing_bracket_ranges(range)
1270            .map(|(start, end)| {
1271                let point_start = start.start.to_point(self)..start.end.to_point(self);
1272                let point_end = end.start.to_point(self)..end.end.to_point(self);
1273                (point_start, point_end)
1274            })
1275    }
1276}
1277
1278fn rust_lang() -> Language {
1279    Language::new(
1280        LanguageConfig {
1281            name: "Rust".into(),
1282            path_suffixes: vec!["rs".to_string()],
1283            ..Default::default()
1284        },
1285        Some(tree_sitter_rust::language()),
1286    )
1287    .with_indents_query(
1288        r#"
1289        (call_expression) @indent
1290        (field_expression) @indent
1291        (_ "(" ")" @end) @indent
1292        (_ "{" "}" @end) @indent
1293        "#,
1294    )
1295    .unwrap()
1296    .with_brackets_query(
1297        r#"
1298        ("{" @open "}" @close)
1299        "#,
1300    )
1301    .unwrap()
1302    .with_outline_query(
1303        r#"
1304        (struct_item
1305            "struct" @context
1306            name: (_) @name) @item
1307        (enum_item
1308            "enum" @context
1309            name: (_) @name) @item
1310        (enum_variant
1311            name: (_) @name) @item
1312        (field_declaration
1313            name: (_) @name) @item
1314        (impl_item
1315            "impl" @context
1316            trait: (_)? @name
1317            "for"? @context
1318            type: (_) @name) @item
1319        (function_item
1320            "fn" @context
1321            name: (_) @name) @item
1322        (mod_item
1323            "mod" @context
1324            name: (_) @name) @item
1325        "#,
1326    )
1327    .unwrap()
1328}
1329
1330fn json_lang() -> Language {
1331    Language::new(
1332        LanguageConfig {
1333            name: "Json".into(),
1334            path_suffixes: vec!["js".to_string()],
1335            ..Default::default()
1336        },
1337        Some(tree_sitter_json::language()),
1338    )
1339}
1340
1341fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1342    buffer.read_with(cx, |buffer, _| {
1343        buffer.syntax_tree().unwrap().root_node().to_sexp()
1344    })
1345}
1346
1347fn empty(point: Point) -> Range<Point> {
1348    point..point
1349}