tests.rs

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