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