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]
 779fn test_outline_annotations(cx: &mut AppContext) {
 780    // Add this new test case
 781    let text = r#"
 782        /// This is a doc comment
 783        /// that spans multiple lines
 784        fn annotated_function() {
 785            // This is not an annotation
 786        }
 787
 788        // This is a single-line annotation
 789        fn another_function() {}
 790
 791        fn unannotated_function() {}
 792
 793        // This comment is not an annotation
 794
 795        fn function_after_blank_line() {}
 796    "#
 797    .unindent();
 798
 799    let buffer =
 800        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 801    let outline = buffer
 802        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 803        .unwrap();
 804
 805    assert_eq!(
 806        outline
 807            .items
 808            .into_iter()
 809            .map(|item| (
 810                item.text,
 811                item.depth,
 812                item.annotation_range
 813                    .map(|range| { buffer.read(cx).text_for_range(range).collect::<String>() })
 814            ))
 815            .collect::<Vec<_>>(),
 816        &[
 817            (
 818                "fn annotated_function".to_string(),
 819                0,
 820                Some("/// This is a doc comment\n/// that spans multiple lines".to_string())
 821            ),
 822            (
 823                "fn another_function".to_string(),
 824                0,
 825                Some("// This is a single-line annotation".to_string())
 826            ),
 827            ("fn unannotated_function".to_string(), 0, None),
 828            ("fn function_after_blank_line".to_string(), 0, None),
 829        ]
 830    );
 831}
 832
 833#[gpui::test]
 834async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 835    let text = r#"
 836        impl Person {
 837            fn one() {
 838                1
 839            }
 840
 841            fn two() {
 842                2
 843            }fn three() {
 844                3
 845            }
 846        }
 847    "#
 848    .unindent();
 849
 850    let buffer =
 851        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 852    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 853
 854    // point is at the start of an item
 855    assert_eq!(
 856        symbols_containing(Point::new(1, 4), &snapshot),
 857        vec![
 858            (
 859                "impl Person".to_string(),
 860                Point::new(0, 0)..Point::new(10, 1)
 861            ),
 862            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 863        ]
 864    );
 865
 866    // point is in the middle of an item
 867    assert_eq!(
 868        symbols_containing(Point::new(2, 8), &snapshot),
 869        vec![
 870            (
 871                "impl Person".to_string(),
 872                Point::new(0, 0)..Point::new(10, 1)
 873            ),
 874            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 875        ]
 876    );
 877
 878    // point is at the end of an item
 879    assert_eq!(
 880        symbols_containing(Point::new(3, 5), &snapshot),
 881        vec![
 882            (
 883                "impl Person".to_string(),
 884                Point::new(0, 0)..Point::new(10, 1)
 885            ),
 886            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 887        ]
 888    );
 889
 890    // point is in between two adjacent items
 891    assert_eq!(
 892        symbols_containing(Point::new(7, 5), &snapshot),
 893        vec![
 894            (
 895                "impl Person".to_string(),
 896                Point::new(0, 0)..Point::new(10, 1)
 897            ),
 898            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 899        ]
 900    );
 901
 902    fn symbols_containing(
 903        position: Point,
 904        snapshot: &BufferSnapshot,
 905    ) -> Vec<(String, Range<Point>)> {
 906        snapshot
 907            .symbols_containing(position, None)
 908            .unwrap()
 909            .into_iter()
 910            .map(|item| {
 911                (
 912                    item.text,
 913                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 914                )
 915            })
 916            .collect()
 917    }
 918}
 919
 920#[gpui::test]
 921fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 922    let mut assert = |selection_text, range_markers| {
 923        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 924    };
 925
 926    assert(
 927        indoc! {"
 928            mod x {
 929                moˇd y {
 930
 931                }
 932            }
 933            let foo = 1;"},
 934        vec![indoc! {"
 935            mod x «{»
 936                mod y {
 937
 938                }
 939            «}»
 940            let foo = 1;"}],
 941    );
 942
 943    assert(
 944        indoc! {"
 945            mod x {
 946                mod y ˇ{
 947
 948                }
 949            }
 950            let foo = 1;"},
 951        vec![
 952            indoc! {"
 953                mod x «{»
 954                    mod y {
 955
 956                    }
 957                «}»
 958                let foo = 1;"},
 959            indoc! {"
 960                mod x {
 961                    mod y «{»
 962
 963                    «}»
 964                }
 965                let foo = 1;"},
 966        ],
 967    );
 968
 969    assert(
 970        indoc! {"
 971            mod x {
 972                mod y {
 973
 974 975            }
 976            let foo = 1;"},
 977        vec![
 978            indoc! {"
 979                mod x «{»
 980                    mod y {
 981
 982                    }
 983                «}»
 984                let foo = 1;"},
 985            indoc! {"
 986                mod x {
 987                    mod y «{»
 988
 989                    «}»
 990                }
 991                let foo = 1;"},
 992        ],
 993    );
 994
 995    assert(
 996        indoc! {"
 997            mod x {
 998                mod y {
 999
1000                }
1001            ˇ}
1002            let foo = 1;"},
1003        vec![indoc! {"
1004            mod x «{»
1005                mod y {
1006
1007                }
1008            «}»
1009            let foo = 1;"}],
1010    );
1011
1012    assert(
1013        indoc! {"
1014            mod x {
1015                mod y {
1016
1017                }
1018            }
1019            let fˇoo = 1;"},
1020        vec![],
1021    );
1022
1023    // Regression test: avoid crash when querying at the end of the buffer.
1024    assert(
1025        indoc! {"
1026            mod x {
1027                mod y {
1028
1029                }
1030            }
1031            let foo = 1;ˇ"},
1032        vec![],
1033    );
1034}
1035
1036#[gpui::test]
1037fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
1038    let mut assert = |selection_text, bracket_pair_texts| {
1039        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
1040    };
1041
1042    assert(
1043        indoc! {"
1044        for (const a in b)ˇ {
1045            // a comment that's longer than the for-loop header
1046        }"},
1047        vec![indoc! {"
1048        for «(»const a in b«)» {
1049            // a comment that's longer than the for-loop header
1050        }"}],
1051    );
1052
1053    // Regression test: even though the parent node of the parentheses (the for loop) does
1054    // intersect the given range, the parentheses themselves do not contain the range, so
1055    // they should not be returned. Only the curly braces contain the range.
1056    assert(
1057        indoc! {"
1058        for (const a in b) {ˇ
1059            // a comment that's longer than the for-loop header
1060        }"},
1061        vec![indoc! {"
1062        for (const a in b) «{»
1063            // a comment that's longer than the for-loop header
1064        «}»"}],
1065    );
1066}
1067
1068#[gpui::test]
1069fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
1070    cx.new_model(|cx| {
1071        let text = "fn a() { b(|c| {}) }";
1072        let buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1073        let snapshot = buffer.snapshot();
1074
1075        assert_eq!(
1076            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
1077            Some(range_of(text, "|"))
1078        );
1079        assert_eq!(
1080            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
1081            Some(range_of(text, "|c|"))
1082        );
1083        assert_eq!(
1084            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
1085            Some(range_of(text, "|c| {}"))
1086        );
1087        assert_eq!(
1088            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
1089            Some(range_of(text, "(|c| {})"))
1090        );
1091
1092        buffer
1093    });
1094
1095    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
1096        let start = text.find(part).unwrap();
1097        start..start
1098    }
1099
1100    fn range_of(text: &str, part: &str) -> Range<usize> {
1101        let start = text.find(part).unwrap();
1102        start..start + part.len()
1103    }
1104}
1105
1106#[gpui::test]
1107fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
1108    init_settings(cx, |_| {});
1109
1110    cx.new_model(|cx| {
1111        let text = "fn a() {}";
1112        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1113
1114        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1115        assert_eq!(buffer.text(), "fn a() {\n    \n}");
1116
1117        buffer.edit(
1118            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
1119            Some(AutoindentMode::EachLine),
1120            cx,
1121        );
1122        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
1123
1124        // Create a field expression on a new line, causing that line
1125        // to be indented.
1126        buffer.edit(
1127            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
1128            Some(AutoindentMode::EachLine),
1129            cx,
1130        );
1131        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
1132
1133        // Remove the dot so that the line is no longer a field expression,
1134        // causing the line to be outdented.
1135        buffer.edit(
1136            [(Point::new(2, 8)..Point::new(2, 9), "")],
1137            Some(AutoindentMode::EachLine),
1138            cx,
1139        );
1140        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
1141
1142        buffer
1143    });
1144}
1145
1146#[gpui::test]
1147fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
1148    init_settings(cx, |settings| {
1149        settings.defaults.hard_tabs = Some(true);
1150    });
1151
1152    cx.new_model(|cx| {
1153        let text = "fn a() {}";
1154        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1155
1156        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1157        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
1158
1159        buffer.edit(
1160            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
1161            Some(AutoindentMode::EachLine),
1162            cx,
1163        );
1164        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1165
1166        // Create a field expression on a new line, causing that line
1167        // to be indented.
1168        buffer.edit(
1169            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1170            Some(AutoindentMode::EachLine),
1171            cx,
1172        );
1173        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1174
1175        // Remove the dot so that the line is no longer a field expression,
1176        // causing the line to be outdented.
1177        buffer.edit(
1178            [(Point::new(2, 2)..Point::new(2, 3), "")],
1179            Some(AutoindentMode::EachLine),
1180            cx,
1181        );
1182        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1183
1184        buffer
1185    });
1186}
1187
1188#[gpui::test]
1189fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1190    init_settings(cx, |_| {});
1191
1192    cx.new_model(|cx| {
1193        let mut buffer = Buffer::local(
1194            "
1195            fn a() {
1196            c;
1197            d;
1198            }
1199            "
1200            .unindent(),
1201            cx,
1202        )
1203        .with_language(Arc::new(rust_lang()), cx);
1204
1205        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1206        // their indentation is not adjusted.
1207        buffer.edit_via_marked_text(
1208            &"
1209            fn a() {
1210            c«()»;
1211            d«()»;
1212            }
1213            "
1214            .unindent(),
1215            Some(AutoindentMode::EachLine),
1216            cx,
1217        );
1218        assert_eq!(
1219            buffer.text(),
1220            "
1221            fn a() {
1222            c();
1223            d();
1224            }
1225            "
1226            .unindent()
1227        );
1228
1229        // When appending new content after these lines, the indentation is based on the
1230        // preceding lines' actual indentation.
1231        buffer.edit_via_marked_text(
1232            &"
1233            fn a() {
12341235            .f
1236            .g()»;
12371238            .f
1239            .g()»;
1240            }
1241            "
1242            .unindent(),
1243            Some(AutoindentMode::EachLine),
1244            cx,
1245        );
1246
1247        assert_eq!(
1248            buffer.text(),
1249            "
1250            fn a() {
1251            c
1252                .f
1253                .g();
1254            d
1255                .f
1256                .g();
1257            }
1258            "
1259            .unindent()
1260        );
1261        buffer
1262    });
1263
1264    cx.new_model(|cx| {
1265        eprintln!("second buffer: {:?}", cx.entity_id());
1266
1267        let mut buffer = Buffer::local(
1268            "
1269            fn a() {
1270                b();
1271                |
1272            "
1273            .replace('|', "") // marker to preserve trailing whitespace
1274            .unindent(),
1275            cx,
1276        )
1277        .with_language(Arc::new(rust_lang()), cx);
1278
1279        // Insert a closing brace. It is outdented.
1280        buffer.edit_via_marked_text(
1281            &"
1282            fn a() {
1283                b();
1284                «}»
1285            "
1286            .unindent(),
1287            Some(AutoindentMode::EachLine),
1288            cx,
1289        );
1290        assert_eq!(
1291            buffer.text(),
1292            "
1293            fn a() {
1294                b();
1295            }
1296            "
1297            .unindent()
1298        );
1299
1300        // Manually edit the leading whitespace. The edit is preserved.
1301        buffer.edit_via_marked_text(
1302            &"
1303            fn a() {
1304                b();
1305            «    »}
1306            "
1307            .unindent(),
1308            Some(AutoindentMode::EachLine),
1309            cx,
1310        );
1311        assert_eq!(
1312            buffer.text(),
1313            "
1314            fn a() {
1315                b();
1316                }
1317            "
1318            .unindent()
1319        );
1320        buffer
1321    });
1322
1323    eprintln!("DONE");
1324}
1325
1326#[gpui::test]
1327fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1328    init_settings(cx, |_| {});
1329
1330    cx.new_model(|cx| {
1331        let mut buffer = Buffer::local(
1332            "
1333            fn a() {
1334                i
1335            }
1336            "
1337            .unindent(),
1338            cx,
1339        )
1340        .with_language(Arc::new(rust_lang()), cx);
1341
1342        // Regression test: line does not get outdented due to syntax error
1343        buffer.edit_via_marked_text(
1344            &"
1345            fn a() {
1346                i«f let Some(x) = y»
1347            }
1348            "
1349            .unindent(),
1350            Some(AutoindentMode::EachLine),
1351            cx,
1352        );
1353        assert_eq!(
1354            buffer.text(),
1355            "
1356            fn a() {
1357                if let Some(x) = y
1358            }
1359            "
1360            .unindent()
1361        );
1362
1363        buffer.edit_via_marked_text(
1364            &"
1365            fn a() {
1366                if let Some(x) = y« {»
1367            }
1368            "
1369            .unindent(),
1370            Some(AutoindentMode::EachLine),
1371            cx,
1372        );
1373        assert_eq!(
1374            buffer.text(),
1375            "
1376            fn a() {
1377                if let Some(x) = y {
1378            }
1379            "
1380            .unindent()
1381        );
1382
1383        buffer
1384    });
1385}
1386
1387#[gpui::test]
1388fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1389    init_settings(cx, |_| {});
1390
1391    cx.new_model(|cx| {
1392        let mut buffer = Buffer::local(
1393            "
1394            fn a() {}
1395            "
1396            .unindent(),
1397            cx,
1398        )
1399        .with_language(Arc::new(rust_lang()), cx);
1400
1401        buffer.edit_via_marked_text(
1402            &"
1403            fn a(«
1404            b») {}
1405            "
1406            .unindent(),
1407            Some(AutoindentMode::EachLine),
1408            cx,
1409        );
1410        assert_eq!(
1411            buffer.text(),
1412            "
1413            fn a(
1414                b) {}
1415            "
1416            .unindent()
1417        );
1418
1419        // The indentation suggestion changed because `@end` node (a close paren)
1420        // is now at the beginning of the line.
1421        buffer.edit_via_marked_text(
1422            &"
1423            fn a(
1424                ˇ) {}
1425            "
1426            .unindent(),
1427            Some(AutoindentMode::EachLine),
1428            cx,
1429        );
1430        assert_eq!(
1431            buffer.text(),
1432            "
1433                fn a(
1434                ) {}
1435            "
1436            .unindent()
1437        );
1438
1439        buffer
1440    });
1441}
1442
1443#[gpui::test]
1444fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1445    init_settings(cx, |_| {});
1446
1447    cx.new_model(|cx| {
1448        let text = "a\nb";
1449        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1450        buffer.edit(
1451            [(0..1, "\n"), (2..3, "\n")],
1452            Some(AutoindentMode::EachLine),
1453            cx,
1454        );
1455        assert_eq!(buffer.text(), "\n\n\n");
1456        buffer
1457    });
1458}
1459
1460#[gpui::test]
1461fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1462    init_settings(cx, |_| {});
1463
1464    cx.new_model(|cx| {
1465        let text = "
1466            const a: usize = 1;
1467            fn b() {
1468                if c {
1469                    let d = 2;
1470                }
1471            }
1472        "
1473        .unindent();
1474
1475        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1476        buffer.edit(
1477            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1478            Some(AutoindentMode::EachLine),
1479            cx,
1480        );
1481        assert_eq!(
1482            buffer.text(),
1483            "
1484                const a: usize = 1;
1485                fn b() {
1486                    if c {
1487                        e(
1488                            f()
1489                        );
1490                        let d = 2;
1491                    }
1492                }
1493            "
1494            .unindent()
1495        );
1496
1497        buffer
1498    });
1499}
1500
1501#[gpui::test]
1502fn test_autoindent_block_mode(cx: &mut AppContext) {
1503    init_settings(cx, |_| {});
1504
1505    cx.new_model(|cx| {
1506        let text = r#"
1507            fn a() {
1508                b();
1509            }
1510        "#
1511        .unindent();
1512        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1513
1514        // When this text was copied, both of the quotation marks were at the same
1515        // indent level, but the indentation of the first line was not included in
1516        // the copied text. This information is retained in the
1517        // 'original_indent_columns' vector.
1518        let original_indent_columns = vec![4];
1519        let inserted_text = r#"
1520            "
1521                  c
1522                    d
1523                      e
1524                "
1525        "#
1526        .unindent();
1527
1528        // Insert the block at column zero. The entire block is indented
1529        // so that the first line matches the previous line's indentation.
1530        buffer.edit(
1531            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1532            Some(AutoindentMode::Block {
1533                original_indent_columns: original_indent_columns.clone(),
1534            }),
1535            cx,
1536        );
1537        assert_eq!(
1538            buffer.text(),
1539            r#"
1540            fn a() {
1541                b();
1542                "
1543                  c
1544                    d
1545                      e
1546                "
1547            }
1548            "#
1549            .unindent()
1550        );
1551
1552        // Grouping is disabled in tests, so we need 2 undos
1553        buffer.undo(cx); // Undo the auto-indent
1554        buffer.undo(cx); // Undo the original edit
1555
1556        // Insert the block at a deeper indent level. The entire block is outdented.
1557        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1558        buffer.edit(
1559            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1560            Some(AutoindentMode::Block {
1561                original_indent_columns: original_indent_columns.clone(),
1562            }),
1563            cx,
1564        );
1565        assert_eq!(
1566            buffer.text(),
1567            r#"
1568            fn a() {
1569                b();
1570                "
1571                  c
1572                    d
1573                      e
1574                "
1575            }
1576            "#
1577            .unindent()
1578        );
1579
1580        buffer
1581    });
1582}
1583
1584#[gpui::test]
1585fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1586    init_settings(cx, |_| {});
1587
1588    cx.new_model(|cx| {
1589        let text = r#"
1590            fn a() {
1591                if b() {
1592
1593                }
1594            }
1595        "#
1596        .unindent();
1597        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1598
1599        // The original indent columns are not known, so this text is
1600        // auto-indented in a block as if the first line was copied in
1601        // its entirety.
1602        let original_indent_columns = Vec::new();
1603        let inserted_text = "    c\n        .d()\n        .e();";
1604
1605        // Insert the block at column zero. The entire block is indented
1606        // so that the first line matches the previous line's indentation.
1607        buffer.edit(
1608            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1609            Some(AutoindentMode::Block {
1610                original_indent_columns: original_indent_columns.clone(),
1611            }),
1612            cx,
1613        );
1614        assert_eq!(
1615            buffer.text(),
1616            r#"
1617            fn a() {
1618                if b() {
1619                    c
1620                        .d()
1621                        .e();
1622                }
1623            }
1624            "#
1625            .unindent()
1626        );
1627
1628        // Grouping is disabled in tests, so we need 2 undos
1629        buffer.undo(cx); // Undo the auto-indent
1630        buffer.undo(cx); // Undo the original edit
1631
1632        // Insert the block at a deeper indent level. The entire block is outdented.
1633        buffer.edit(
1634            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1635            None,
1636            cx,
1637        );
1638        buffer.edit(
1639            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1640            Some(AutoindentMode::Block {
1641                original_indent_columns: Vec::new(),
1642            }),
1643            cx,
1644        );
1645        assert_eq!(
1646            buffer.text(),
1647            r#"
1648            fn a() {
1649                if b() {
1650                    c
1651                        .d()
1652                        .e();
1653                }
1654            }
1655            "#
1656            .unindent()
1657        );
1658
1659        buffer
1660    });
1661}
1662
1663#[gpui::test]
1664fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1665    init_settings(cx, |_| {});
1666
1667    cx.new_model(|cx| {
1668        let text = "
1669            * one
1670                - a
1671                - b
1672            * two
1673        "
1674        .unindent();
1675
1676        let mut buffer = Buffer::local(text, cx).with_language(
1677            Arc::new(Language::new(
1678                LanguageConfig {
1679                    name: "Markdown".into(),
1680                    auto_indent_using_last_non_empty_line: false,
1681                    ..Default::default()
1682                },
1683                Some(tree_sitter_json::language()),
1684            )),
1685            cx,
1686        );
1687        buffer.edit(
1688            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1689            Some(AutoindentMode::EachLine),
1690            cx,
1691        );
1692        assert_eq!(
1693            buffer.text(),
1694            "
1695            * one
1696                - a
1697                - b
1698
1699            * two
1700            "
1701            .unindent()
1702        );
1703        buffer
1704    });
1705}
1706
1707#[gpui::test]
1708fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1709    init_settings(cx, |settings| {
1710        settings.languages.extend([
1711            (
1712                "HTML".into(),
1713                LanguageSettingsContent {
1714                    tab_size: Some(2.try_into().unwrap()),
1715                    ..Default::default()
1716                },
1717            ),
1718            (
1719                "JavaScript".into(),
1720                LanguageSettingsContent {
1721                    tab_size: Some(8.try_into().unwrap()),
1722                    ..Default::default()
1723                },
1724            ),
1725        ])
1726    });
1727
1728    let html_language = Arc::new(html_lang());
1729
1730    let javascript_language = Arc::new(javascript_lang());
1731
1732    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1733    language_registry.add(html_language.clone());
1734    language_registry.add(javascript_language.clone());
1735
1736    cx.new_model(|cx| {
1737        let (text, ranges) = marked_text_ranges(
1738            &"
1739                <div>ˇ
1740                </div>
1741                <script>
1742                    init({ˇ
1743                    })
1744                </script>
1745                <span>ˇ
1746                </span>
1747            "
1748            .unindent(),
1749            false,
1750        );
1751
1752        let mut buffer = Buffer::local(text, cx);
1753        buffer.set_language_registry(language_registry);
1754        buffer.set_language(Some(html_language), cx);
1755        buffer.edit(
1756            ranges.into_iter().map(|range| (range, "\na")),
1757            Some(AutoindentMode::EachLine),
1758            cx,
1759        );
1760        assert_eq!(
1761            buffer.text(),
1762            "
1763                <div>
1764                  a
1765                </div>
1766                <script>
1767                    init({
1768                            a
1769                    })
1770                </script>
1771                <span>
1772                  a
1773                </span>
1774            "
1775            .unindent()
1776        );
1777        buffer
1778    });
1779}
1780
1781#[gpui::test]
1782fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1783    init_settings(cx, |settings| {
1784        settings.defaults.tab_size = Some(2.try_into().unwrap());
1785    });
1786
1787    cx.new_model(|cx| {
1788        let mut buffer = Buffer::local("", cx).with_language(Arc::new(ruby_lang()), cx);
1789
1790        let text = r#"
1791            class C
1792            def a(b, c)
1793            puts b
1794            puts c
1795            rescue
1796            puts "errored"
1797            exit 1
1798            end
1799            end
1800        "#
1801        .unindent();
1802
1803        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1804
1805        assert_eq!(
1806            buffer.text(),
1807            r#"
1808                class C
1809                  def a(b, c)
1810                    puts b
1811                    puts c
1812                  rescue
1813                    puts "errored"
1814                    exit 1
1815                  end
1816                end
1817            "#
1818            .unindent()
1819        );
1820
1821        buffer
1822    });
1823}
1824
1825#[gpui::test]
1826fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1827    init_settings(cx, |_| {});
1828
1829    cx.new_model(|cx| {
1830        let language = Language::new(
1831            LanguageConfig {
1832                name: "JavaScript".into(),
1833                line_comments: vec!["// ".into()],
1834                brackets: BracketPairConfig {
1835                    pairs: vec![
1836                        BracketPair {
1837                            start: "{".into(),
1838                            end: "}".into(),
1839                            close: true,
1840                            surround: true,
1841                            newline: false,
1842                        },
1843                        BracketPair {
1844                            start: "'".into(),
1845                            end: "'".into(),
1846                            close: true,
1847                            surround: true,
1848                            newline: false,
1849                        },
1850                    ],
1851                    disabled_scopes_by_bracket_ix: vec![
1852                        Vec::new(), //
1853                        vec!["string".into()],
1854                    ],
1855                },
1856                overrides: [(
1857                    "element".into(),
1858                    LanguageConfigOverride {
1859                        line_comments: Override::Remove { remove: true },
1860                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1861                        ..Default::default()
1862                    },
1863                )]
1864                .into_iter()
1865                .collect(),
1866                ..Default::default()
1867            },
1868            Some(tree_sitter_typescript::language_tsx()),
1869        )
1870        .with_override_query(
1871            r#"
1872                (jsx_element) @element
1873                (string) @string
1874                [
1875                    (jsx_opening_element)
1876                    (jsx_closing_element)
1877                    (jsx_expression)
1878                ] @default
1879            "#,
1880        )
1881        .unwrap();
1882
1883        let text = r#"
1884            a["b"] = <C d="e">
1885                <F></F>
1886                { g() }
1887            </C>;
1888        "#
1889        .unindent();
1890
1891        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
1892        let snapshot = buffer.snapshot();
1893
1894        let config = snapshot.language_scope_at(0).unwrap();
1895        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
1896        // Both bracket pairs are enabled
1897        assert_eq!(
1898            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1899            &[true, true]
1900        );
1901
1902        let string_config = snapshot
1903            .language_scope_at(text.find("b\"").unwrap())
1904            .unwrap();
1905        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
1906        // Second bracket pair is disabled
1907        assert_eq!(
1908            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1909            &[true, false]
1910        );
1911
1912        // In between JSX tags: use the `element` override.
1913        let element_config = snapshot
1914            .language_scope_at(text.find("<F>").unwrap())
1915            .unwrap();
1916        // TODO nested blocks after newlines are captured with all whitespaces
1917        // https://github.com/tree-sitter/tree-sitter-typescript/issues/306
1918        // assert_eq!(element_config.line_comment_prefixes(), &[]);
1919        // assert_eq!(
1920        //     element_config.block_comment_delimiters(),
1921        //     Some((&"{/*".into(), &"*/}".into()))
1922        // );
1923        assert_eq!(
1924            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1925            &[true, true]
1926        );
1927
1928        // Within a JSX tag: use the default config.
1929        let tag_config = snapshot
1930            .language_scope_at(text.find(" d=").unwrap() + 1)
1931            .unwrap();
1932        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
1933        assert_eq!(
1934            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1935            &[true, true]
1936        );
1937
1938        // In a JSX expression: use the default config.
1939        let expression_in_element_config = snapshot
1940            .language_scope_at(text.find('{').unwrap() + 1)
1941            .unwrap();
1942        assert_eq!(
1943            expression_in_element_config.line_comment_prefixes(),
1944            &[Arc::from("// ")]
1945        );
1946        assert_eq!(
1947            expression_in_element_config
1948                .brackets()
1949                .map(|e| e.1)
1950                .collect::<Vec<_>>(),
1951            &[true, true]
1952        );
1953
1954        buffer
1955    });
1956}
1957
1958#[gpui::test]
1959fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1960    init_settings(cx, |_| {});
1961
1962    cx.new_model(|cx| {
1963        let language = Language::new(
1964            LanguageConfig {
1965                name: "Rust".into(),
1966                brackets: BracketPairConfig {
1967                    pairs: vec![
1968                        BracketPair {
1969                            start: "{".into(),
1970                            end: "}".into(),
1971                            close: true,
1972                            surround: true,
1973                            newline: false,
1974                        },
1975                        BracketPair {
1976                            start: "'".into(),
1977                            end: "'".into(),
1978                            close: true,
1979                            surround: true,
1980                            newline: false,
1981                        },
1982                    ],
1983                    disabled_scopes_by_bracket_ix: vec![
1984                        Vec::new(), //
1985                        vec!["string".into()],
1986                    ],
1987                },
1988                ..Default::default()
1989            },
1990            Some(tree_sitter_rust::language()),
1991        )
1992        .with_override_query(
1993            r#"
1994                (string_literal) @string
1995            "#,
1996        )
1997        .unwrap();
1998
1999        let text = r#"
2000            const S: &'static str = "hello";
2001        "#
2002        .unindent();
2003
2004        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
2005        let snapshot = buffer.snapshot();
2006
2007        // By default, all brackets are enabled
2008        let config = snapshot.language_scope_at(0).unwrap();
2009        assert_eq!(
2010            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2011            &[true, true]
2012        );
2013
2014        // Within a string, the quotation brackets are disabled.
2015        let string_config = snapshot
2016            .language_scope_at(text.find("ello").unwrap())
2017            .unwrap();
2018        assert_eq!(
2019            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2020            &[true, false]
2021        );
2022
2023        buffer
2024    });
2025}
2026
2027#[gpui::test]
2028fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
2029    init_settings(cx, |_| {});
2030
2031    cx.new_model(|cx| {
2032        let text = r#"
2033            <ol>
2034            <% people.each do |person| %>
2035                <li>
2036                    <%= person.name %>
2037                </li>
2038            <% end %>
2039            </ol>
2040        "#
2041        .unindent();
2042
2043        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2044        language_registry.add(Arc::new(ruby_lang()));
2045        language_registry.add(Arc::new(html_lang()));
2046        language_registry.add(Arc::new(erb_lang()));
2047
2048        let mut buffer = Buffer::local(text, cx);
2049        buffer.set_language_registry(language_registry.clone());
2050        buffer.set_language(
2051            language_registry
2052                .language_for_name("ERB")
2053                .now_or_never()
2054                .unwrap()
2055                .ok(),
2056            cx,
2057        );
2058
2059        let snapshot = buffer.snapshot();
2060        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2061        assert_eq!(html_config.line_comment_prefixes(), &[]);
2062        assert_eq!(
2063            html_config.block_comment_delimiters(),
2064            Some((&"<!--".into(), &"-->".into()))
2065        );
2066
2067        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2068        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2069        assert_eq!(ruby_config.block_comment_delimiters(), None);
2070
2071        buffer
2072    });
2073}
2074
2075#[gpui::test]
2076fn test_serialization(cx: &mut gpui::AppContext) {
2077    let mut now = Instant::now();
2078
2079    let buffer1 = cx.new_model(|cx| {
2080        let mut buffer = Buffer::local("abc", cx);
2081        buffer.edit([(3..3, "D")], None, cx);
2082
2083        now += Duration::from_secs(1);
2084        buffer.start_transaction_at(now);
2085        buffer.edit([(4..4, "E")], None, cx);
2086        buffer.end_transaction_at(now, cx);
2087        assert_eq!(buffer.text(), "abcDE");
2088
2089        buffer.undo(cx);
2090        assert_eq!(buffer.text(), "abcD");
2091
2092        buffer.edit([(4..4, "F")], None, cx);
2093        assert_eq!(buffer.text(), "abcDF");
2094        buffer
2095    });
2096    assert_eq!(buffer1.read(cx).text(), "abcDF");
2097
2098    let state = buffer1.read(cx).to_proto(cx);
2099    let ops = cx
2100        .background_executor()
2101        .block(buffer1.read(cx).serialize_ops(None, cx));
2102    let buffer2 = cx.new_model(|cx| {
2103        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2104        buffer
2105            .apply_ops(
2106                ops.into_iter()
2107                    .map(|op| proto::deserialize_operation(op).unwrap()),
2108                cx,
2109            )
2110            .unwrap();
2111        buffer
2112    });
2113    assert_eq!(buffer2.read(cx).text(), "abcDF");
2114}
2115
2116#[gpui::test]
2117async fn test_find_matching_indent(cx: &mut TestAppContext) {
2118    cx.update(|cx| init_settings(cx, |_| {}));
2119
2120    async fn enclosing_indent(
2121        text: impl Into<String>,
2122        buffer_row: u32,
2123        cx: &mut TestAppContext,
2124    ) -> Option<(Range<u32>, LineIndent)> {
2125        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2126        let snapshot = cx.read(|cx| buffer.read(cx).snapshot());
2127        snapshot.enclosing_indent(buffer_row).await
2128    }
2129
2130    assert_eq!(
2131        enclosing_indent(
2132            "
2133        fn b() {
2134            if c {
2135                let d = 2;
2136            }
2137        }"
2138            .unindent(),
2139            1,
2140            cx,
2141        )
2142        .await,
2143        Some((
2144            1..2,
2145            LineIndent {
2146                tabs: 0,
2147                spaces: 4,
2148                line_blank: false,
2149            }
2150        ))
2151    );
2152
2153    assert_eq!(
2154        enclosing_indent(
2155            "
2156        fn b() {
2157            if c {
2158                let d = 2;
2159            }
2160        }"
2161            .unindent(),
2162            2,
2163            cx,
2164        )
2165        .await,
2166        Some((
2167            1..2,
2168            LineIndent {
2169                tabs: 0,
2170                spaces: 4,
2171                line_blank: false,
2172            }
2173        ))
2174    );
2175
2176    assert_eq!(
2177        enclosing_indent(
2178            "
2179        fn b() {
2180            if c {
2181                let d = 2;
2182
2183                let e = 5;
2184            }
2185        }"
2186            .unindent(),
2187            3,
2188            cx,
2189        )
2190        .await,
2191        Some((
2192            1..4,
2193            LineIndent {
2194                tabs: 0,
2195                spaces: 4,
2196                line_blank: false,
2197            }
2198        ))
2199    );
2200}
2201
2202#[gpui::test(iterations = 100)]
2203fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2204    let min_peers = env::var("MIN_PEERS")
2205        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2206        .unwrap_or(1);
2207    let max_peers = env::var("MAX_PEERS")
2208        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2209        .unwrap_or(5);
2210    let operations = env::var("OPERATIONS")
2211        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2212        .unwrap_or(10);
2213
2214    let base_text_len = rng.gen_range(0..10);
2215    let base_text = RandomCharIter::new(&mut rng)
2216        .take(base_text_len)
2217        .collect::<String>();
2218    let mut replica_ids = Vec::new();
2219    let mut buffers = Vec::new();
2220    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2221    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2222
2223    for i in 0..rng.gen_range(min_peers..=max_peers) {
2224        let buffer = cx.new_model(|cx| {
2225            let state = base_buffer.read(cx).to_proto(cx);
2226            let ops = cx
2227                .background_executor()
2228                .block(base_buffer.read(cx).serialize_ops(None, cx));
2229            let mut buffer =
2230                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2231            buffer
2232                .apply_ops(
2233                    ops.into_iter()
2234                        .map(|op| proto::deserialize_operation(op).unwrap()),
2235                    cx,
2236                )
2237                .unwrap();
2238            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2239            let network = network.clone();
2240            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2241                if let Event::Operation(op) = event {
2242                    network
2243                        .lock()
2244                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2245                }
2246            })
2247            .detach();
2248            buffer
2249        });
2250
2251        buffers.push(buffer);
2252        replica_ids.push(i as ReplicaId);
2253        network.lock().add_peer(i as ReplicaId);
2254        log::info!("Adding initial peer with replica id {}", i);
2255    }
2256
2257    log::info!("initial text: {:?}", base_text);
2258
2259    let mut now = Instant::now();
2260    let mut mutation_count = operations;
2261    let mut next_diagnostic_id = 0;
2262    let mut active_selections = BTreeMap::default();
2263    loop {
2264        let replica_index = rng.gen_range(0..replica_ids.len());
2265        let replica_id = replica_ids[replica_index];
2266        let buffer = &mut buffers[replica_index];
2267        let mut new_buffer = None;
2268        match rng.gen_range(0..100) {
2269            0..=29 if mutation_count != 0 => {
2270                buffer.update(cx, |buffer, cx| {
2271                    buffer.start_transaction_at(now);
2272                    buffer.randomly_edit(&mut rng, 5, cx);
2273                    buffer.end_transaction_at(now, cx);
2274                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2275                });
2276                mutation_count -= 1;
2277            }
2278            30..=39 if mutation_count != 0 => {
2279                buffer.update(cx, |buffer, cx| {
2280                    if rng.gen_bool(0.2) {
2281                        log::info!("peer {} clearing active selections", replica_id);
2282                        active_selections.remove(&replica_id);
2283                        buffer.remove_active_selections(cx);
2284                    } else {
2285                        let mut selections = Vec::new();
2286                        for id in 0..rng.gen_range(1..=5) {
2287                            let range = buffer.random_byte_range(0, &mut rng);
2288                            selections.push(Selection {
2289                                id,
2290                                start: buffer.anchor_before(range.start),
2291                                end: buffer.anchor_before(range.end),
2292                                reversed: false,
2293                                goal: SelectionGoal::None,
2294                            });
2295                        }
2296                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2297                        log::info!(
2298                            "peer {} setting active selections: {:?}",
2299                            replica_id,
2300                            selections
2301                        );
2302                        active_selections.insert(replica_id, selections.clone());
2303                        buffer.set_active_selections(selections, false, Default::default(), cx);
2304                    }
2305                });
2306                mutation_count -= 1;
2307            }
2308            40..=49 if mutation_count != 0 && replica_id == 0 => {
2309                let entry_count = rng.gen_range(1..=5);
2310                buffer.update(cx, |buffer, cx| {
2311                    let diagnostics = DiagnosticSet::new(
2312                        (0..entry_count).map(|_| {
2313                            let range = buffer.random_byte_range(0, &mut rng);
2314                            let range = range.to_point_utf16(buffer);
2315                            let range = range.start..range.end;
2316                            DiagnosticEntry {
2317                                range,
2318                                diagnostic: Diagnostic {
2319                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2320                                    ..Default::default()
2321                                },
2322                            }
2323                        }),
2324                        buffer,
2325                    );
2326                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2327                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2328                });
2329                mutation_count -= 1;
2330            }
2331            50..=59 if replica_ids.len() < max_peers => {
2332                let old_buffer_state = buffer.read(cx).to_proto(cx);
2333                let old_buffer_ops = cx
2334                    .background_executor()
2335                    .block(buffer.read(cx).serialize_ops(None, cx));
2336                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2337                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2338                    .choose(&mut rng)
2339                    .unwrap();
2340                log::info!(
2341                    "Adding new replica {} (replicating from {})",
2342                    new_replica_id,
2343                    replica_id
2344                );
2345                new_buffer = Some(cx.new_model(|cx| {
2346                    let mut new_buffer = Buffer::from_proto(
2347                        new_replica_id,
2348                        Capability::ReadWrite,
2349                        old_buffer_state,
2350                        None,
2351                    )
2352                    .unwrap();
2353                    new_buffer
2354                        .apply_ops(
2355                            old_buffer_ops
2356                                .into_iter()
2357                                .map(|op| deserialize_operation(op).unwrap()),
2358                            cx,
2359                        )
2360                        .unwrap();
2361                    log::info!(
2362                        "New replica {} text: {:?}",
2363                        new_buffer.replica_id(),
2364                        new_buffer.text()
2365                    );
2366                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2367                    let network = network.clone();
2368                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2369                        if let Event::Operation(op) = event {
2370                            network.lock().broadcast(
2371                                buffer.replica_id(),
2372                                vec![proto::serialize_operation(op)],
2373                            );
2374                        }
2375                    })
2376                    .detach();
2377                    new_buffer
2378                }));
2379                network.lock().replicate(replica_id, new_replica_id);
2380
2381                if new_replica_id as usize == replica_ids.len() {
2382                    replica_ids.push(new_replica_id);
2383                } else {
2384                    let new_buffer = new_buffer.take().unwrap();
2385                    while network.lock().has_unreceived(new_replica_id) {
2386                        let ops = network
2387                            .lock()
2388                            .receive(new_replica_id)
2389                            .into_iter()
2390                            .map(|op| proto::deserialize_operation(op).unwrap());
2391                        if ops.len() > 0 {
2392                            log::info!(
2393                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2394                                new_replica_id,
2395                                buffer.read(cx).version(),
2396                                ops.len(),
2397                                ops
2398                            );
2399                            new_buffer.update(cx, |new_buffer, cx| {
2400                                new_buffer.apply_ops(ops, cx).unwrap();
2401                            });
2402                        }
2403                    }
2404                    buffers[new_replica_id as usize] = new_buffer;
2405                }
2406            }
2407            60..=69 if mutation_count != 0 => {
2408                buffer.update(cx, |buffer, cx| {
2409                    buffer.randomly_undo_redo(&mut rng, cx);
2410                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2411                });
2412                mutation_count -= 1;
2413            }
2414            _ if network.lock().has_unreceived(replica_id) => {
2415                let ops = network
2416                    .lock()
2417                    .receive(replica_id)
2418                    .into_iter()
2419                    .map(|op| proto::deserialize_operation(op).unwrap());
2420                if ops.len() > 0 {
2421                    log::info!(
2422                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2423                        replica_id,
2424                        buffer.read(cx).version(),
2425                        ops.len(),
2426                        ops
2427                    );
2428                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2429                }
2430            }
2431            _ => {}
2432        }
2433
2434        now += Duration::from_millis(rng.gen_range(0..=200));
2435        buffers.extend(new_buffer);
2436
2437        for buffer in &buffers {
2438            buffer.read(cx).check_invariants();
2439        }
2440
2441        if mutation_count == 0 && network.lock().is_idle() {
2442            break;
2443        }
2444    }
2445
2446    let first_buffer = buffers[0].read(cx).snapshot();
2447    for buffer in &buffers[1..] {
2448        let buffer = buffer.read(cx).snapshot();
2449        assert_eq!(
2450            buffer.version(),
2451            first_buffer.version(),
2452            "Replica {} version != Replica 0 version",
2453            buffer.replica_id()
2454        );
2455        assert_eq!(
2456            buffer.text(),
2457            first_buffer.text(),
2458            "Replica {} text != Replica 0 text",
2459            buffer.replica_id()
2460        );
2461        assert_eq!(
2462            buffer
2463                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2464                .collect::<Vec<_>>(),
2465            first_buffer
2466                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2467                .collect::<Vec<_>>(),
2468            "Replica {} diagnostics != Replica 0 diagnostics",
2469            buffer.replica_id()
2470        );
2471    }
2472
2473    for buffer in &buffers {
2474        let buffer = buffer.read(cx).snapshot();
2475        let actual_remote_selections = buffer
2476            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
2477            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2478            .collect::<Vec<_>>();
2479        let expected_remote_selections = active_selections
2480            .iter()
2481            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2482            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2483            .collect::<Vec<_>>();
2484        assert_eq!(
2485            actual_remote_selections,
2486            expected_remote_selections,
2487            "Replica {} remote selections != expected selections",
2488            buffer.replica_id()
2489        );
2490    }
2491}
2492
2493#[test]
2494fn test_contiguous_ranges() {
2495    assert_eq!(
2496        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2497        &[1..4, 5..7, 9..13]
2498    );
2499
2500    // Respects the `max_len` parameter
2501    assert_eq!(
2502        contiguous_ranges(
2503            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2504            3
2505        )
2506        .collect::<Vec<_>>(),
2507        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2508    );
2509}
2510
2511#[gpui::test(iterations = 500)]
2512fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2513    // Generate a random multi-line string containing
2514    // some lines with trailing whitespace.
2515    let mut text = String::new();
2516    for _ in 0..rng.gen_range(0..16) {
2517        for _ in 0..rng.gen_range(0..36) {
2518            text.push(match rng.gen_range(0..10) {
2519                0..=1 => ' ',
2520                3 => '\t',
2521                _ => rng.gen_range('a'..='z'),
2522            });
2523        }
2524        text.push('\n');
2525    }
2526
2527    match rng.gen_range(0..10) {
2528        // sometimes remove the last newline
2529        0..=1 => drop(text.pop()), //
2530
2531        // sometimes add extra newlines
2532        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2533        _ => {}
2534    }
2535
2536    let rope = Rope::from(text.as_str());
2537    let actual_ranges = trailing_whitespace_ranges(&rope);
2538    let expected_ranges = TRAILING_WHITESPACE_REGEX
2539        .find_iter(&text)
2540        .map(|m| m.range())
2541        .collect::<Vec<_>>();
2542    assert_eq!(
2543        actual_ranges,
2544        expected_ranges,
2545        "wrong ranges for text lines:\n{:?}",
2546        text.split('\n').collect::<Vec<_>>()
2547    );
2548}
2549
2550fn ruby_lang() -> Language {
2551    Language::new(
2552        LanguageConfig {
2553            name: "Ruby".into(),
2554            matcher: LanguageMatcher {
2555                path_suffixes: vec!["rb".to_string()],
2556                ..Default::default()
2557            },
2558            line_comments: vec!["# ".into()],
2559            ..Default::default()
2560        },
2561        Some(tree_sitter_ruby::language()),
2562    )
2563    .with_indents_query(
2564        r#"
2565            (class "end" @end) @indent
2566            (method "end" @end) @indent
2567            (rescue) @outdent
2568            (then) @indent
2569        "#,
2570    )
2571    .unwrap()
2572}
2573
2574fn html_lang() -> Language {
2575    Language::new(
2576        LanguageConfig {
2577            name: "HTML".into(),
2578            block_comment: Some(("<!--".into(), "-->".into())),
2579            ..Default::default()
2580        },
2581        Some(tree_sitter_html::language()),
2582    )
2583    .with_indents_query(
2584        "
2585        (element
2586          (start_tag) @start
2587          (end_tag)? @end) @indent
2588        ",
2589    )
2590    .unwrap()
2591    .with_injection_query(
2592        r#"
2593        (script_element
2594            (raw_text) @content
2595            (#set! "language" "javascript"))
2596        "#,
2597    )
2598    .unwrap()
2599}
2600
2601fn erb_lang() -> Language {
2602    Language::new(
2603        LanguageConfig {
2604            name: "ERB".into(),
2605            matcher: LanguageMatcher {
2606                path_suffixes: vec!["erb".to_string()],
2607                ..Default::default()
2608            },
2609            block_comment: Some(("<%#".into(), "%>".into())),
2610            ..Default::default()
2611        },
2612        Some(tree_sitter_embedded_template::language()),
2613    )
2614    .with_injection_query(
2615        r#"
2616            (
2617                (code) @content
2618                (#set! "language" "ruby")
2619                (#set! "combined")
2620            )
2621
2622            (
2623                (content) @content
2624                (#set! "language" "html")
2625                (#set! "combined")
2626            )
2627        "#,
2628    )
2629    .unwrap()
2630}
2631
2632fn rust_lang() -> Language {
2633    Language::new(
2634        LanguageConfig {
2635            name: "Rust".into(),
2636            matcher: LanguageMatcher {
2637                path_suffixes: vec!["rs".to_string()],
2638                ..Default::default()
2639            },
2640            ..Default::default()
2641        },
2642        Some(tree_sitter_rust::language()),
2643    )
2644    .with_indents_query(
2645        r#"
2646        (call_expression) @indent
2647        (field_expression) @indent
2648        (_ "(" ")" @end) @indent
2649        (_ "{" "}" @end) @indent
2650        "#,
2651    )
2652    .unwrap()
2653    .with_brackets_query(
2654        r#"
2655        ("{" @open "}" @close)
2656        "#,
2657    )
2658    .unwrap()
2659    .with_outline_query(
2660        r#"
2661        (line_comment) @annotation
2662
2663        (struct_item
2664            "struct" @context
2665            name: (_) @name) @item
2666        (enum_item
2667            "enum" @context
2668            name: (_) @name) @item
2669        (enum_variant
2670            name: (_) @name) @item
2671        (field_declaration
2672            name: (_) @name) @item
2673        (impl_item
2674            "impl" @context
2675            trait: (_)? @name
2676            "for"? @context
2677            type: (_) @name
2678            body: (_ "{" (_)* "}")) @item
2679        (function_item
2680            "fn" @context
2681            name: (_) @name) @item
2682        (mod_item
2683            "mod" @context
2684            name: (_) @name) @item
2685        "#,
2686    )
2687    .unwrap()
2688}
2689
2690fn json_lang() -> Language {
2691    Language::new(
2692        LanguageConfig {
2693            name: "Json".into(),
2694            matcher: LanguageMatcher {
2695                path_suffixes: vec!["js".to_string()],
2696                ..Default::default()
2697            },
2698            ..Default::default()
2699        },
2700        Some(tree_sitter_json::language()),
2701    )
2702}
2703
2704fn javascript_lang() -> Language {
2705    Language::new(
2706        LanguageConfig {
2707            name: "JavaScript".into(),
2708            ..Default::default()
2709        },
2710        Some(tree_sitter_typescript::language_tsx()),
2711    )
2712    .with_brackets_query(
2713        r#"
2714        ("{" @open "}" @close)
2715        ("(" @open ")" @close)
2716        "#,
2717    )
2718    .unwrap()
2719    .with_indents_query(
2720        r#"
2721        (object "}" @end) @indent
2722        "#,
2723    )
2724    .unwrap()
2725}
2726
2727fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2728    buffer.update(cx, |buffer, _| {
2729        let snapshot = buffer.snapshot();
2730        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2731        layers[0].node().to_sexp()
2732    })
2733}
2734
2735// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2736fn assert_bracket_pairs(
2737    selection_text: &'static str,
2738    bracket_pair_texts: Vec<&'static str>,
2739    language: Language,
2740    cx: &mut AppContext,
2741) {
2742    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2743    let buffer = cx.new_model(|cx| {
2744        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2745    });
2746    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2747
2748    let selection_range = selection_ranges[0].clone();
2749
2750    let bracket_pairs = bracket_pair_texts
2751        .into_iter()
2752        .map(|pair_text| {
2753            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2754            assert_eq!(bracket_text, expected_text);
2755            (ranges[0].clone(), ranges[1].clone())
2756        })
2757        .collect::<Vec<_>>();
2758
2759    assert_set_eq!(
2760        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2761        bracket_pairs
2762    );
2763}
2764
2765fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2766    let settings_store = SettingsStore::test(cx);
2767    cx.set_global(settings_store);
2768    crate::init(cx);
2769    cx.update_global::<SettingsStore, _>(|settings, cx| {
2770        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2771    });
2772}