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