buffer_tests.rs

   1use super::*;
   2use crate::language_settings::{
   3    AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent,
   4};
   5use crate::Buffer;
   6use clock::ReplicaId;
   7use collections::BTreeMap;
   8use futures::FutureExt as _;
   9use gpui::{AppContext, BorrowAppContext, Model};
  10use gpui::{Context, TestAppContext};
  11use indoc::indoc;
  12use proto::deserialize_operation;
  13use rand::prelude::*;
  14use regex::RegexBuilder;
  15use settings::SettingsStore;
  16use std::{
  17    env,
  18    ops::Range,
  19    time::{Duration, Instant},
  20};
  21use text::network::Network;
  22use text::{BufferId, LineEnding, LineIndent};
  23use text::{Point, ToPoint};
  24use unindent::Unindent as _;
  25use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  26
  27lazy_static! {
  28    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  29        .multi_line(true)
  30        .build()
  31        .unwrap();
  32}
  33
  34#[cfg(test)]
  35#[ctor::ctor]
  36fn init_logger() {
  37    if std::env::var("RUST_LOG").is_ok() {
  38        env_logger::init();
  39    }
  40}
  41
  42#[gpui::test]
  43fn test_line_endings(cx: &mut gpui::AppContext) {
  44    init_settings(cx, |_| {});
  45
  46    cx.new_model(|cx| {
  47        let mut buffer =
  48            Buffer::local("one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  49        assert_eq!(buffer.text(), "one\ntwo\nthree");
  50        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  51
  52        buffer.check_invariants();
  53        buffer.edit(
  54            [(buffer.len()..buffer.len(), "\r\nfour")],
  55            Some(AutoindentMode::EachLine),
  56            cx,
  57        );
  58        buffer.edit([(0..0, "zero\r\n")], None, cx);
  59        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  60        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  61        buffer.check_invariants();
  62
  63        buffer
  64    });
  65}
  66
  67#[gpui::test]
  68fn test_select_language(cx: &mut AppContext) {
  69    init_settings(cx, |_| {});
  70
  71    let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
  72    registry.add(Arc::new(Language::new(
  73        LanguageConfig {
  74            name: "Rust".into(),
  75            matcher: LanguageMatcher {
  76                path_suffixes: vec!["rs".to_string()],
  77                ..Default::default()
  78            },
  79            ..Default::default()
  80        },
  81        Some(tree_sitter_rust::language()),
  82    )));
  83    registry.add(Arc::new(Language::new(
  84        LanguageConfig {
  85            name: "Make".into(),
  86            matcher: LanguageMatcher {
  87                path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  88                ..Default::default()
  89            },
  90            ..Default::default()
  91        },
  92        Some(tree_sitter_rust::language()),
  93    )));
  94
  95    // matching file extension
  96    assert_eq!(
  97        registry
  98            .language_for_file(&file("src/lib.rs"), None, cx)
  99            .now_or_never()
 100            .and_then(|l| Some(l.ok()?.name())),
 101        Some("Rust".into())
 102    );
 103    assert_eq!(
 104        registry
 105            .language_for_file(&file("src/lib.mk"), None, cx)
 106            .now_or_never()
 107            .and_then(|l| Some(l.ok()?.name())),
 108        Some("Make".into())
 109    );
 110
 111    // matching filename
 112    assert_eq!(
 113        registry
 114            .language_for_file(&file("src/Makefile"), None, cx)
 115            .now_or_never()
 116            .and_then(|l| Some(l.ok()?.name())),
 117        Some("Make".into())
 118    );
 119
 120    // matching suffix that is not the full file extension or filename
 121    assert_eq!(
 122        registry
 123            .language_for_file(&file("zed/cars"), None, cx)
 124            .now_or_never()
 125            .and_then(|l| Some(l.ok()?.name())),
 126        None
 127    );
 128    assert_eq!(
 129        registry
 130            .language_for_file(&file("zed/a.cars"), None, cx)
 131            .now_or_never()
 132            .and_then(|l| Some(l.ok()?.name())),
 133        None
 134    );
 135    assert_eq!(
 136        registry
 137            .language_for_file(&file("zed/sumk"), None, cx)
 138            .now_or_never()
 139            .and_then(|l| Some(l.ok()?.name())),
 140        None
 141    );
 142}
 143
 144#[gpui::test(iterations = 10)]
 145async fn test_first_line_pattern(cx: &mut TestAppContext) {
 146    cx.update(|cx| init_settings(cx, |_| {}));
 147
 148    let languages = LanguageRegistry::test(cx.executor());
 149    let languages = Arc::new(languages);
 150
 151    languages.register_test_language(LanguageConfig {
 152        name: "JavaScript".into(),
 153        matcher: LanguageMatcher {
 154            path_suffixes: vec!["js".into()],
 155            first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()),
 156        },
 157        ..Default::default()
 158    });
 159
 160    cx.read(|cx| languages.language_for_file(&file("the/script"), None, cx))
 161        .await
 162        .unwrap_err();
 163    cx.read(|cx| languages.language_for_file(&file("the/script"), Some(&"nothing".into()), cx))
 164        .await
 165        .unwrap_err();
 166    assert_eq!(
 167        cx.read(|cx| languages.language_for_file(
 168            &file("the/script"),
 169            Some(&"#!/bin/env node".into()),
 170            cx
 171        ))
 172        .await
 173        .unwrap()
 174        .name()
 175        .as_ref(),
 176        "JavaScript"
 177    );
 178}
 179
 180#[gpui::test]
 181async fn test_language_for_file_with_custom_file_types(cx: &mut TestAppContext) {
 182    cx.update(|cx| {
 183        init_settings(cx, |settings| {
 184            settings.file_types.extend([
 185                ("TypeScript".into(), vec!["js".into()]),
 186                ("C++".into(), vec!["c".into()]),
 187                (
 188                    "Dockerfile".into(),
 189                    vec!["Dockerfile".into(), "Dockerfile.*".into()],
 190                ),
 191            ]);
 192        })
 193    });
 194
 195    let languages = Arc::new(LanguageRegistry::test(cx.executor()));
 196
 197    for config in [
 198        LanguageConfig {
 199            name: "JavaScript".into(),
 200            matcher: LanguageMatcher {
 201                path_suffixes: vec!["js".to_string()],
 202                ..Default::default()
 203            },
 204            ..Default::default()
 205        },
 206        LanguageConfig {
 207            name: "TypeScript".into(),
 208            matcher: LanguageMatcher {
 209                path_suffixes: vec!["js".to_string()],
 210                ..Default::default()
 211            },
 212            ..Default::default()
 213        },
 214        LanguageConfig {
 215            name: "C++".into(),
 216            matcher: LanguageMatcher {
 217                path_suffixes: vec!["cpp".to_string()],
 218                ..Default::default()
 219            },
 220            ..Default::default()
 221        },
 222        LanguageConfig {
 223            name: "C".into(),
 224            matcher: LanguageMatcher {
 225                path_suffixes: vec!["c".to_string()],
 226                ..Default::default()
 227            },
 228            ..Default::default()
 229        },
 230        LanguageConfig {
 231            name: "Dockerfile".into(),
 232            matcher: LanguageMatcher {
 233                path_suffixes: vec!["Dockerfile".to_string()],
 234                ..Default::default()
 235            },
 236            ..Default::default()
 237        },
 238    ] {
 239        languages.add(Arc::new(Language::new(config, None)));
 240    }
 241
 242    let language = cx
 243        .read(|cx| languages.language_for_file(&file("foo.js"), None, cx))
 244        .await
 245        .unwrap();
 246    assert_eq!(language.name().as_ref(), "TypeScript");
 247    let language = cx
 248        .read(|cx| languages.language_for_file(&file("foo.c"), None, cx))
 249        .await
 250        .unwrap();
 251    assert_eq!(language.name().as_ref(), "C++");
 252    let language = cx
 253        .read(|cx| languages.language_for_file(&file("Dockerfile.dev"), None, cx))
 254        .await
 255        .unwrap();
 256    assert_eq!(language.name().as_ref(), "Dockerfile");
 257}
 258
 259fn file(path: &str) -> Arc<dyn File> {
 260    Arc::new(TestFile {
 261        path: Path::new(path).into(),
 262        root_name: "zed".into(),
 263    })
 264}
 265
 266#[gpui::test]
 267fn test_edit_events(cx: &mut gpui::AppContext) {
 268    let mut now = Instant::now();
 269    let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
 270    let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
 271
 272    let buffer1 = cx.new_model(|cx| Buffer::local("abcdef", cx));
 273    let buffer2 = cx.new_model(|cx| {
 274        Buffer::remote(
 275            BufferId::from(cx.entity_id().as_non_zero_u64()),
 276            1,
 277            Capability::ReadWrite,
 278            "abcdef",
 279        )
 280    });
 281    let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
 282    buffer1.update(cx, {
 283        let buffer1_ops = buffer1_ops.clone();
 284        |buffer, cx| {
 285            let buffer_1_events = buffer_1_events.clone();
 286            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 287                Event::Operation(op) => buffer1_ops.lock().push(op),
 288                event => buffer_1_events.lock().push(event),
 289            })
 290            .detach();
 291            let buffer_2_events = buffer_2_events.clone();
 292            cx.subscribe(&buffer2, move |_, _, event, _| {
 293                buffer_2_events.lock().push(event.clone())
 294            })
 295            .detach();
 296
 297            // An edit emits an edited event, followed by a dirty changed event,
 298            // since the buffer was previously in a clean state.
 299            buffer.edit([(2..4, "XYZ")], None, cx);
 300
 301            // An empty transaction does not emit any events.
 302            buffer.start_transaction();
 303            buffer.end_transaction(cx);
 304
 305            // A transaction containing two edits emits one edited event.
 306            now += Duration::from_secs(1);
 307            buffer.start_transaction_at(now);
 308            buffer.edit([(5..5, "u")], None, cx);
 309            buffer.edit([(6..6, "w")], None, cx);
 310            buffer.end_transaction_at(now, cx);
 311
 312            // Undoing a transaction emits one edited event.
 313            buffer.undo(cx);
 314        }
 315    });
 316
 317    // Incorporating a set of remote ops emits a single edited event,
 318    // followed by a dirty changed event.
 319    buffer2.update(cx, |buffer, cx| {
 320        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 321    });
 322    assert_eq!(
 323        mem::take(&mut *buffer_1_events.lock()),
 324        vec![
 325            Event::Edited,
 326            Event::DirtyChanged,
 327            Event::Edited,
 328            Event::Edited,
 329        ]
 330    );
 331    assert_eq!(
 332        mem::take(&mut *buffer_2_events.lock()),
 333        vec![Event::Edited, Event::DirtyChanged]
 334    );
 335
 336    buffer1.update(cx, |buffer, cx| {
 337        // Undoing the first transaction emits edited event, followed by a
 338        // dirty changed event, since the buffer is again in a clean state.
 339        buffer.undo(cx);
 340    });
 341    // Incorporating the remote ops again emits a single edited event,
 342    // followed by a dirty changed event.
 343    buffer2.update(cx, |buffer, cx| {
 344        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 345    });
 346    assert_eq!(
 347        mem::take(&mut *buffer_1_events.lock()),
 348        vec![Event::Edited, Event::DirtyChanged,]
 349    );
 350    assert_eq!(
 351        mem::take(&mut *buffer_2_events.lock()),
 352        vec![Event::Edited, Event::DirtyChanged]
 353    );
 354}
 355
 356#[gpui::test]
 357async fn test_apply_diff(cx: &mut TestAppContext) {
 358    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 359    let buffer = cx.new_model(|cx| Buffer::local(text, cx));
 360    let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 361
 362    let text = "a\nccc\ndddd\nffffff\n";
 363    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 364    buffer.update(cx, |buffer, cx| {
 365        buffer.apply_diff(diff, cx).unwrap();
 366        assert_eq!(buffer.text(), text);
 367        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 368    });
 369
 370    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 371    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 372    buffer.update(cx, |buffer, cx| {
 373        buffer.apply_diff(diff, cx).unwrap();
 374        assert_eq!(buffer.text(), text);
 375        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 376    });
 377}
 378
 379#[gpui::test(iterations = 10)]
 380async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 381    let text = [
 382        "zero",     //
 383        "one  ",    // 2 trailing spaces
 384        "two",      //
 385        "three   ", // 3 trailing spaces
 386        "four",     //
 387        "five    ", // 4 trailing spaces
 388    ]
 389    .join("\n");
 390
 391    let buffer = cx.new_model(|cx| Buffer::local(text, cx));
 392
 393    // Spawn a task to format the buffer's whitespace.
 394    // Pause so that the foratting task starts running.
 395    let format = buffer.update(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 396    smol::future::yield_now().await;
 397
 398    // Edit the buffer while the normalization task is running.
 399    let version_before_edit = buffer.update(cx, |buffer, _| buffer.version());
 400    buffer.update(cx, |buffer, cx| {
 401        buffer.edit(
 402            [
 403                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 404                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 405            ],
 406            None,
 407            cx,
 408        );
 409    });
 410
 411    let format_diff = format.await;
 412    buffer.update(cx, |buffer, cx| {
 413        let version_before_format = format_diff.base_version.clone();
 414        buffer.apply_diff(format_diff, cx);
 415
 416        // The outcome depends on the order of concurrent tasks.
 417        //
 418        // If the edit occurred while searching for trailing whitespace ranges,
 419        // then the trailing whitespace region touched by the edit is left intact.
 420        if version_before_format == version_before_edit {
 421            assert_eq!(
 422                buffer.text(),
 423                [
 424                    "zEEero",      //
 425                    "one",         //
 426                    "two",         //
 427                    "threeEEE   ", //
 428                    "four",        //
 429                    "five",        //
 430                ]
 431                .join("\n")
 432            );
 433        }
 434        // Otherwise, all trailing whitespace is removed.
 435        else {
 436            assert_eq!(
 437                buffer.text(),
 438                [
 439                    "zEEero",   //
 440                    "one",      //
 441                    "two",      //
 442                    "threeEEE", //
 443                    "four",     //
 444                    "five",     //
 445                ]
 446                .join("\n")
 447            );
 448        }
 449    });
 450}
 451
 452#[gpui::test]
 453async fn test_reparse(cx: &mut gpui::TestAppContext) {
 454    let text = "fn a() {}";
 455    let buffer =
 456        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 457
 458    // Wait for the initial text to parse
 459    cx.executor().run_until_parked();
 460    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 461    assert_eq!(
 462        get_tree_sexp(&buffer, cx),
 463        concat!(
 464            "(source_file (function_item name: (identifier) ",
 465            "parameters: (parameters) ",
 466            "body: (block)))"
 467        )
 468    );
 469
 470    buffer.update(cx, |buffer, _| {
 471        buffer.set_sync_parse_timeout(Duration::ZERO)
 472    });
 473
 474    // Perform some edits (add parameter and variable reference)
 475    // Parsing doesn't begin until the transaction is complete
 476    buffer.update(cx, |buf, cx| {
 477        buf.start_transaction();
 478
 479        let offset = buf.text().find(')').unwrap();
 480        buf.edit([(offset..offset, "b: C")], None, cx);
 481        assert!(!buf.is_parsing());
 482
 483        let offset = buf.text().find('}').unwrap();
 484        buf.edit([(offset..offset, " d; ")], None, cx);
 485        assert!(!buf.is_parsing());
 486
 487        buf.end_transaction(cx);
 488        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 489        assert!(buf.is_parsing());
 490    });
 491    cx.executor().run_until_parked();
 492    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 493    assert_eq!(
 494        get_tree_sexp(&buffer, cx),
 495        concat!(
 496            "(source_file (function_item name: (identifier) ",
 497            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 498            "body: (block (expression_statement (identifier)))))"
 499        )
 500    );
 501
 502    // Perform a series of edits without waiting for the current parse to complete:
 503    // * turn identifier into a field expression
 504    // * turn field expression into a method call
 505    // * add a turbofish to the method call
 506    buffer.update(cx, |buf, cx| {
 507        let offset = buf.text().find(';').unwrap();
 508        buf.edit([(offset..offset, ".e")], None, cx);
 509        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 510        assert!(buf.is_parsing());
 511    });
 512    buffer.update(cx, |buf, cx| {
 513        let offset = buf.text().find(';').unwrap();
 514        buf.edit([(offset..offset, "(f)")], None, cx);
 515        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 516        assert!(buf.is_parsing());
 517    });
 518    buffer.update(cx, |buf, cx| {
 519        let offset = buf.text().find("(f)").unwrap();
 520        buf.edit([(offset..offset, "::<G>")], None, cx);
 521        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 522        assert!(buf.is_parsing());
 523    });
 524    cx.executor().run_until_parked();
 525    assert_eq!(
 526        get_tree_sexp(&buffer, cx),
 527        concat!(
 528            "(source_file (function_item name: (identifier) ",
 529            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 530            "body: (block (expression_statement (call_expression ",
 531            "function: (generic_function ",
 532            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 533            "type_arguments: (type_arguments (type_identifier))) ",
 534            "arguments: (arguments (identifier)))))))",
 535        )
 536    );
 537
 538    buffer.update(cx, |buf, cx| {
 539        buf.undo(cx);
 540        buf.undo(cx);
 541        buf.undo(cx);
 542        buf.undo(cx);
 543        assert_eq!(buf.text(), "fn a() {}");
 544        assert!(buf.is_parsing());
 545    });
 546
 547    cx.executor().run_until_parked();
 548    assert_eq!(
 549        get_tree_sexp(&buffer, cx),
 550        concat!(
 551            "(source_file (function_item name: (identifier) ",
 552            "parameters: (parameters) ",
 553            "body: (block)))"
 554        )
 555    );
 556
 557    buffer.update(cx, |buf, cx| {
 558        buf.redo(cx);
 559        buf.redo(cx);
 560        buf.redo(cx);
 561        buf.redo(cx);
 562        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 563        assert!(buf.is_parsing());
 564    });
 565    cx.executor().run_until_parked();
 566    assert_eq!(
 567        get_tree_sexp(&buffer, cx),
 568        concat!(
 569            "(source_file (function_item name: (identifier) ",
 570            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 571            "body: (block (expression_statement (call_expression ",
 572            "function: (generic_function ",
 573            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 574            "type_arguments: (type_arguments (type_identifier))) ",
 575            "arguments: (arguments (identifier)))))))",
 576        )
 577    );
 578}
 579
 580#[gpui::test]
 581async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 582    let buffer = cx.new_model(|cx| {
 583        let mut buffer = Buffer::local("{}", cx).with_language(Arc::new(rust_lang()), cx);
 584        buffer.set_sync_parse_timeout(Duration::ZERO);
 585        buffer
 586    });
 587
 588    // Wait for the initial text to parse
 589    cx.executor().run_until_parked();
 590    assert_eq!(
 591        get_tree_sexp(&buffer, cx),
 592        "(source_file (expression_statement (block)))"
 593    );
 594
 595    buffer.update(cx, |buffer, cx| {
 596        buffer.set_language(Some(Arc::new(json_lang())), cx)
 597    });
 598    cx.executor().run_until_parked();
 599    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 600}
 601
 602#[gpui::test]
 603async fn test_outline(cx: &mut gpui::TestAppContext) {
 604    let text = r#"
 605        struct Person {
 606            name: String,
 607            age: usize,
 608        }
 609
 610        mod module {
 611            enum LoginState {
 612                LoggedOut,
 613                LoggingOn,
 614                LoggedIn {
 615                    person: Person,
 616                    time: Instant,
 617                }
 618            }
 619        }
 620
 621        impl Eq for Person {}
 622
 623        impl Drop for Person {
 624            fn drop(&mut self) {
 625                println!("bye");
 626            }
 627        }
 628    "#
 629    .unindent();
 630
 631    let buffer =
 632        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 633    let outline = buffer
 634        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 635        .unwrap();
 636
 637    assert_eq!(
 638        outline
 639            .items
 640            .iter()
 641            .map(|item| (item.text.as_str(), item.depth))
 642            .collect::<Vec<_>>(),
 643        &[
 644            ("struct Person", 0),
 645            ("name", 1),
 646            ("age", 1),
 647            ("mod module", 0),
 648            ("enum LoginState", 1),
 649            ("LoggedOut", 2),
 650            ("LoggingOn", 2),
 651            ("LoggedIn", 2),
 652            ("person", 3),
 653            ("time", 3),
 654            ("impl Eq for Person", 0),
 655            ("impl Drop for Person", 0),
 656            ("fn drop", 1),
 657        ]
 658    );
 659
 660    // Without space, we only match on names
 661    assert_eq!(
 662        search(&outline, "oon", cx).await,
 663        &[
 664            ("mod module", vec![]),                    // included as the parent of a match
 665            ("enum LoginState", vec![]),               // included as the parent of a match
 666            ("LoggingOn", vec![1, 7, 8]),              // matches
 667            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 668        ]
 669    );
 670
 671    assert_eq!(
 672        search(&outline, "dp p", cx).await,
 673        &[
 674            ("impl Drop for Person", vec![5, 8, 9, 14]),
 675            ("fn drop", vec![]),
 676        ]
 677    );
 678    assert_eq!(
 679        search(&outline, "dpn", cx).await,
 680        &[("impl Drop for Person", vec![5, 14, 19])]
 681    );
 682    assert_eq!(
 683        search(&outline, "impl ", cx).await,
 684        &[
 685            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 686            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 687            ("fn drop", vec![]),
 688        ]
 689    );
 690
 691    async fn search<'a>(
 692        outline: &'a Outline<Anchor>,
 693        query: &'a str,
 694        cx: &'a gpui::TestAppContext,
 695    ) -> Vec<(&'a str, Vec<usize>)> {
 696        let matches = cx
 697            .update(|cx| outline.search(query, cx.background_executor().clone()))
 698            .await;
 699        matches
 700            .into_iter()
 701            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 702            .collect::<Vec<_>>()
 703    }
 704}
 705
 706#[gpui::test]
 707async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 708    let text = r#"
 709        impl A for B<
 710            C
 711        > {
 712        };
 713    "#
 714    .unindent();
 715
 716    let buffer =
 717        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 718    let outline = buffer
 719        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 720        .unwrap();
 721
 722    assert_eq!(
 723        outline
 724            .items
 725            .iter()
 726            .map(|item| (item.text.as_str(), item.depth))
 727            .collect::<Vec<_>>(),
 728        &[("impl A for B<", 0)]
 729    );
 730}
 731
 732#[gpui::test]
 733async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
 734    let language = javascript_lang()
 735        .with_outline_query(
 736            r#"
 737            (function_declaration
 738                "function" @context
 739                name: (_) @name
 740                parameters: (formal_parameters
 741                    "(" @context.extra
 742                    ")" @context.extra)) @item
 743            "#,
 744        )
 745        .unwrap();
 746
 747    let text = r#"
 748        function a() {}
 749        function b(c) {}
 750    "#
 751    .unindent();
 752
 753    let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(language), cx));
 754    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 755
 756    // extra context nodes are included in the outline.
 757    let outline = snapshot.outline(None).unwrap();
 758    assert_eq!(
 759        outline
 760            .items
 761            .iter()
 762            .map(|item| (item.text.as_str(), item.depth))
 763            .collect::<Vec<_>>(),
 764        &[("function a()", 0), ("function b( )", 0),]
 765    );
 766
 767    // extra context nodes do not appear in breadcrumbs.
 768    let symbols = snapshot.symbols_containing(3, None).unwrap();
 769    assert_eq!(
 770        symbols
 771            .iter()
 772            .map(|item| (item.text.as_str(), item.depth))
 773            .collect::<Vec<_>>(),
 774        &[("function a", 0)]
 775    );
 776}
 777
 778#[gpui::test]
 779async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 780    let text = r#"
 781        impl Person {
 782            fn one() {
 783                1
 784            }
 785
 786            fn two() {
 787                2
 788            }fn three() {
 789                3
 790            }
 791        }
 792    "#
 793    .unindent();
 794
 795    let buffer =
 796        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 797    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 798
 799    // point is at the start of an item
 800    assert_eq!(
 801        symbols_containing(Point::new(1, 4), &snapshot),
 802        vec![
 803            (
 804                "impl Person".to_string(),
 805                Point::new(0, 0)..Point::new(10, 1)
 806            ),
 807            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 808        ]
 809    );
 810
 811    // point is in the middle of an item
 812    assert_eq!(
 813        symbols_containing(Point::new(2, 8), &snapshot),
 814        vec![
 815            (
 816                "impl Person".to_string(),
 817                Point::new(0, 0)..Point::new(10, 1)
 818            ),
 819            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 820        ]
 821    );
 822
 823    // point is at the end of an item
 824    assert_eq!(
 825        symbols_containing(Point::new(3, 5), &snapshot),
 826        vec![
 827            (
 828                "impl Person".to_string(),
 829                Point::new(0, 0)..Point::new(10, 1)
 830            ),
 831            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 832        ]
 833    );
 834
 835    // point is in between two adjacent items
 836    assert_eq!(
 837        symbols_containing(Point::new(7, 5), &snapshot),
 838        vec![
 839            (
 840                "impl Person".to_string(),
 841                Point::new(0, 0)..Point::new(10, 1)
 842            ),
 843            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 844        ]
 845    );
 846
 847    fn symbols_containing(
 848        position: Point,
 849        snapshot: &BufferSnapshot,
 850    ) -> Vec<(String, Range<Point>)> {
 851        snapshot
 852            .symbols_containing(position, None)
 853            .unwrap()
 854            .into_iter()
 855            .map(|item| {
 856                (
 857                    item.text,
 858                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 859                )
 860            })
 861            .collect()
 862    }
 863}
 864
 865#[gpui::test]
 866fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 867    let mut assert = |selection_text, range_markers| {
 868        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 869    };
 870
 871    assert(
 872        indoc! {"
 873            mod x {
 874                moˇd y {
 875
 876                }
 877            }
 878            let foo = 1;"},
 879        vec![indoc! {"
 880            mod x «{»
 881                mod y {
 882
 883                }
 884            «}»
 885            let foo = 1;"}],
 886    );
 887
 888    assert(
 889        indoc! {"
 890            mod x {
 891                mod y ˇ{
 892
 893                }
 894            }
 895            let foo = 1;"},
 896        vec![
 897            indoc! {"
 898                mod x «{»
 899                    mod y {
 900
 901                    }
 902                «}»
 903                let foo = 1;"},
 904            indoc! {"
 905                mod x {
 906                    mod y «{»
 907
 908                    «}»
 909                }
 910                let foo = 1;"},
 911        ],
 912    );
 913
 914    assert(
 915        indoc! {"
 916            mod x {
 917                mod y {
 918
 919 920            }
 921            let foo = 1;"},
 922        vec![
 923            indoc! {"
 924                mod x «{»
 925                    mod y {
 926
 927                    }
 928                «}»
 929                let foo = 1;"},
 930            indoc! {"
 931                mod x {
 932                    mod y «{»
 933
 934                    «}»
 935                }
 936                let foo = 1;"},
 937        ],
 938    );
 939
 940    assert(
 941        indoc! {"
 942            mod x {
 943                mod y {
 944
 945                }
 946            ˇ}
 947            let foo = 1;"},
 948        vec![indoc! {"
 949            mod x «{»
 950                mod y {
 951
 952                }
 953            «}»
 954            let foo = 1;"}],
 955    );
 956
 957    assert(
 958        indoc! {"
 959            mod x {
 960                mod y {
 961
 962                }
 963            }
 964            let fˇoo = 1;"},
 965        vec![],
 966    );
 967
 968    // Regression test: avoid crash when querying at the end of the buffer.
 969    assert(
 970        indoc! {"
 971            mod x {
 972                mod y {
 973
 974                }
 975            }
 976            let foo = 1;ˇ"},
 977        vec![],
 978    );
 979}
 980
 981#[gpui::test]
 982fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 983    let mut assert = |selection_text, bracket_pair_texts| {
 984        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 985    };
 986
 987    assert(
 988        indoc! {"
 989        for (const a in b)ˇ {
 990            // a comment that's longer than the for-loop header
 991        }"},
 992        vec![indoc! {"
 993        for «(»const a in b«)» {
 994            // a comment that's longer than the for-loop header
 995        }"}],
 996    );
 997
 998    // Regression test: even though the parent node of the parentheses (the for loop) does
 999    // intersect the given range, the parentheses themselves do not contain the range, so
1000    // they should not be returned. Only the curly braces contain the range.
1001    assert(
1002        indoc! {"
1003        for (const a in b) {ˇ
1004            // a comment that's longer than the for-loop header
1005        }"},
1006        vec![indoc! {"
1007        for (const a in b) «{»
1008            // a comment that's longer than the for-loop header
1009        «}»"}],
1010    );
1011}
1012
1013#[gpui::test]
1014fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
1015    cx.new_model(|cx| {
1016        let text = "fn a() { b(|c| {}) }";
1017        let buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1018        let snapshot = buffer.snapshot();
1019
1020        assert_eq!(
1021            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
1022            Some(range_of(text, "|"))
1023        );
1024        assert_eq!(
1025            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
1026            Some(range_of(text, "|c|"))
1027        );
1028        assert_eq!(
1029            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
1030            Some(range_of(text, "|c| {}"))
1031        );
1032        assert_eq!(
1033            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
1034            Some(range_of(text, "(|c| {})"))
1035        );
1036
1037        buffer
1038    });
1039
1040    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
1041        let start = text.find(part).unwrap();
1042        start..start
1043    }
1044
1045    fn range_of(text: &str, part: &str) -> Range<usize> {
1046        let start = text.find(part).unwrap();
1047        start..start + part.len()
1048    }
1049}
1050
1051#[gpui::test]
1052fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
1053    init_settings(cx, |_| {});
1054
1055    cx.new_model(|cx| {
1056        let text = "fn a() {}";
1057        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1058
1059        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1060        assert_eq!(buffer.text(), "fn a() {\n    \n}");
1061
1062        buffer.edit(
1063            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
1064            Some(AutoindentMode::EachLine),
1065            cx,
1066        );
1067        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
1068
1069        // Create a field expression on a new line, causing that line
1070        // to be indented.
1071        buffer.edit(
1072            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
1073            Some(AutoindentMode::EachLine),
1074            cx,
1075        );
1076        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
1077
1078        // Remove the dot so that the line is no longer a field expression,
1079        // causing the line to be outdented.
1080        buffer.edit(
1081            [(Point::new(2, 8)..Point::new(2, 9), "")],
1082            Some(AutoindentMode::EachLine),
1083            cx,
1084        );
1085        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
1086
1087        buffer
1088    });
1089}
1090
1091#[gpui::test]
1092fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
1093    init_settings(cx, |settings| {
1094        settings.defaults.hard_tabs = Some(true);
1095    });
1096
1097    cx.new_model(|cx| {
1098        let text = "fn a() {}";
1099        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1100
1101        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1102        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
1103
1104        buffer.edit(
1105            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
1106            Some(AutoindentMode::EachLine),
1107            cx,
1108        );
1109        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1110
1111        // Create a field expression on a new line, causing that line
1112        // to be indented.
1113        buffer.edit(
1114            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1115            Some(AutoindentMode::EachLine),
1116            cx,
1117        );
1118        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1119
1120        // Remove the dot so that the line is no longer a field expression,
1121        // causing the line to be outdented.
1122        buffer.edit(
1123            [(Point::new(2, 2)..Point::new(2, 3), "")],
1124            Some(AutoindentMode::EachLine),
1125            cx,
1126        );
1127        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1128
1129        buffer
1130    });
1131}
1132
1133#[gpui::test]
1134fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1135    init_settings(cx, |_| {});
1136
1137    cx.new_model(|cx| {
1138        let mut buffer = Buffer::local(
1139            "
1140            fn a() {
1141            c;
1142            d;
1143            }
1144            "
1145            .unindent(),
1146            cx,
1147        )
1148        .with_language(Arc::new(rust_lang()), cx);
1149
1150        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1151        // their indentation is not adjusted.
1152        buffer.edit_via_marked_text(
1153            &"
1154            fn a() {
1155            c«()»;
1156            d«()»;
1157            }
1158            "
1159            .unindent(),
1160            Some(AutoindentMode::EachLine),
1161            cx,
1162        );
1163        assert_eq!(
1164            buffer.text(),
1165            "
1166            fn a() {
1167            c();
1168            d();
1169            }
1170            "
1171            .unindent()
1172        );
1173
1174        // When appending new content after these lines, the indentation is based on the
1175        // preceding lines' actual indentation.
1176        buffer.edit_via_marked_text(
1177            &"
1178            fn a() {
11791180            .f
1181            .g()»;
11821183            .f
1184            .g()»;
1185            }
1186            "
1187            .unindent(),
1188            Some(AutoindentMode::EachLine),
1189            cx,
1190        );
1191
1192        assert_eq!(
1193            buffer.text(),
1194            "
1195            fn a() {
1196            c
1197                .f
1198                .g();
1199            d
1200                .f
1201                .g();
1202            }
1203            "
1204            .unindent()
1205        );
1206        buffer
1207    });
1208
1209    cx.new_model(|cx| {
1210        eprintln!("second buffer: {:?}", cx.entity_id());
1211
1212        let mut buffer = Buffer::local(
1213            "
1214            fn a() {
1215                b();
1216                |
1217            "
1218            .replace('|', "") // marker to preserve trailing whitespace
1219            .unindent(),
1220            cx,
1221        )
1222        .with_language(Arc::new(rust_lang()), cx);
1223
1224        // Insert a closing brace. It is outdented.
1225        buffer.edit_via_marked_text(
1226            &"
1227            fn a() {
1228                b();
1229                «}»
1230            "
1231            .unindent(),
1232            Some(AutoindentMode::EachLine),
1233            cx,
1234        );
1235        assert_eq!(
1236            buffer.text(),
1237            "
1238            fn a() {
1239                b();
1240            }
1241            "
1242            .unindent()
1243        );
1244
1245        // Manually edit the leading whitespace. The edit is preserved.
1246        buffer.edit_via_marked_text(
1247            &"
1248            fn a() {
1249                b();
1250            «    »}
1251            "
1252            .unindent(),
1253            Some(AutoindentMode::EachLine),
1254            cx,
1255        );
1256        assert_eq!(
1257            buffer.text(),
1258            "
1259            fn a() {
1260                b();
1261                }
1262            "
1263            .unindent()
1264        );
1265        buffer
1266    });
1267
1268    eprintln!("DONE");
1269}
1270
1271#[gpui::test]
1272fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1273    init_settings(cx, |_| {});
1274
1275    cx.new_model(|cx| {
1276        let mut buffer = Buffer::local(
1277            "
1278            fn a() {
1279                i
1280            }
1281            "
1282            .unindent(),
1283            cx,
1284        )
1285        .with_language(Arc::new(rust_lang()), cx);
1286
1287        // Regression test: line does not get outdented due to syntax error
1288        buffer.edit_via_marked_text(
1289            &"
1290            fn a() {
1291                i«f let Some(x) = y»
1292            }
1293            "
1294            .unindent(),
1295            Some(AutoindentMode::EachLine),
1296            cx,
1297        );
1298        assert_eq!(
1299            buffer.text(),
1300            "
1301            fn a() {
1302                if let Some(x) = y
1303            }
1304            "
1305            .unindent()
1306        );
1307
1308        buffer.edit_via_marked_text(
1309            &"
1310            fn a() {
1311                if let Some(x) = y« {»
1312            }
1313            "
1314            .unindent(),
1315            Some(AutoindentMode::EachLine),
1316            cx,
1317        );
1318        assert_eq!(
1319            buffer.text(),
1320            "
1321            fn a() {
1322                if let Some(x) = y {
1323            }
1324            "
1325            .unindent()
1326        );
1327
1328        buffer
1329    });
1330}
1331
1332#[gpui::test]
1333fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1334    init_settings(cx, |_| {});
1335
1336    cx.new_model(|cx| {
1337        let mut buffer = Buffer::local(
1338            "
1339            fn a() {}
1340            "
1341            .unindent(),
1342            cx,
1343        )
1344        .with_language(Arc::new(rust_lang()), cx);
1345
1346        buffer.edit_via_marked_text(
1347            &"
1348            fn a(«
1349            b») {}
1350            "
1351            .unindent(),
1352            Some(AutoindentMode::EachLine),
1353            cx,
1354        );
1355        assert_eq!(
1356            buffer.text(),
1357            "
1358            fn a(
1359                b) {}
1360            "
1361            .unindent()
1362        );
1363
1364        // The indentation suggestion changed because `@end` node (a close paren)
1365        // is now at the beginning of the line.
1366        buffer.edit_via_marked_text(
1367            &"
1368            fn a(
1369                ˇ) {}
1370            "
1371            .unindent(),
1372            Some(AutoindentMode::EachLine),
1373            cx,
1374        );
1375        assert_eq!(
1376            buffer.text(),
1377            "
1378                fn a(
1379                ) {}
1380            "
1381            .unindent()
1382        );
1383
1384        buffer
1385    });
1386}
1387
1388#[gpui::test]
1389fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1390    init_settings(cx, |_| {});
1391
1392    cx.new_model(|cx| {
1393        let text = "a\nb";
1394        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1395        buffer.edit(
1396            [(0..1, "\n"), (2..3, "\n")],
1397            Some(AutoindentMode::EachLine),
1398            cx,
1399        );
1400        assert_eq!(buffer.text(), "\n\n\n");
1401        buffer
1402    });
1403}
1404
1405#[gpui::test]
1406fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1407    init_settings(cx, |_| {});
1408
1409    cx.new_model(|cx| {
1410        let text = "
1411            const a: usize = 1;
1412            fn b() {
1413                if c {
1414                    let d = 2;
1415                }
1416            }
1417        "
1418        .unindent();
1419
1420        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1421        buffer.edit(
1422            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1423            Some(AutoindentMode::EachLine),
1424            cx,
1425        );
1426        assert_eq!(
1427            buffer.text(),
1428            "
1429                const a: usize = 1;
1430                fn b() {
1431                    if c {
1432                        e(
1433                            f()
1434                        );
1435                        let d = 2;
1436                    }
1437                }
1438            "
1439            .unindent()
1440        );
1441
1442        buffer
1443    });
1444}
1445
1446#[gpui::test]
1447fn test_autoindent_block_mode(cx: &mut AppContext) {
1448    init_settings(cx, |_| {});
1449
1450    cx.new_model(|cx| {
1451        let text = r#"
1452            fn a() {
1453                b();
1454            }
1455        "#
1456        .unindent();
1457        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1458
1459        // When this text was copied, both of the quotation marks were at the same
1460        // indent level, but the indentation of the first line was not included in
1461        // the copied text. This information is retained in the
1462        // 'original_indent_columns' vector.
1463        let original_indent_columns = vec![4];
1464        let inserted_text = r#"
1465            "
1466                  c
1467                    d
1468                      e
1469                "
1470        "#
1471        .unindent();
1472
1473        // Insert the block at column zero. The entire block is indented
1474        // so that the first line matches the previous line's indentation.
1475        buffer.edit(
1476            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1477            Some(AutoindentMode::Block {
1478                original_indent_columns: original_indent_columns.clone(),
1479            }),
1480            cx,
1481        );
1482        assert_eq!(
1483            buffer.text(),
1484            r#"
1485            fn a() {
1486                b();
1487                "
1488                  c
1489                    d
1490                      e
1491                "
1492            }
1493            "#
1494            .unindent()
1495        );
1496
1497        // Grouping is disabled in tests, so we need 2 undos
1498        buffer.undo(cx); // Undo the auto-indent
1499        buffer.undo(cx); // Undo the original edit
1500
1501        // Insert the block at a deeper indent level. The entire block is outdented.
1502        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1503        buffer.edit(
1504            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1505            Some(AutoindentMode::Block {
1506                original_indent_columns: original_indent_columns.clone(),
1507            }),
1508            cx,
1509        );
1510        assert_eq!(
1511            buffer.text(),
1512            r#"
1513            fn a() {
1514                b();
1515                "
1516                  c
1517                    d
1518                      e
1519                "
1520            }
1521            "#
1522            .unindent()
1523        );
1524
1525        buffer
1526    });
1527}
1528
1529#[gpui::test]
1530fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1531    init_settings(cx, |_| {});
1532
1533    cx.new_model(|cx| {
1534        let text = r#"
1535            fn a() {
1536                if b() {
1537
1538                }
1539            }
1540        "#
1541        .unindent();
1542        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1543
1544        // The original indent columns are not known, so this text is
1545        // auto-indented in a block as if the first line was copied in
1546        // its entirety.
1547        let original_indent_columns = Vec::new();
1548        let inserted_text = "    c\n        .d()\n        .e();";
1549
1550        // Insert the block at column zero. The entire block is indented
1551        // so that the first line matches the previous line's indentation.
1552        buffer.edit(
1553            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1554            Some(AutoindentMode::Block {
1555                original_indent_columns: original_indent_columns.clone(),
1556            }),
1557            cx,
1558        );
1559        assert_eq!(
1560            buffer.text(),
1561            r#"
1562            fn a() {
1563                if b() {
1564                    c
1565                        .d()
1566                        .e();
1567                }
1568            }
1569            "#
1570            .unindent()
1571        );
1572
1573        // Grouping is disabled in tests, so we need 2 undos
1574        buffer.undo(cx); // Undo the auto-indent
1575        buffer.undo(cx); // Undo the original edit
1576
1577        // Insert the block at a deeper indent level. The entire block is outdented.
1578        buffer.edit(
1579            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1580            None,
1581            cx,
1582        );
1583        buffer.edit(
1584            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1585            Some(AutoindentMode::Block {
1586                original_indent_columns: Vec::new(),
1587            }),
1588            cx,
1589        );
1590        assert_eq!(
1591            buffer.text(),
1592            r#"
1593            fn a() {
1594                if b() {
1595                    c
1596                        .d()
1597                        .e();
1598                }
1599            }
1600            "#
1601            .unindent()
1602        );
1603
1604        buffer
1605    });
1606}
1607
1608#[gpui::test]
1609fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1610    init_settings(cx, |_| {});
1611
1612    cx.new_model(|cx| {
1613        let text = "
1614            * one
1615                - a
1616                - b
1617            * two
1618        "
1619        .unindent();
1620
1621        let mut buffer = Buffer::local(text, cx).with_language(
1622            Arc::new(Language::new(
1623                LanguageConfig {
1624                    name: "Markdown".into(),
1625                    auto_indent_using_last_non_empty_line: false,
1626                    ..Default::default()
1627                },
1628                Some(tree_sitter_json::language()),
1629            )),
1630            cx,
1631        );
1632        buffer.edit(
1633            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1634            Some(AutoindentMode::EachLine),
1635            cx,
1636        );
1637        assert_eq!(
1638            buffer.text(),
1639            "
1640            * one
1641                - a
1642                - b
1643
1644            * two
1645            "
1646            .unindent()
1647        );
1648        buffer
1649    });
1650}
1651
1652#[gpui::test]
1653fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1654    init_settings(cx, |settings| {
1655        settings.languages.extend([
1656            (
1657                "HTML".into(),
1658                LanguageSettingsContent {
1659                    tab_size: Some(2.try_into().unwrap()),
1660                    ..Default::default()
1661                },
1662            ),
1663            (
1664                "JavaScript".into(),
1665                LanguageSettingsContent {
1666                    tab_size: Some(8.try_into().unwrap()),
1667                    ..Default::default()
1668                },
1669            ),
1670        ])
1671    });
1672
1673    let html_language = Arc::new(html_lang());
1674
1675    let javascript_language = Arc::new(javascript_lang());
1676
1677    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1678    language_registry.add(html_language.clone());
1679    language_registry.add(javascript_language.clone());
1680
1681    cx.new_model(|cx| {
1682        let (text, ranges) = marked_text_ranges(
1683            &"
1684                <div>ˇ
1685                </div>
1686                <script>
1687                    init({ˇ
1688                    })
1689                </script>
1690                <span>ˇ
1691                </span>
1692            "
1693            .unindent(),
1694            false,
1695        );
1696
1697        let mut buffer = Buffer::local(text, cx);
1698        buffer.set_language_registry(language_registry);
1699        buffer.set_language(Some(html_language), cx);
1700        buffer.edit(
1701            ranges.into_iter().map(|range| (range, "\na")),
1702            Some(AutoindentMode::EachLine),
1703            cx,
1704        );
1705        assert_eq!(
1706            buffer.text(),
1707            "
1708                <div>
1709                  a
1710                </div>
1711                <script>
1712                    init({
1713                            a
1714                    })
1715                </script>
1716                <span>
1717                  a
1718                </span>
1719            "
1720            .unindent()
1721        );
1722        buffer
1723    });
1724}
1725
1726#[gpui::test]
1727fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1728    init_settings(cx, |settings| {
1729        settings.defaults.tab_size = Some(2.try_into().unwrap());
1730    });
1731
1732    cx.new_model(|cx| {
1733        let mut buffer = Buffer::local("", cx).with_language(Arc::new(ruby_lang()), cx);
1734
1735        let text = r#"
1736            class C
1737            def a(b, c)
1738            puts b
1739            puts c
1740            rescue
1741            puts "errored"
1742            exit 1
1743            end
1744            end
1745        "#
1746        .unindent();
1747
1748        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1749
1750        assert_eq!(
1751            buffer.text(),
1752            r#"
1753                class C
1754                  def a(b, c)
1755                    puts b
1756                    puts c
1757                  rescue
1758                    puts "errored"
1759                    exit 1
1760                  end
1761                end
1762            "#
1763            .unindent()
1764        );
1765
1766        buffer
1767    });
1768}
1769
1770#[gpui::test]
1771fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1772    init_settings(cx, |_| {});
1773
1774    cx.new_model(|cx| {
1775        let language = Language::new(
1776            LanguageConfig {
1777                name: "JavaScript".into(),
1778                line_comments: vec!["// ".into()],
1779                brackets: BracketPairConfig {
1780                    pairs: vec![
1781                        BracketPair {
1782                            start: "{".into(),
1783                            end: "}".into(),
1784                            close: true,
1785                            surround: true,
1786                            newline: false,
1787                        },
1788                        BracketPair {
1789                            start: "'".into(),
1790                            end: "'".into(),
1791                            close: true,
1792                            surround: true,
1793                            newline: false,
1794                        },
1795                    ],
1796                    disabled_scopes_by_bracket_ix: vec![
1797                        Vec::new(), //
1798                        vec!["string".into()],
1799                    ],
1800                },
1801                overrides: [(
1802                    "element".into(),
1803                    LanguageConfigOverride {
1804                        line_comments: Override::Remove { remove: true },
1805                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1806                        ..Default::default()
1807                    },
1808                )]
1809                .into_iter()
1810                .collect(),
1811                ..Default::default()
1812            },
1813            Some(tree_sitter_typescript::language_tsx()),
1814        )
1815        .with_override_query(
1816            r#"
1817                (jsx_element) @element
1818                (string) @string
1819                [
1820                    (jsx_opening_element)
1821                    (jsx_closing_element)
1822                    (jsx_expression)
1823                ] @default
1824            "#,
1825        )
1826        .unwrap();
1827
1828        let text = r#"
1829            a["b"] = <C d="e">
1830                <F></F>
1831                { g() }
1832            </C>;
1833        "#
1834        .unindent();
1835
1836        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
1837        let snapshot = buffer.snapshot();
1838
1839        let config = snapshot.language_scope_at(0).unwrap();
1840        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
1841        // Both bracket pairs are enabled
1842        assert_eq!(
1843            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1844            &[true, true]
1845        );
1846
1847        let string_config = snapshot
1848            .language_scope_at(text.find("b\"").unwrap())
1849            .unwrap();
1850        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
1851        // Second bracket pair is disabled
1852        assert_eq!(
1853            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1854            &[true, false]
1855        );
1856
1857        // In between JSX tags: use the `element` override.
1858        let element_config = snapshot
1859            .language_scope_at(text.find("<F>").unwrap())
1860            .unwrap();
1861        assert_eq!(element_config.line_comment_prefixes(), &[]);
1862        assert_eq!(
1863            element_config.block_comment_delimiters(),
1864            Some((&"{/*".into(), &"*/}".into()))
1865        );
1866        assert_eq!(
1867            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1868            &[true, true]
1869        );
1870
1871        // Within a JSX tag: use the default config.
1872        let tag_config = snapshot
1873            .language_scope_at(text.find(" d=").unwrap() + 1)
1874            .unwrap();
1875        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
1876        assert_eq!(
1877            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1878            &[true, true]
1879        );
1880
1881        // In a JSX expression: use the default config.
1882        let expression_in_element_config = snapshot
1883            .language_scope_at(text.find('{').unwrap() + 1)
1884            .unwrap();
1885        assert_eq!(
1886            expression_in_element_config.line_comment_prefixes(),
1887            &[Arc::from("// ")]
1888        );
1889        assert_eq!(
1890            expression_in_element_config
1891                .brackets()
1892                .map(|e| e.1)
1893                .collect::<Vec<_>>(),
1894            &[true, true]
1895        );
1896
1897        buffer
1898    });
1899}
1900
1901#[gpui::test]
1902fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1903    init_settings(cx, |_| {});
1904
1905    cx.new_model(|cx| {
1906        let language = Language::new(
1907            LanguageConfig {
1908                name: "Rust".into(),
1909                brackets: BracketPairConfig {
1910                    pairs: vec![
1911                        BracketPair {
1912                            start: "{".into(),
1913                            end: "}".into(),
1914                            close: true,
1915                            surround: true,
1916                            newline: false,
1917                        },
1918                        BracketPair {
1919                            start: "'".into(),
1920                            end: "'".into(),
1921                            close: true,
1922                            surround: true,
1923                            newline: false,
1924                        },
1925                    ],
1926                    disabled_scopes_by_bracket_ix: vec![
1927                        Vec::new(), //
1928                        vec!["string".into()],
1929                    ],
1930                },
1931                ..Default::default()
1932            },
1933            Some(tree_sitter_rust::language()),
1934        )
1935        .with_override_query(
1936            r#"
1937                (string_literal) @string
1938            "#,
1939        )
1940        .unwrap();
1941
1942        let text = r#"
1943            const S: &'static str = "hello";
1944        "#
1945        .unindent();
1946
1947        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
1948        let snapshot = buffer.snapshot();
1949
1950        // By default, all brackets are enabled
1951        let config = snapshot.language_scope_at(0).unwrap();
1952        assert_eq!(
1953            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1954            &[true, true]
1955        );
1956
1957        // Within a string, the quotation brackets are disabled.
1958        let string_config = snapshot
1959            .language_scope_at(text.find("ello").unwrap())
1960            .unwrap();
1961        assert_eq!(
1962            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1963            &[true, false]
1964        );
1965
1966        buffer
1967    });
1968}
1969
1970#[gpui::test]
1971fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1972    init_settings(cx, |_| {});
1973
1974    cx.new_model(|cx| {
1975        let text = r#"
1976            <ol>
1977            <% people.each do |person| %>
1978                <li>
1979                    <%= person.name %>
1980                </li>
1981            <% end %>
1982            </ol>
1983        "#
1984        .unindent();
1985
1986        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1987        language_registry.add(Arc::new(ruby_lang()));
1988        language_registry.add(Arc::new(html_lang()));
1989        language_registry.add(Arc::new(erb_lang()));
1990
1991        let mut buffer = Buffer::local(text, cx);
1992        buffer.set_language_registry(language_registry.clone());
1993        buffer.set_language(
1994            language_registry
1995                .language_for_name("ERB")
1996                .now_or_never()
1997                .unwrap()
1998                .ok(),
1999            cx,
2000        );
2001
2002        let snapshot = buffer.snapshot();
2003        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2004        assert_eq!(html_config.line_comment_prefixes(), &[]);
2005        assert_eq!(
2006            html_config.block_comment_delimiters(),
2007            Some((&"<!--".into(), &"-->".into()))
2008        );
2009
2010        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2011        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2012        assert_eq!(ruby_config.block_comment_delimiters(), None);
2013
2014        buffer
2015    });
2016}
2017
2018#[gpui::test]
2019fn test_serialization(cx: &mut gpui::AppContext) {
2020    let mut now = Instant::now();
2021
2022    let buffer1 = cx.new_model(|cx| {
2023        let mut buffer = Buffer::local("abc", cx);
2024        buffer.edit([(3..3, "D")], None, cx);
2025
2026        now += Duration::from_secs(1);
2027        buffer.start_transaction_at(now);
2028        buffer.edit([(4..4, "E")], None, cx);
2029        buffer.end_transaction_at(now, cx);
2030        assert_eq!(buffer.text(), "abcDE");
2031
2032        buffer.undo(cx);
2033        assert_eq!(buffer.text(), "abcD");
2034
2035        buffer.edit([(4..4, "F")], None, cx);
2036        assert_eq!(buffer.text(), "abcDF");
2037        buffer
2038    });
2039    assert_eq!(buffer1.read(cx).text(), "abcDF");
2040
2041    let state = buffer1.read(cx).to_proto();
2042    let ops = cx
2043        .background_executor()
2044        .block(buffer1.read(cx).serialize_ops(None, cx));
2045    let buffer2 = cx.new_model(|cx| {
2046        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2047        buffer
2048            .apply_ops(
2049                ops.into_iter()
2050                    .map(|op| proto::deserialize_operation(op).unwrap()),
2051                cx,
2052            )
2053            .unwrap();
2054        buffer
2055    });
2056    assert_eq!(buffer2.read(cx).text(), "abcDF");
2057}
2058
2059#[gpui::test]
2060async fn test_find_matching_indent(cx: &mut TestAppContext) {
2061    cx.update(|cx| init_settings(cx, |_| {}));
2062
2063    async fn enclosing_indent(
2064        text: impl Into<String>,
2065        buffer_row: u32,
2066        cx: &mut TestAppContext,
2067    ) -> Option<(Range<u32>, LineIndent)> {
2068        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2069        let snapshot = cx.read(|cx| buffer.read(cx).snapshot());
2070        snapshot.enclosing_indent(buffer_row).await
2071    }
2072
2073    assert_eq!(
2074        enclosing_indent(
2075            "
2076        fn b() {
2077            if c {
2078                let d = 2;
2079            }
2080        }"
2081            .unindent(),
2082            1,
2083            cx,
2084        )
2085        .await,
2086        Some((
2087            1..2,
2088            LineIndent {
2089                tabs: 0,
2090                spaces: 4,
2091                line_blank: false,
2092            }
2093        ))
2094    );
2095
2096    assert_eq!(
2097        enclosing_indent(
2098            "
2099        fn b() {
2100            if c {
2101                let d = 2;
2102            }
2103        }"
2104            .unindent(),
2105            2,
2106            cx,
2107        )
2108        .await,
2109        Some((
2110            1..2,
2111            LineIndent {
2112                tabs: 0,
2113                spaces: 4,
2114                line_blank: false,
2115            }
2116        ))
2117    );
2118
2119    assert_eq!(
2120        enclosing_indent(
2121            "
2122        fn b() {
2123            if c {
2124                let d = 2;
2125
2126                let e = 5;
2127            }
2128        }"
2129            .unindent(),
2130            3,
2131            cx,
2132        )
2133        .await,
2134        Some((
2135            1..4,
2136            LineIndent {
2137                tabs: 0,
2138                spaces: 4,
2139                line_blank: false,
2140            }
2141        ))
2142    );
2143}
2144
2145#[gpui::test(iterations = 100)]
2146fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2147    let min_peers = env::var("MIN_PEERS")
2148        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2149        .unwrap_or(1);
2150    let max_peers = env::var("MAX_PEERS")
2151        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2152        .unwrap_or(5);
2153    let operations = env::var("OPERATIONS")
2154        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2155        .unwrap_or(10);
2156
2157    let base_text_len = rng.gen_range(0..10);
2158    let base_text = RandomCharIter::new(&mut rng)
2159        .take(base_text_len)
2160        .collect::<String>();
2161    let mut replica_ids = Vec::new();
2162    let mut buffers = Vec::new();
2163    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2164    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2165
2166    for i in 0..rng.gen_range(min_peers..=max_peers) {
2167        let buffer = cx.new_model(|cx| {
2168            let state = base_buffer.read(cx).to_proto();
2169            let ops = cx
2170                .background_executor()
2171                .block(base_buffer.read(cx).serialize_ops(None, cx));
2172            let mut buffer =
2173                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2174            buffer
2175                .apply_ops(
2176                    ops.into_iter()
2177                        .map(|op| proto::deserialize_operation(op).unwrap()),
2178                    cx,
2179                )
2180                .unwrap();
2181            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2182            let network = network.clone();
2183            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2184                if let Event::Operation(op) = event {
2185                    network
2186                        .lock()
2187                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2188                }
2189            })
2190            .detach();
2191            buffer
2192        });
2193
2194        buffers.push(buffer);
2195        replica_ids.push(i as ReplicaId);
2196        network.lock().add_peer(i as ReplicaId);
2197        log::info!("Adding initial peer with replica id {}", i);
2198    }
2199
2200    log::info!("initial text: {:?}", base_text);
2201
2202    let mut now = Instant::now();
2203    let mut mutation_count = operations;
2204    let mut next_diagnostic_id = 0;
2205    let mut active_selections = BTreeMap::default();
2206    loop {
2207        let replica_index = rng.gen_range(0..replica_ids.len());
2208        let replica_id = replica_ids[replica_index];
2209        let buffer = &mut buffers[replica_index];
2210        let mut new_buffer = None;
2211        match rng.gen_range(0..100) {
2212            0..=29 if mutation_count != 0 => {
2213                buffer.update(cx, |buffer, cx| {
2214                    buffer.start_transaction_at(now);
2215                    buffer.randomly_edit(&mut rng, 5, cx);
2216                    buffer.end_transaction_at(now, cx);
2217                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2218                });
2219                mutation_count -= 1;
2220            }
2221            30..=39 if mutation_count != 0 => {
2222                buffer.update(cx, |buffer, cx| {
2223                    if rng.gen_bool(0.2) {
2224                        log::info!("peer {} clearing active selections", replica_id);
2225                        active_selections.remove(&replica_id);
2226                        buffer.remove_active_selections(cx);
2227                    } else {
2228                        let mut selections = Vec::new();
2229                        for id in 0..rng.gen_range(1..=5) {
2230                            let range = buffer.random_byte_range(0, &mut rng);
2231                            selections.push(Selection {
2232                                id,
2233                                start: buffer.anchor_before(range.start),
2234                                end: buffer.anchor_before(range.end),
2235                                reversed: false,
2236                                goal: SelectionGoal::None,
2237                            });
2238                        }
2239                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2240                        log::info!(
2241                            "peer {} setting active selections: {:?}",
2242                            replica_id,
2243                            selections
2244                        );
2245                        active_selections.insert(replica_id, selections.clone());
2246                        buffer.set_active_selections(selections, false, Default::default(), cx);
2247                    }
2248                });
2249                mutation_count -= 1;
2250            }
2251            40..=49 if mutation_count != 0 && replica_id == 0 => {
2252                let entry_count = rng.gen_range(1..=5);
2253                buffer.update(cx, |buffer, cx| {
2254                    let diagnostics = DiagnosticSet::new(
2255                        (0..entry_count).map(|_| {
2256                            let range = buffer.random_byte_range(0, &mut rng);
2257                            let range = range.to_point_utf16(buffer);
2258                            let range = range.start..range.end;
2259                            DiagnosticEntry {
2260                                range,
2261                                diagnostic: Diagnostic {
2262                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2263                                    ..Default::default()
2264                                },
2265                            }
2266                        }),
2267                        buffer,
2268                    );
2269                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2270                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2271                });
2272                mutation_count -= 1;
2273            }
2274            50..=59 if replica_ids.len() < max_peers => {
2275                let old_buffer_state = buffer.read(cx).to_proto();
2276                let old_buffer_ops = cx
2277                    .background_executor()
2278                    .block(buffer.read(cx).serialize_ops(None, cx));
2279                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2280                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2281                    .choose(&mut rng)
2282                    .unwrap();
2283                log::info!(
2284                    "Adding new replica {} (replicating from {})",
2285                    new_replica_id,
2286                    replica_id
2287                );
2288                new_buffer = Some(cx.new_model(|cx| {
2289                    let mut new_buffer = Buffer::from_proto(
2290                        new_replica_id,
2291                        Capability::ReadWrite,
2292                        old_buffer_state,
2293                        None,
2294                    )
2295                    .unwrap();
2296                    new_buffer
2297                        .apply_ops(
2298                            old_buffer_ops
2299                                .into_iter()
2300                                .map(|op| deserialize_operation(op).unwrap()),
2301                            cx,
2302                        )
2303                        .unwrap();
2304                    log::info!(
2305                        "New replica {} text: {:?}",
2306                        new_buffer.replica_id(),
2307                        new_buffer.text()
2308                    );
2309                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2310                    let network = network.clone();
2311                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2312                        if let Event::Operation(op) = event {
2313                            network.lock().broadcast(
2314                                buffer.replica_id(),
2315                                vec![proto::serialize_operation(op)],
2316                            );
2317                        }
2318                    })
2319                    .detach();
2320                    new_buffer
2321                }));
2322                network.lock().replicate(replica_id, new_replica_id);
2323
2324                if new_replica_id as usize == replica_ids.len() {
2325                    replica_ids.push(new_replica_id);
2326                } else {
2327                    let new_buffer = new_buffer.take().unwrap();
2328                    while network.lock().has_unreceived(new_replica_id) {
2329                        let ops = network
2330                            .lock()
2331                            .receive(new_replica_id)
2332                            .into_iter()
2333                            .map(|op| proto::deserialize_operation(op).unwrap());
2334                        if ops.len() > 0 {
2335                            log::info!(
2336                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2337                                new_replica_id,
2338                                buffer.read(cx).version(),
2339                                ops.len(),
2340                                ops
2341                            );
2342                            new_buffer.update(cx, |new_buffer, cx| {
2343                                new_buffer.apply_ops(ops, cx).unwrap();
2344                            });
2345                        }
2346                    }
2347                    buffers[new_replica_id as usize] = new_buffer;
2348                }
2349            }
2350            60..=69 if mutation_count != 0 => {
2351                buffer.update(cx, |buffer, cx| {
2352                    buffer.randomly_undo_redo(&mut rng, cx);
2353                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2354                });
2355                mutation_count -= 1;
2356            }
2357            _ if network.lock().has_unreceived(replica_id) => {
2358                let ops = network
2359                    .lock()
2360                    .receive(replica_id)
2361                    .into_iter()
2362                    .map(|op| proto::deserialize_operation(op).unwrap());
2363                if ops.len() > 0 {
2364                    log::info!(
2365                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2366                        replica_id,
2367                        buffer.read(cx).version(),
2368                        ops.len(),
2369                        ops
2370                    );
2371                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2372                }
2373            }
2374            _ => {}
2375        }
2376
2377        now += Duration::from_millis(rng.gen_range(0..=200));
2378        buffers.extend(new_buffer);
2379
2380        for buffer in &buffers {
2381            buffer.read(cx).check_invariants();
2382        }
2383
2384        if mutation_count == 0 && network.lock().is_idle() {
2385            break;
2386        }
2387    }
2388
2389    let first_buffer = buffers[0].read(cx).snapshot();
2390    for buffer in &buffers[1..] {
2391        let buffer = buffer.read(cx).snapshot();
2392        assert_eq!(
2393            buffer.version(),
2394            first_buffer.version(),
2395            "Replica {} version != Replica 0 version",
2396            buffer.replica_id()
2397        );
2398        assert_eq!(
2399            buffer.text(),
2400            first_buffer.text(),
2401            "Replica {} text != Replica 0 text",
2402            buffer.replica_id()
2403        );
2404        assert_eq!(
2405            buffer
2406                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2407                .collect::<Vec<_>>(),
2408            first_buffer
2409                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2410                .collect::<Vec<_>>(),
2411            "Replica {} diagnostics != Replica 0 diagnostics",
2412            buffer.replica_id()
2413        );
2414    }
2415
2416    for buffer in &buffers {
2417        let buffer = buffer.read(cx).snapshot();
2418        let actual_remote_selections = buffer
2419            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
2420            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2421            .collect::<Vec<_>>();
2422        let expected_remote_selections = active_selections
2423            .iter()
2424            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2425            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2426            .collect::<Vec<_>>();
2427        assert_eq!(
2428            actual_remote_selections,
2429            expected_remote_selections,
2430            "Replica {} remote selections != expected selections",
2431            buffer.replica_id()
2432        );
2433    }
2434}
2435
2436#[test]
2437fn test_contiguous_ranges() {
2438    assert_eq!(
2439        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2440        &[1..4, 5..7, 9..13]
2441    );
2442
2443    // Respects the `max_len` parameter
2444    assert_eq!(
2445        contiguous_ranges(
2446            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2447            3
2448        )
2449        .collect::<Vec<_>>(),
2450        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2451    );
2452}
2453
2454#[gpui::test(iterations = 500)]
2455fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2456    // Generate a random multi-line string containing
2457    // some lines with trailing whitespace.
2458    let mut text = String::new();
2459    for _ in 0..rng.gen_range(0..16) {
2460        for _ in 0..rng.gen_range(0..36) {
2461            text.push(match rng.gen_range(0..10) {
2462                0..=1 => ' ',
2463                3 => '\t',
2464                _ => rng.gen_range('a'..'z'),
2465            });
2466        }
2467        text.push('\n');
2468    }
2469
2470    match rng.gen_range(0..10) {
2471        // sometimes remove the last newline
2472        0..=1 => drop(text.pop()), //
2473
2474        // sometimes add extra newlines
2475        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2476        _ => {}
2477    }
2478
2479    let rope = Rope::from(text.as_str());
2480    let actual_ranges = trailing_whitespace_ranges(&rope);
2481    let expected_ranges = TRAILING_WHITESPACE_REGEX
2482        .find_iter(&text)
2483        .map(|m| m.range())
2484        .collect::<Vec<_>>();
2485    assert_eq!(
2486        actual_ranges,
2487        expected_ranges,
2488        "wrong ranges for text lines:\n{:?}",
2489        text.split('\n').collect::<Vec<_>>()
2490    );
2491}
2492
2493fn ruby_lang() -> Language {
2494    Language::new(
2495        LanguageConfig {
2496            name: "Ruby".into(),
2497            matcher: LanguageMatcher {
2498                path_suffixes: vec!["rb".to_string()],
2499                ..Default::default()
2500            },
2501            line_comments: vec!["# ".into()],
2502            ..Default::default()
2503        },
2504        Some(tree_sitter_ruby::language()),
2505    )
2506    .with_indents_query(
2507        r#"
2508            (class "end" @end) @indent
2509            (method "end" @end) @indent
2510            (rescue) @outdent
2511            (then) @indent
2512        "#,
2513    )
2514    .unwrap()
2515}
2516
2517fn html_lang() -> Language {
2518    Language::new(
2519        LanguageConfig {
2520            name: "HTML".into(),
2521            block_comment: Some(("<!--".into(), "-->".into())),
2522            ..Default::default()
2523        },
2524        Some(tree_sitter_html::language()),
2525    )
2526    .with_indents_query(
2527        "
2528        (element
2529          (start_tag) @start
2530          (end_tag)? @end) @indent
2531        ",
2532    )
2533    .unwrap()
2534    .with_injection_query(
2535        r#"
2536        (script_element
2537            (raw_text) @content
2538            (#set! "language" "javascript"))
2539        "#,
2540    )
2541    .unwrap()
2542}
2543
2544fn erb_lang() -> Language {
2545    Language::new(
2546        LanguageConfig {
2547            name: "ERB".into(),
2548            matcher: LanguageMatcher {
2549                path_suffixes: vec!["erb".to_string()],
2550                ..Default::default()
2551            },
2552            block_comment: Some(("<%#".into(), "%>".into())),
2553            ..Default::default()
2554        },
2555        Some(tree_sitter_embedded_template::language()),
2556    )
2557    .with_injection_query(
2558        r#"
2559            (
2560                (code) @content
2561                (#set! "language" "ruby")
2562                (#set! "combined")
2563            )
2564
2565            (
2566                (content) @content
2567                (#set! "language" "html")
2568                (#set! "combined")
2569            )
2570        "#,
2571    )
2572    .unwrap()
2573}
2574
2575fn rust_lang() -> Language {
2576    Language::new(
2577        LanguageConfig {
2578            name: "Rust".into(),
2579            matcher: LanguageMatcher {
2580                path_suffixes: vec!["rs".to_string()],
2581                ..Default::default()
2582            },
2583            ..Default::default()
2584        },
2585        Some(tree_sitter_rust::language()),
2586    )
2587    .with_indents_query(
2588        r#"
2589        (call_expression) @indent
2590        (field_expression) @indent
2591        (_ "(" ")" @end) @indent
2592        (_ "{" "}" @end) @indent
2593        "#,
2594    )
2595    .unwrap()
2596    .with_brackets_query(
2597        r#"
2598        ("{" @open "}" @close)
2599        "#,
2600    )
2601    .unwrap()
2602    .with_outline_query(
2603        r#"
2604        (struct_item
2605            "struct" @context
2606            name: (_) @name) @item
2607        (enum_item
2608            "enum" @context
2609            name: (_) @name) @item
2610        (enum_variant
2611            name: (_) @name) @item
2612        (field_declaration
2613            name: (_) @name) @item
2614        (impl_item
2615            "impl" @context
2616            trait: (_)? @name
2617            "for"? @context
2618            type: (_) @name) @item
2619        (function_item
2620            "fn" @context
2621            name: (_) @name) @item
2622        (mod_item
2623            "mod" @context
2624            name: (_) @name) @item
2625        "#,
2626    )
2627    .unwrap()
2628}
2629
2630fn json_lang() -> Language {
2631    Language::new(
2632        LanguageConfig {
2633            name: "Json".into(),
2634            matcher: LanguageMatcher {
2635                path_suffixes: vec!["js".to_string()],
2636                ..Default::default()
2637            },
2638            ..Default::default()
2639        },
2640        Some(tree_sitter_json::language()),
2641    )
2642}
2643
2644fn javascript_lang() -> Language {
2645    Language::new(
2646        LanguageConfig {
2647            name: "JavaScript".into(),
2648            ..Default::default()
2649        },
2650        Some(tree_sitter_typescript::language_tsx()),
2651    )
2652    .with_brackets_query(
2653        r#"
2654        ("{" @open "}" @close)
2655        ("(" @open ")" @close)
2656        "#,
2657    )
2658    .unwrap()
2659    .with_indents_query(
2660        r#"
2661        (object "}" @end) @indent
2662        "#,
2663    )
2664    .unwrap()
2665}
2666
2667fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2668    buffer.update(cx, |buffer, _| {
2669        let snapshot = buffer.snapshot();
2670        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2671        layers[0].node().to_sexp()
2672    })
2673}
2674
2675// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2676fn assert_bracket_pairs(
2677    selection_text: &'static str,
2678    bracket_pair_texts: Vec<&'static str>,
2679    language: Language,
2680    cx: &mut AppContext,
2681) {
2682    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2683    let buffer = cx.new_model(|cx| {
2684        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2685    });
2686    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2687
2688    let selection_range = selection_ranges[0].clone();
2689
2690    let bracket_pairs = bracket_pair_texts
2691        .into_iter()
2692        .map(|pair_text| {
2693            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2694            assert_eq!(bracket_text, expected_text);
2695            (ranges[0].clone(), ranges[1].clone())
2696        })
2697        .collect::<Vec<_>>();
2698
2699    assert_set_eq!(
2700        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2701        bracket_pairs
2702    );
2703}
2704
2705fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2706    let settings_store = SettingsStore::test(cx);
2707    cx.set_global(settings_store);
2708    crate::init(cx);
2709    cx.update_global::<SettingsStore, _>(|settings, cx| {
2710        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2711    });
2712}