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                            newline: false,
1786                        },
1787                        BracketPair {
1788                            start: "'".into(),
1789                            end: "'".into(),
1790                            close: true,
1791                            newline: false,
1792                        },
1793                    ],
1794                    disabled_scopes_by_bracket_ix: vec![
1795                        Vec::new(), //
1796                        vec!["string".into()],
1797                    ],
1798                },
1799                overrides: [(
1800                    "element".into(),
1801                    LanguageConfigOverride {
1802                        line_comments: Override::Remove { remove: true },
1803                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1804                        ..Default::default()
1805                    },
1806                )]
1807                .into_iter()
1808                .collect(),
1809                ..Default::default()
1810            },
1811            Some(tree_sitter_typescript::language_tsx()),
1812        )
1813        .with_override_query(
1814            r#"
1815                (jsx_element) @element
1816                (string) @string
1817                [
1818                    (jsx_opening_element)
1819                    (jsx_closing_element)
1820                    (jsx_expression)
1821                ] @default
1822            "#,
1823        )
1824        .unwrap();
1825
1826        let text = r#"
1827            a["b"] = <C d="e">
1828                <F></F>
1829                { g() }
1830            </C>;
1831        "#
1832        .unindent();
1833
1834        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
1835        let snapshot = buffer.snapshot();
1836
1837        let config = snapshot.language_scope_at(0).unwrap();
1838        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
1839        // Both bracket pairs are enabled
1840        assert_eq!(
1841            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1842            &[true, true]
1843        );
1844
1845        let string_config = snapshot
1846            .language_scope_at(text.find("b\"").unwrap())
1847            .unwrap();
1848        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
1849        // Second bracket pair is disabled
1850        assert_eq!(
1851            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1852            &[true, false]
1853        );
1854
1855        // In between JSX tags: use the `element` override.
1856        let element_config = snapshot
1857            .language_scope_at(text.find("<F>").unwrap())
1858            .unwrap();
1859        assert_eq!(element_config.line_comment_prefixes(), &[]);
1860        assert_eq!(
1861            element_config.block_comment_delimiters(),
1862            Some((&"{/*".into(), &"*/}".into()))
1863        );
1864        assert_eq!(
1865            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1866            &[true, true]
1867        );
1868
1869        // Within a JSX tag: use the default config.
1870        let tag_config = snapshot
1871            .language_scope_at(text.find(" d=").unwrap() + 1)
1872            .unwrap();
1873        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
1874        assert_eq!(
1875            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1876            &[true, true]
1877        );
1878
1879        // In a JSX expression: use the default config.
1880        let expression_in_element_config = snapshot
1881            .language_scope_at(text.find('{').unwrap() + 1)
1882            .unwrap();
1883        assert_eq!(
1884            expression_in_element_config.line_comment_prefixes(),
1885            &[Arc::from("// ")]
1886        );
1887        assert_eq!(
1888            expression_in_element_config
1889                .brackets()
1890                .map(|e| e.1)
1891                .collect::<Vec<_>>(),
1892            &[true, true]
1893        );
1894
1895        buffer
1896    });
1897}
1898
1899#[gpui::test]
1900fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1901    init_settings(cx, |_| {});
1902
1903    cx.new_model(|cx| {
1904        let language = Language::new(
1905            LanguageConfig {
1906                name: "Rust".into(),
1907                brackets: BracketPairConfig {
1908                    pairs: vec![
1909                        BracketPair {
1910                            start: "{".into(),
1911                            end: "}".into(),
1912                            close: true,
1913                            newline: false,
1914                        },
1915                        BracketPair {
1916                            start: "'".into(),
1917                            end: "'".into(),
1918                            close: true,
1919                            newline: false,
1920                        },
1921                    ],
1922                    disabled_scopes_by_bracket_ix: vec![
1923                        Vec::new(), //
1924                        vec!["string".into()],
1925                    ],
1926                },
1927                ..Default::default()
1928            },
1929            Some(tree_sitter_rust::language()),
1930        )
1931        .with_override_query(
1932            r#"
1933                (string_literal) @string
1934            "#,
1935        )
1936        .unwrap();
1937
1938        let text = r#"
1939            const S: &'static str = "hello";
1940        "#
1941        .unindent();
1942
1943        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
1944        let snapshot = buffer.snapshot();
1945
1946        // By default, all brackets are enabled
1947        let config = snapshot.language_scope_at(0).unwrap();
1948        assert_eq!(
1949            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1950            &[true, true]
1951        );
1952
1953        // Within a string, the quotation brackets are disabled.
1954        let string_config = snapshot
1955            .language_scope_at(text.find("ello").unwrap())
1956            .unwrap();
1957        assert_eq!(
1958            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1959            &[true, false]
1960        );
1961
1962        buffer
1963    });
1964}
1965
1966#[gpui::test]
1967fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1968    init_settings(cx, |_| {});
1969
1970    cx.new_model(|cx| {
1971        let text = r#"
1972            <ol>
1973            <% people.each do |person| %>
1974                <li>
1975                    <%= person.name %>
1976                </li>
1977            <% end %>
1978            </ol>
1979        "#
1980        .unindent();
1981
1982        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1983        language_registry.add(Arc::new(ruby_lang()));
1984        language_registry.add(Arc::new(html_lang()));
1985        language_registry.add(Arc::new(erb_lang()));
1986
1987        let mut buffer = Buffer::local(text, cx);
1988        buffer.set_language_registry(language_registry.clone());
1989        buffer.set_language(
1990            language_registry
1991                .language_for_name("ERB")
1992                .now_or_never()
1993                .unwrap()
1994                .ok(),
1995            cx,
1996        );
1997
1998        let snapshot = buffer.snapshot();
1999        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2000        assert_eq!(html_config.line_comment_prefixes(), &[]);
2001        assert_eq!(
2002            html_config.block_comment_delimiters(),
2003            Some((&"<!--".into(), &"-->".into()))
2004        );
2005
2006        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2007        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2008        assert_eq!(ruby_config.block_comment_delimiters(), None);
2009
2010        buffer
2011    });
2012}
2013
2014#[gpui::test]
2015fn test_serialization(cx: &mut gpui::AppContext) {
2016    let mut now = Instant::now();
2017
2018    let buffer1 = cx.new_model(|cx| {
2019        let mut buffer = Buffer::local("abc", cx);
2020        buffer.edit([(3..3, "D")], None, cx);
2021
2022        now += Duration::from_secs(1);
2023        buffer.start_transaction_at(now);
2024        buffer.edit([(4..4, "E")], None, cx);
2025        buffer.end_transaction_at(now, cx);
2026        assert_eq!(buffer.text(), "abcDE");
2027
2028        buffer.undo(cx);
2029        assert_eq!(buffer.text(), "abcD");
2030
2031        buffer.edit([(4..4, "F")], None, cx);
2032        assert_eq!(buffer.text(), "abcDF");
2033        buffer
2034    });
2035    assert_eq!(buffer1.read(cx).text(), "abcDF");
2036
2037    let state = buffer1.read(cx).to_proto();
2038    let ops = cx
2039        .background_executor()
2040        .block(buffer1.read(cx).serialize_ops(None, cx));
2041    let buffer2 = cx.new_model(|cx| {
2042        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2043        buffer
2044            .apply_ops(
2045                ops.into_iter()
2046                    .map(|op| proto::deserialize_operation(op).unwrap()),
2047                cx,
2048            )
2049            .unwrap();
2050        buffer
2051    });
2052    assert_eq!(buffer2.read(cx).text(), "abcDF");
2053}
2054
2055#[gpui::test]
2056async fn test_find_matching_indent(cx: &mut TestAppContext) {
2057    cx.update(|cx| init_settings(cx, |_| {}));
2058
2059    async fn enclosing_indent(
2060        text: impl Into<String>,
2061        buffer_row: u32,
2062        cx: &mut TestAppContext,
2063    ) -> Option<(Range<u32>, LineIndent)> {
2064        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2065        let snapshot = cx.read(|cx| buffer.read(cx).snapshot());
2066        snapshot.enclosing_indent(buffer_row).await
2067    }
2068
2069    assert_eq!(
2070        enclosing_indent(
2071            "
2072        fn b() {
2073            if c {
2074                let d = 2;
2075            }
2076        }"
2077            .unindent(),
2078            1,
2079            cx,
2080        )
2081        .await,
2082        Some((
2083            1..2,
2084            LineIndent {
2085                tabs: 0,
2086                spaces: 4,
2087                line_blank: false,
2088            }
2089        ))
2090    );
2091
2092    assert_eq!(
2093        enclosing_indent(
2094            "
2095        fn b() {
2096            if c {
2097                let d = 2;
2098            }
2099        }"
2100            .unindent(),
2101            2,
2102            cx,
2103        )
2104        .await,
2105        Some((
2106            1..2,
2107            LineIndent {
2108                tabs: 0,
2109                spaces: 4,
2110                line_blank: false,
2111            }
2112        ))
2113    );
2114
2115    assert_eq!(
2116        enclosing_indent(
2117            "
2118        fn b() {
2119            if c {
2120                let d = 2;
2121
2122                let e = 5;
2123            }
2124        }"
2125            .unindent(),
2126            3,
2127            cx,
2128        )
2129        .await,
2130        Some((
2131            1..4,
2132            LineIndent {
2133                tabs: 0,
2134                spaces: 4,
2135                line_blank: false,
2136            }
2137        ))
2138    );
2139}
2140
2141#[gpui::test(iterations = 100)]
2142fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2143    let min_peers = env::var("MIN_PEERS")
2144        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2145        .unwrap_or(1);
2146    let max_peers = env::var("MAX_PEERS")
2147        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2148        .unwrap_or(5);
2149    let operations = env::var("OPERATIONS")
2150        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2151        .unwrap_or(10);
2152
2153    let base_text_len = rng.gen_range(0..10);
2154    let base_text = RandomCharIter::new(&mut rng)
2155        .take(base_text_len)
2156        .collect::<String>();
2157    let mut replica_ids = Vec::new();
2158    let mut buffers = Vec::new();
2159    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2160    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2161
2162    for i in 0..rng.gen_range(min_peers..=max_peers) {
2163        let buffer = cx.new_model(|cx| {
2164            let state = base_buffer.read(cx).to_proto();
2165            let ops = cx
2166                .background_executor()
2167                .block(base_buffer.read(cx).serialize_ops(None, cx));
2168            let mut buffer =
2169                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2170            buffer
2171                .apply_ops(
2172                    ops.into_iter()
2173                        .map(|op| proto::deserialize_operation(op).unwrap()),
2174                    cx,
2175                )
2176                .unwrap();
2177            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2178            let network = network.clone();
2179            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2180                if let Event::Operation(op) = event {
2181                    network
2182                        .lock()
2183                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2184                }
2185            })
2186            .detach();
2187            buffer
2188        });
2189
2190        buffers.push(buffer);
2191        replica_ids.push(i as ReplicaId);
2192        network.lock().add_peer(i as ReplicaId);
2193        log::info!("Adding initial peer with replica id {}", i);
2194    }
2195
2196    log::info!("initial text: {:?}", base_text);
2197
2198    let mut now = Instant::now();
2199    let mut mutation_count = operations;
2200    let mut next_diagnostic_id = 0;
2201    let mut active_selections = BTreeMap::default();
2202    loop {
2203        let replica_index = rng.gen_range(0..replica_ids.len());
2204        let replica_id = replica_ids[replica_index];
2205        let buffer = &mut buffers[replica_index];
2206        let mut new_buffer = None;
2207        match rng.gen_range(0..100) {
2208            0..=29 if mutation_count != 0 => {
2209                buffer.update(cx, |buffer, cx| {
2210                    buffer.start_transaction_at(now);
2211                    buffer.randomly_edit(&mut rng, 5, cx);
2212                    buffer.end_transaction_at(now, cx);
2213                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2214                });
2215                mutation_count -= 1;
2216            }
2217            30..=39 if mutation_count != 0 => {
2218                buffer.update(cx, |buffer, cx| {
2219                    if rng.gen_bool(0.2) {
2220                        log::info!("peer {} clearing active selections", replica_id);
2221                        active_selections.remove(&replica_id);
2222                        buffer.remove_active_selections(cx);
2223                    } else {
2224                        let mut selections = Vec::new();
2225                        for id in 0..rng.gen_range(1..=5) {
2226                            let range = buffer.random_byte_range(0, &mut rng);
2227                            selections.push(Selection {
2228                                id,
2229                                start: buffer.anchor_before(range.start),
2230                                end: buffer.anchor_before(range.end),
2231                                reversed: false,
2232                                goal: SelectionGoal::None,
2233                            });
2234                        }
2235                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2236                        log::info!(
2237                            "peer {} setting active selections: {:?}",
2238                            replica_id,
2239                            selections
2240                        );
2241                        active_selections.insert(replica_id, selections.clone());
2242                        buffer.set_active_selections(selections, false, Default::default(), cx);
2243                    }
2244                });
2245                mutation_count -= 1;
2246            }
2247            40..=49 if mutation_count != 0 && replica_id == 0 => {
2248                let entry_count = rng.gen_range(1..=5);
2249                buffer.update(cx, |buffer, cx| {
2250                    let diagnostics = DiagnosticSet::new(
2251                        (0..entry_count).map(|_| {
2252                            let range = buffer.random_byte_range(0, &mut rng);
2253                            let range = range.to_point_utf16(buffer);
2254                            let range = range.start..range.end;
2255                            DiagnosticEntry {
2256                                range,
2257                                diagnostic: Diagnostic {
2258                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2259                                    ..Default::default()
2260                                },
2261                            }
2262                        }),
2263                        buffer,
2264                    );
2265                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2266                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2267                });
2268                mutation_count -= 1;
2269            }
2270            50..=59 if replica_ids.len() < max_peers => {
2271                let old_buffer_state = buffer.read(cx).to_proto();
2272                let old_buffer_ops = cx
2273                    .background_executor()
2274                    .block(buffer.read(cx).serialize_ops(None, cx));
2275                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2276                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2277                    .choose(&mut rng)
2278                    .unwrap();
2279                log::info!(
2280                    "Adding new replica {} (replicating from {})",
2281                    new_replica_id,
2282                    replica_id
2283                );
2284                new_buffer = Some(cx.new_model(|cx| {
2285                    let mut new_buffer = Buffer::from_proto(
2286                        new_replica_id,
2287                        Capability::ReadWrite,
2288                        old_buffer_state,
2289                        None,
2290                    )
2291                    .unwrap();
2292                    new_buffer
2293                        .apply_ops(
2294                            old_buffer_ops
2295                                .into_iter()
2296                                .map(|op| deserialize_operation(op).unwrap()),
2297                            cx,
2298                        )
2299                        .unwrap();
2300                    log::info!(
2301                        "New replica {} text: {:?}",
2302                        new_buffer.replica_id(),
2303                        new_buffer.text()
2304                    );
2305                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2306                    let network = network.clone();
2307                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2308                        if let Event::Operation(op) = event {
2309                            network.lock().broadcast(
2310                                buffer.replica_id(),
2311                                vec![proto::serialize_operation(op)],
2312                            );
2313                        }
2314                    })
2315                    .detach();
2316                    new_buffer
2317                }));
2318                network.lock().replicate(replica_id, new_replica_id);
2319
2320                if new_replica_id as usize == replica_ids.len() {
2321                    replica_ids.push(new_replica_id);
2322                } else {
2323                    let new_buffer = new_buffer.take().unwrap();
2324                    while network.lock().has_unreceived(new_replica_id) {
2325                        let ops = network
2326                            .lock()
2327                            .receive(new_replica_id)
2328                            .into_iter()
2329                            .map(|op| proto::deserialize_operation(op).unwrap());
2330                        if ops.len() > 0 {
2331                            log::info!(
2332                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2333                                new_replica_id,
2334                                buffer.read(cx).version(),
2335                                ops.len(),
2336                                ops
2337                            );
2338                            new_buffer.update(cx, |new_buffer, cx| {
2339                                new_buffer.apply_ops(ops, cx).unwrap();
2340                            });
2341                        }
2342                    }
2343                    buffers[new_replica_id as usize] = new_buffer;
2344                }
2345            }
2346            60..=69 if mutation_count != 0 => {
2347                buffer.update(cx, |buffer, cx| {
2348                    buffer.randomly_undo_redo(&mut rng, cx);
2349                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2350                });
2351                mutation_count -= 1;
2352            }
2353            _ if network.lock().has_unreceived(replica_id) => {
2354                let ops = network
2355                    .lock()
2356                    .receive(replica_id)
2357                    .into_iter()
2358                    .map(|op| proto::deserialize_operation(op).unwrap());
2359                if ops.len() > 0 {
2360                    log::info!(
2361                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2362                        replica_id,
2363                        buffer.read(cx).version(),
2364                        ops.len(),
2365                        ops
2366                    );
2367                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2368                }
2369            }
2370            _ => {}
2371        }
2372
2373        now += Duration::from_millis(rng.gen_range(0..=200));
2374        buffers.extend(new_buffer);
2375
2376        for buffer in &buffers {
2377            buffer.read(cx).check_invariants();
2378        }
2379
2380        if mutation_count == 0 && network.lock().is_idle() {
2381            break;
2382        }
2383    }
2384
2385    let first_buffer = buffers[0].read(cx).snapshot();
2386    for buffer in &buffers[1..] {
2387        let buffer = buffer.read(cx).snapshot();
2388        assert_eq!(
2389            buffer.version(),
2390            first_buffer.version(),
2391            "Replica {} version != Replica 0 version",
2392            buffer.replica_id()
2393        );
2394        assert_eq!(
2395            buffer.text(),
2396            first_buffer.text(),
2397            "Replica {} text != Replica 0 text",
2398            buffer.replica_id()
2399        );
2400        assert_eq!(
2401            buffer
2402                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2403                .collect::<Vec<_>>(),
2404            first_buffer
2405                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2406                .collect::<Vec<_>>(),
2407            "Replica {} diagnostics != Replica 0 diagnostics",
2408            buffer.replica_id()
2409        );
2410    }
2411
2412    for buffer in &buffers {
2413        let buffer = buffer.read(cx).snapshot();
2414        let actual_remote_selections = buffer
2415            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2416            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2417            .collect::<Vec<_>>();
2418        let expected_remote_selections = active_selections
2419            .iter()
2420            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2421            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2422            .collect::<Vec<_>>();
2423        assert_eq!(
2424            actual_remote_selections,
2425            expected_remote_selections,
2426            "Replica {} remote selections != expected selections",
2427            buffer.replica_id()
2428        );
2429    }
2430}
2431
2432#[test]
2433fn test_contiguous_ranges() {
2434    assert_eq!(
2435        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2436        &[1..4, 5..7, 9..13]
2437    );
2438
2439    // Respects the `max_len` parameter
2440    assert_eq!(
2441        contiguous_ranges(
2442            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2443            3
2444        )
2445        .collect::<Vec<_>>(),
2446        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2447    );
2448}
2449
2450#[gpui::test(iterations = 500)]
2451fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2452    // Generate a random multi-line string containing
2453    // some lines with trailing whitespace.
2454    let mut text = String::new();
2455    for _ in 0..rng.gen_range(0..16) {
2456        for _ in 0..rng.gen_range(0..36) {
2457            text.push(match rng.gen_range(0..10) {
2458                0..=1 => ' ',
2459                3 => '\t',
2460                _ => rng.gen_range('a'..'z'),
2461            });
2462        }
2463        text.push('\n');
2464    }
2465
2466    match rng.gen_range(0..10) {
2467        // sometimes remove the last newline
2468        0..=1 => drop(text.pop()), //
2469
2470        // sometimes add extra newlines
2471        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2472        _ => {}
2473    }
2474
2475    let rope = Rope::from(text.as_str());
2476    let actual_ranges = trailing_whitespace_ranges(&rope);
2477    let expected_ranges = TRAILING_WHITESPACE_REGEX
2478        .find_iter(&text)
2479        .map(|m| m.range())
2480        .collect::<Vec<_>>();
2481    assert_eq!(
2482        actual_ranges,
2483        expected_ranges,
2484        "wrong ranges for text lines:\n{:?}",
2485        text.split('\n').collect::<Vec<_>>()
2486    );
2487}
2488
2489fn ruby_lang() -> Language {
2490    Language::new(
2491        LanguageConfig {
2492            name: "Ruby".into(),
2493            matcher: LanguageMatcher {
2494                path_suffixes: vec!["rb".to_string()],
2495                ..Default::default()
2496            },
2497            line_comments: vec!["# ".into()],
2498            ..Default::default()
2499        },
2500        Some(tree_sitter_ruby::language()),
2501    )
2502    .with_indents_query(
2503        r#"
2504            (class "end" @end) @indent
2505            (method "end" @end) @indent
2506            (rescue) @outdent
2507            (then) @indent
2508        "#,
2509    )
2510    .unwrap()
2511}
2512
2513fn html_lang() -> Language {
2514    Language::new(
2515        LanguageConfig {
2516            name: "HTML".into(),
2517            block_comment: Some(("<!--".into(), "-->".into())),
2518            ..Default::default()
2519        },
2520        Some(tree_sitter_html::language()),
2521    )
2522    .with_indents_query(
2523        "
2524        (element
2525          (start_tag) @start
2526          (end_tag)? @end) @indent
2527        ",
2528    )
2529    .unwrap()
2530    .with_injection_query(
2531        r#"
2532        (script_element
2533            (raw_text) @content
2534            (#set! "language" "javascript"))
2535        "#,
2536    )
2537    .unwrap()
2538}
2539
2540fn erb_lang() -> Language {
2541    Language::new(
2542        LanguageConfig {
2543            name: "ERB".into(),
2544            matcher: LanguageMatcher {
2545                path_suffixes: vec!["erb".to_string()],
2546                ..Default::default()
2547            },
2548            block_comment: Some(("<%#".into(), "%>".into())),
2549            ..Default::default()
2550        },
2551        Some(tree_sitter_embedded_template::language()),
2552    )
2553    .with_injection_query(
2554        r#"
2555            (
2556                (code) @content
2557                (#set! "language" "ruby")
2558                (#set! "combined")
2559            )
2560
2561            (
2562                (content) @content
2563                (#set! "language" "html")
2564                (#set! "combined")
2565            )
2566        "#,
2567    )
2568    .unwrap()
2569}
2570
2571fn rust_lang() -> Language {
2572    Language::new(
2573        LanguageConfig {
2574            name: "Rust".into(),
2575            matcher: LanguageMatcher {
2576                path_suffixes: vec!["rs".to_string()],
2577                ..Default::default()
2578            },
2579            ..Default::default()
2580        },
2581        Some(tree_sitter_rust::language()),
2582    )
2583    .with_indents_query(
2584        r#"
2585        (call_expression) @indent
2586        (field_expression) @indent
2587        (_ "(" ")" @end) @indent
2588        (_ "{" "}" @end) @indent
2589        "#,
2590    )
2591    .unwrap()
2592    .with_brackets_query(
2593        r#"
2594        ("{" @open "}" @close)
2595        "#,
2596    )
2597    .unwrap()
2598    .with_outline_query(
2599        r#"
2600        (struct_item
2601            "struct" @context
2602            name: (_) @name) @item
2603        (enum_item
2604            "enum" @context
2605            name: (_) @name) @item
2606        (enum_variant
2607            name: (_) @name) @item
2608        (field_declaration
2609            name: (_) @name) @item
2610        (impl_item
2611            "impl" @context
2612            trait: (_)? @name
2613            "for"? @context
2614            type: (_) @name) @item
2615        (function_item
2616            "fn" @context
2617            name: (_) @name) @item
2618        (mod_item
2619            "mod" @context
2620            name: (_) @name) @item
2621        "#,
2622    )
2623    .unwrap()
2624}
2625
2626fn json_lang() -> Language {
2627    Language::new(
2628        LanguageConfig {
2629            name: "Json".into(),
2630            matcher: LanguageMatcher {
2631                path_suffixes: vec!["js".to_string()],
2632                ..Default::default()
2633            },
2634            ..Default::default()
2635        },
2636        Some(tree_sitter_json::language()),
2637    )
2638}
2639
2640fn javascript_lang() -> Language {
2641    Language::new(
2642        LanguageConfig {
2643            name: "JavaScript".into(),
2644            ..Default::default()
2645        },
2646        Some(tree_sitter_typescript::language_tsx()),
2647    )
2648    .with_brackets_query(
2649        r#"
2650        ("{" @open "}" @close)
2651        ("(" @open ")" @close)
2652        "#,
2653    )
2654    .unwrap()
2655    .with_indents_query(
2656        r#"
2657        (object "}" @end) @indent
2658        "#,
2659    )
2660    .unwrap()
2661}
2662
2663fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2664    buffer.update(cx, |buffer, _| {
2665        let snapshot = buffer.snapshot();
2666        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2667        layers[0].node().to_sexp()
2668    })
2669}
2670
2671// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2672fn assert_bracket_pairs(
2673    selection_text: &'static str,
2674    bracket_pair_texts: Vec<&'static str>,
2675    language: Language,
2676    cx: &mut AppContext,
2677) {
2678    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2679    let buffer = cx.new_model(|cx| {
2680        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2681    });
2682    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2683
2684    let selection_range = selection_ranges[0].clone();
2685
2686    let bracket_pairs = bracket_pair_texts
2687        .into_iter()
2688        .map(|pair_text| {
2689            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2690            assert_eq!(bracket_text, expected_text);
2691            (ranges[0].clone(), ranges[1].clone())
2692        })
2693        .collect::<Vec<_>>();
2694
2695    assert_set_eq!(
2696        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2697        bracket_pairs
2698    );
2699}
2700
2701fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2702    let settings_store = SettingsStore::test(cx);
2703    cx.set_global(settings_store);
2704    crate::init(cx);
2705    cx.update_global::<SettingsStore, _>(|settings, cx| {
2706        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2707    });
2708}