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_preserves_relative_indentation_in_multi_line_insertion(
 904    cx: &mut MutableAppContext,
 905) {
 906    cx.add_model(|cx| {
 907        let text = "
 908            fn a() {
 909                b();
 910            }
 911        "
 912        .unindent();
 913        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 914
 915        let pasted_text = r#"
 916            "
 917              c
 918                d
 919                  e
 920            "
 921        "#
 922        .unindent();
 923
 924        // insert at the beginning of a line
 925        buffer.edit_with_autoindent(
 926            [(Point::new(2, 0)..Point::new(2, 0), pasted_text.clone())],
 927            IndentSize::spaces(4),
 928            cx,
 929        );
 930        assert_eq!(
 931            buffer.text(),
 932            r#"
 933            fn a() {
 934                b();
 935                "
 936                  c
 937                    d
 938                      e
 939                "
 940            }
 941            "#
 942            .unindent()
 943        );
 944
 945        buffer
 946    });
 947}
 948
 949#[gpui::test]
 950fn test_autoindent_disabled(cx: &mut MutableAppContext) {
 951    cx.add_model(|cx| {
 952        let text = "
 953            * one
 954                - a
 955                - b
 956            * two
 957        "
 958        .unindent();
 959
 960        let mut buffer = Buffer::new(0, text, cx).with_language(
 961            Arc::new(Language::new(
 962                LanguageConfig {
 963                    name: "Markdown".into(),
 964                    ..Default::default()
 965                },
 966                Some(tree_sitter_json::language()),
 967            )),
 968            cx,
 969        );
 970        buffer.edit_with_autoindent(
 971            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
 972            IndentSize::spaces(4),
 973            cx,
 974        );
 975        assert_eq!(
 976            buffer.text(),
 977            "
 978            * one
 979                - a
 980                - b
 981
 982            * two
 983            "
 984            .unindent()
 985        );
 986        buffer
 987    });
 988}
 989
 990#[gpui::test]
 991fn test_serialization(cx: &mut gpui::MutableAppContext) {
 992    let mut now = Instant::now();
 993
 994    let buffer1 = cx.add_model(|cx| {
 995        let mut buffer = Buffer::new(0, "abc", cx);
 996        buffer.edit([(3..3, "D")], cx);
 997
 998        now += Duration::from_secs(1);
 999        buffer.start_transaction_at(now);
1000        buffer.edit([(4..4, "E")], cx);
1001        buffer.end_transaction_at(now, cx);
1002        assert_eq!(buffer.text(), "abcDE");
1003
1004        buffer.undo(cx);
1005        assert_eq!(buffer.text(), "abcD");
1006
1007        buffer.edit([(4..4, "F")], cx);
1008        assert_eq!(buffer.text(), "abcDF");
1009        buffer
1010    });
1011    assert_eq!(buffer1.read(cx).text(), "abcDF");
1012
1013    let message = buffer1.read(cx).to_proto();
1014    let buffer2 = cx.add_model(|cx| Buffer::from_proto(1, message, None, cx).unwrap());
1015    assert_eq!(buffer2.read(cx).text(), "abcDF");
1016}
1017
1018#[gpui::test(iterations = 100)]
1019fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1020    let min_peers = env::var("MIN_PEERS")
1021        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1022        .unwrap_or(1);
1023    let max_peers = env::var("MAX_PEERS")
1024        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1025        .unwrap_or(5);
1026    let operations = env::var("OPERATIONS")
1027        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1028        .unwrap_or(10);
1029
1030    let base_text_len = rng.gen_range(0..10);
1031    let base_text = RandomCharIter::new(&mut rng)
1032        .take(base_text_len)
1033        .collect::<String>();
1034    let mut replica_ids = Vec::new();
1035    let mut buffers = Vec::new();
1036    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1037    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1038
1039    for i in 0..rng.gen_range(min_peers..=max_peers) {
1040        let buffer = cx.add_model(|cx| {
1041            let mut buffer =
1042                Buffer::from_proto(i as ReplicaId, base_buffer.read(cx).to_proto(), None, cx)
1043                    .unwrap();
1044            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1045            let network = network.clone();
1046            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1047                if let Event::Operation(op) = event {
1048                    network
1049                        .borrow_mut()
1050                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(&op)]);
1051                }
1052            })
1053            .detach();
1054            buffer
1055        });
1056        buffers.push(buffer);
1057        replica_ids.push(i as ReplicaId);
1058        network.borrow_mut().add_peer(i as ReplicaId);
1059        log::info!("Adding initial peer with replica id {}", i);
1060    }
1061
1062    log::info!("initial text: {:?}", base_text);
1063
1064    let mut now = Instant::now();
1065    let mut mutation_count = operations;
1066    let mut next_diagnostic_id = 0;
1067    let mut active_selections = BTreeMap::default();
1068    loop {
1069        let replica_index = rng.gen_range(0..replica_ids.len());
1070        let replica_id = replica_ids[replica_index];
1071        let buffer = &mut buffers[replica_index];
1072        let mut new_buffer = None;
1073        match rng.gen_range(0..100) {
1074            0..=29 if mutation_count != 0 => {
1075                buffer.update(cx, |buffer, cx| {
1076                    buffer.start_transaction_at(now);
1077                    buffer.randomly_edit(&mut rng, 5, cx);
1078                    buffer.end_transaction_at(now, cx);
1079                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1080                });
1081                mutation_count -= 1;
1082            }
1083            30..=39 if mutation_count != 0 => {
1084                buffer.update(cx, |buffer, cx| {
1085                    let mut selections = Vec::new();
1086                    for id in 0..rng.gen_range(1..=5) {
1087                        let range = buffer.random_byte_range(0, &mut rng);
1088                        selections.push(Selection {
1089                            id,
1090                            start: buffer.anchor_before(range.start),
1091                            end: buffer.anchor_before(range.end),
1092                            reversed: false,
1093                            goal: SelectionGoal::None,
1094                        });
1095                    }
1096                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1097                    log::info!(
1098                        "peer {} setting active selections: {:?}",
1099                        replica_id,
1100                        selections
1101                    );
1102                    active_selections.insert(replica_id, selections.clone());
1103                    buffer.set_active_selections(selections, false, cx);
1104                });
1105                mutation_count -= 1;
1106            }
1107            40..=49 if mutation_count != 0 && replica_id == 0 => {
1108                let entry_count = rng.gen_range(1..=5);
1109                buffer.update(cx, |buffer, cx| {
1110                    let diagnostics = DiagnosticSet::new(
1111                        (0..entry_count).map(|_| {
1112                            let range = buffer.random_byte_range(0, &mut rng);
1113                            let range = range.to_point_utf16(buffer);
1114                            DiagnosticEntry {
1115                                range,
1116                                diagnostic: Diagnostic {
1117                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1118                                    ..Default::default()
1119                                },
1120                            }
1121                        }),
1122                        buffer,
1123                    );
1124                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1125                    buffer.update_diagnostics(diagnostics, cx);
1126                });
1127                mutation_count -= 1;
1128            }
1129            50..=59 if replica_ids.len() < max_peers => {
1130                let old_buffer = buffer.read(cx).to_proto();
1131                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1132                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1133                    .choose(&mut rng)
1134                    .unwrap();
1135                log::info!(
1136                    "Adding new replica {} (replicating from {})",
1137                    new_replica_id,
1138                    replica_id
1139                );
1140                new_buffer = Some(cx.add_model(|cx| {
1141                    let mut new_buffer =
1142                        Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap();
1143                    log::info!(
1144                        "New replica {} text: {:?}",
1145                        new_buffer.replica_id(),
1146                        new_buffer.text()
1147                    );
1148                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1149                    let network = network.clone();
1150                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1151                        if let Event::Operation(op) = event {
1152                            network.borrow_mut().broadcast(
1153                                buffer.replica_id(),
1154                                vec![proto::serialize_operation(&op)],
1155                            );
1156                        }
1157                    })
1158                    .detach();
1159                    new_buffer
1160                }));
1161                network.borrow_mut().replicate(replica_id, new_replica_id);
1162
1163                if new_replica_id as usize == replica_ids.len() {
1164                    replica_ids.push(new_replica_id);
1165                } else {
1166                    let new_buffer = new_buffer.take().unwrap();
1167                    while network.borrow().has_unreceived(new_replica_id) {
1168                        let ops = network
1169                            .borrow_mut()
1170                            .receive(new_replica_id)
1171                            .into_iter()
1172                            .map(|op| proto::deserialize_operation(op).unwrap());
1173                        if ops.len() > 0 {
1174                            log::info!(
1175                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1176                                new_replica_id,
1177                                buffer.read(cx).version(),
1178                                ops.len(),
1179                                ops
1180                            );
1181                            new_buffer.update(cx, |new_buffer, cx| {
1182                                new_buffer.apply_ops(ops, cx).unwrap();
1183                            });
1184                        }
1185                    }
1186                    buffers[new_replica_id as usize] = new_buffer;
1187                }
1188            }
1189            60..=69 if mutation_count != 0 => {
1190                buffer.update(cx, |buffer, cx| {
1191                    buffer.randomly_undo_redo(&mut rng, cx);
1192                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1193                });
1194                mutation_count -= 1;
1195            }
1196            _ if network.borrow().has_unreceived(replica_id) => {
1197                let ops = network
1198                    .borrow_mut()
1199                    .receive(replica_id)
1200                    .into_iter()
1201                    .map(|op| proto::deserialize_operation(op).unwrap());
1202                if ops.len() > 0 {
1203                    log::info!(
1204                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1205                        replica_id,
1206                        buffer.read(cx).version(),
1207                        ops.len(),
1208                        ops
1209                    );
1210                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1211                }
1212            }
1213            _ => {}
1214        }
1215
1216        now += Duration::from_millis(rng.gen_range(0..=200));
1217        buffers.extend(new_buffer);
1218
1219        for buffer in &buffers {
1220            buffer.read(cx).check_invariants();
1221        }
1222
1223        if mutation_count == 0 && network.borrow().is_idle() {
1224            break;
1225        }
1226    }
1227
1228    let first_buffer = buffers[0].read(cx).snapshot();
1229    for buffer in &buffers[1..] {
1230        let buffer = buffer.read(cx).snapshot();
1231        assert_eq!(
1232            buffer.version(),
1233            first_buffer.version(),
1234            "Replica {} version != Replica 0 version",
1235            buffer.replica_id()
1236        );
1237        assert_eq!(
1238            buffer.text(),
1239            first_buffer.text(),
1240            "Replica {} text != Replica 0 text",
1241            buffer.replica_id()
1242        );
1243        assert_eq!(
1244            buffer
1245                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1246                .collect::<Vec<_>>(),
1247            first_buffer
1248                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1249                .collect::<Vec<_>>(),
1250            "Replica {} diagnostics != Replica 0 diagnostics",
1251            buffer.replica_id()
1252        );
1253    }
1254
1255    for buffer in &buffers {
1256        let buffer = buffer.read(cx).snapshot();
1257        let actual_remote_selections = buffer
1258            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1259            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1260            .collect::<Vec<_>>();
1261        let expected_remote_selections = active_selections
1262            .iter()
1263            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1264            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1265            .collect::<Vec<_>>();
1266        assert_eq!(
1267            actual_remote_selections,
1268            expected_remote_selections,
1269            "Replica {} remote selections != expected selections",
1270            buffer.replica_id()
1271        );
1272    }
1273}
1274
1275#[test]
1276fn test_contiguous_ranges() {
1277    assert_eq!(
1278        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1279        &[1..4, 5..7, 9..13]
1280    );
1281
1282    // Respects the `max_len` parameter
1283    assert_eq!(
1284        contiguous_ranges(
1285            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1286            3
1287        )
1288        .collect::<Vec<_>>(),
1289        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1290    );
1291}
1292
1293impl Buffer {
1294    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1295        &self,
1296        range: Range<T>,
1297    ) -> Option<(Range<Point>, Range<Point>)> {
1298        self.snapshot()
1299            .enclosing_bracket_ranges(range)
1300            .map(|(start, end)| {
1301                let point_start = start.start.to_point(self)..start.end.to_point(self);
1302                let point_end = end.start.to_point(self)..end.end.to_point(self);
1303                (point_start, point_end)
1304            })
1305    }
1306}
1307
1308fn rust_lang() -> Language {
1309    Language::new(
1310        LanguageConfig {
1311            name: "Rust".into(),
1312            path_suffixes: vec!["rs".to_string()],
1313            ..Default::default()
1314        },
1315        Some(tree_sitter_rust::language()),
1316    )
1317    .with_indents_query(
1318        r#"
1319        (call_expression) @indent
1320        (field_expression) @indent
1321        (_ "(" ")" @end) @indent
1322        (_ "{" "}" @end) @indent
1323        "#,
1324    )
1325    .unwrap()
1326    .with_brackets_query(
1327        r#"
1328        ("{" @open "}" @close)
1329        "#,
1330    )
1331    .unwrap()
1332    .with_outline_query(
1333        r#"
1334        (struct_item
1335            "struct" @context
1336            name: (_) @name) @item
1337        (enum_item
1338            "enum" @context
1339            name: (_) @name) @item
1340        (enum_variant
1341            name: (_) @name) @item
1342        (field_declaration
1343            name: (_) @name) @item
1344        (impl_item
1345            "impl" @context
1346            trait: (_)? @name
1347            "for"? @context
1348            type: (_) @name) @item
1349        (function_item
1350            "fn" @context
1351            name: (_) @name) @item
1352        (mod_item
1353            "mod" @context
1354            name: (_) @name) @item
1355        "#,
1356    )
1357    .unwrap()
1358}
1359
1360fn json_lang() -> Language {
1361    Language::new(
1362        LanguageConfig {
1363            name: "Json".into(),
1364            path_suffixes: vec!["js".to_string()],
1365            ..Default::default()
1366        },
1367        Some(tree_sitter_json::language()),
1368    )
1369}
1370
1371fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1372    buffer.read_with(cx, |buffer, _| {
1373        buffer.syntax_tree().unwrap().root_node().to_sexp()
1374    })
1375}
1376
1377fn empty(point: Point) -> Range<Point> {
1378    point..point
1379}