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