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