tests.rs

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