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};
  23use text::{Point, ToPoint};
  24use unindent::Unindent as _;
  25use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  26
  27lazy_static! {
  28    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  29        .multi_line(true)
  30        .build()
  31        .unwrap();
  32}
  33
  34#[cfg(test)]
  35#[ctor::ctor]
  36fn init_logger() {
  37    if std::env::var("RUST_LOG").is_ok() {
  38        env_logger::init();
  39    }
  40}
  41
  42#[gpui::test]
  43fn test_line_endings(cx: &mut gpui::AppContext) {
  44    init_settings(cx, |_| {});
  45
  46    cx.new_model(|cx| {
  47        let mut buffer =
  48            Buffer::local("one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  49        assert_eq!(buffer.text(), "one\ntwo\nthree");
  50        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  51
  52        buffer.check_invariants();
  53        buffer.edit(
  54            [(buffer.len()..buffer.len(), "\r\nfour")],
  55            Some(AutoindentMode::EachLine),
  56            cx,
  57        );
  58        buffer.edit([(0..0, "zero\r\n")], None, cx);
  59        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  60        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  61        buffer.check_invariants();
  62
  63        buffer
  64    });
  65}
  66
  67#[gpui::test]
  68fn test_select_language(cx: &mut AppContext) {
  69    init_settings(cx, |_| {});
  70
  71    let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
  72    registry.add(Arc::new(Language::new(
  73        LanguageConfig {
  74            name: "Rust".into(),
  75            matcher: LanguageMatcher {
  76                path_suffixes: vec!["rs".to_string()],
  77                ..Default::default()
  78            },
  79            ..Default::default()
  80        },
  81        Some(tree_sitter_rust::language()),
  82    )));
  83    registry.add(Arc::new(Language::new(
  84        LanguageConfig {
  85            name: "Make".into(),
  86            matcher: LanguageMatcher {
  87                path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  88                ..Default::default()
  89            },
  90            ..Default::default()
  91        },
  92        Some(tree_sitter_rust::language()),
  93    )));
  94
  95    // matching file extension
  96    assert_eq!(
  97        registry
  98            .language_for_file(&file("src/lib.rs"), None, cx)
  99            .now_or_never()
 100            .and_then(|l| Some(l.ok()?.name())),
 101        Some("Rust".into())
 102    );
 103    assert_eq!(
 104        registry
 105            .language_for_file(&file("src/lib.mk"), None, cx)
 106            .now_or_never()
 107            .and_then(|l| Some(l.ok()?.name())),
 108        Some("Make".into())
 109    );
 110
 111    // matching filename
 112    assert_eq!(
 113        registry
 114            .language_for_file(&file("src/Makefile"), None, cx)
 115            .now_or_never()
 116            .and_then(|l| Some(l.ok()?.name())),
 117        Some("Make".into())
 118    );
 119
 120    // matching suffix that is not the full file extension or filename
 121    assert_eq!(
 122        registry
 123            .language_for_file(&file("zed/cars"), None, cx)
 124            .now_or_never()
 125            .and_then(|l| Some(l.ok()?.name())),
 126        None
 127    );
 128    assert_eq!(
 129        registry
 130            .language_for_file(&file("zed/a.cars"), None, cx)
 131            .now_or_never()
 132            .and_then(|l| Some(l.ok()?.name())),
 133        None
 134    );
 135    assert_eq!(
 136        registry
 137            .language_for_file(&file("zed/sumk"), None, cx)
 138            .now_or_never()
 139            .and_then(|l| Some(l.ok()?.name())),
 140        None
 141    );
 142}
 143
 144#[gpui::test(iterations = 10)]
 145async fn test_first_line_pattern(cx: &mut TestAppContext) {
 146    cx.update(|cx| init_settings(cx, |_| {}));
 147
 148    let languages = LanguageRegistry::test(cx.executor());
 149    let languages = Arc::new(languages);
 150
 151    languages.register_test_language(LanguageConfig {
 152        name: "JavaScript".into(),
 153        matcher: LanguageMatcher {
 154            path_suffixes: vec!["js".into()],
 155            first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()),
 156        },
 157        ..Default::default()
 158    });
 159
 160    cx.read(|cx| languages.language_for_file(&file("the/script"), None, cx))
 161        .await
 162        .unwrap_err();
 163    cx.read(|cx| languages.language_for_file(&file("the/script"), Some(&"nothing".into()), cx))
 164        .await
 165        .unwrap_err();
 166    assert_eq!(
 167        cx.read(|cx| languages.language_for_file(
 168            &file("the/script"),
 169            Some(&"#!/bin/env node".into()),
 170            cx
 171        ))
 172        .await
 173        .unwrap()
 174        .name()
 175        .as_ref(),
 176        "JavaScript"
 177    );
 178}
 179
 180#[gpui::test]
 181async fn test_language_for_file_with_custom_file_types(cx: &mut TestAppContext) {
 182    cx.update(|cx| {
 183        init_settings(cx, |settings| {
 184            settings.file_types.extend([
 185                ("TypeScript".into(), vec!["js".into()]),
 186                ("C++".into(), vec!["c".into()]),
 187                (
 188                    "Dockerfile".into(),
 189                    vec!["Dockerfile".into(), "Dockerfile.*".into()],
 190                ),
 191            ]);
 192        })
 193    });
 194
 195    let languages = Arc::new(LanguageRegistry::test(cx.executor()));
 196
 197    for config in [
 198        LanguageConfig {
 199            name: "JavaScript".into(),
 200            matcher: LanguageMatcher {
 201                path_suffixes: vec!["js".to_string()],
 202                ..Default::default()
 203            },
 204            ..Default::default()
 205        },
 206        LanguageConfig {
 207            name: "TypeScript".into(),
 208            matcher: LanguageMatcher {
 209                path_suffixes: vec!["js".to_string()],
 210                ..Default::default()
 211            },
 212            ..Default::default()
 213        },
 214        LanguageConfig {
 215            name: "C++".into(),
 216            matcher: LanguageMatcher {
 217                path_suffixes: vec!["cpp".to_string()],
 218                ..Default::default()
 219            },
 220            ..Default::default()
 221        },
 222        LanguageConfig {
 223            name: "C".into(),
 224            matcher: LanguageMatcher {
 225                path_suffixes: vec!["c".to_string()],
 226                ..Default::default()
 227            },
 228            ..Default::default()
 229        },
 230        LanguageConfig {
 231            name: "Dockerfile".into(),
 232            matcher: LanguageMatcher {
 233                path_suffixes: vec!["Dockerfile".to_string()],
 234                ..Default::default()
 235            },
 236            ..Default::default()
 237        },
 238    ] {
 239        languages.add(Arc::new(Language::new(config, None)));
 240    }
 241
 242    let language = cx
 243        .read(|cx| languages.language_for_file(&file("foo.js"), None, cx))
 244        .await
 245        .unwrap();
 246    assert_eq!(language.name().as_ref(), "TypeScript");
 247    let language = cx
 248        .read(|cx| languages.language_for_file(&file("foo.c"), None, cx))
 249        .await
 250        .unwrap();
 251    assert_eq!(language.name().as_ref(), "C++");
 252    let language = cx
 253        .read(|cx| languages.language_for_file(&file("Dockerfile.dev"), None, cx))
 254        .await
 255        .unwrap();
 256    assert_eq!(language.name().as_ref(), "Dockerfile");
 257}
 258
 259fn file(path: &str) -> Arc<dyn File> {
 260    Arc::new(TestFile {
 261        path: Path::new(path).into(),
 262        root_name: "zed".into(),
 263    })
 264}
 265
 266#[gpui::test]
 267fn test_edit_events(cx: &mut gpui::AppContext) {
 268    let mut now = Instant::now();
 269    let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
 270    let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
 271
 272    let buffer1 = cx.new_model(|cx| Buffer::local("abcdef", cx));
 273    let buffer2 = cx.new_model(|cx| {
 274        Buffer::remote(
 275            BufferId::from(cx.entity_id().as_non_zero_u64()),
 276            1,
 277            Capability::ReadWrite,
 278            "abcdef",
 279        )
 280    });
 281    let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
 282    buffer1.update(cx, {
 283        let buffer1_ops = buffer1_ops.clone();
 284        |buffer, cx| {
 285            let buffer_1_events = buffer_1_events.clone();
 286            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 287                Event::Operation(op) => buffer1_ops.lock().push(op),
 288                event => buffer_1_events.lock().push(event),
 289            })
 290            .detach();
 291            let buffer_2_events = buffer_2_events.clone();
 292            cx.subscribe(&buffer2, move |_, _, event, _| {
 293                buffer_2_events.lock().push(event.clone())
 294            })
 295            .detach();
 296
 297            // An edit emits an edited event, followed by a dirty changed event,
 298            // since the buffer was previously in a clean state.
 299            buffer.edit([(2..4, "XYZ")], None, cx);
 300
 301            // An empty transaction does not emit any events.
 302            buffer.start_transaction();
 303            buffer.end_transaction(cx);
 304
 305            // A transaction containing two edits emits one edited event.
 306            now += Duration::from_secs(1);
 307            buffer.start_transaction_at(now);
 308            buffer.edit([(5..5, "u")], None, cx);
 309            buffer.edit([(6..6, "w")], None, cx);
 310            buffer.end_transaction_at(now, cx);
 311
 312            // Undoing a transaction emits one edited event.
 313            buffer.undo(cx);
 314        }
 315    });
 316
 317    // Incorporating a set of remote ops emits a single edited event,
 318    // followed by a dirty changed event.
 319    buffer2.update(cx, |buffer, cx| {
 320        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 321    });
 322    assert_eq!(
 323        mem::take(&mut *buffer_1_events.lock()),
 324        vec![
 325            Event::Edited,
 326            Event::DirtyChanged,
 327            Event::Edited,
 328            Event::Edited,
 329        ]
 330    );
 331    assert_eq!(
 332        mem::take(&mut *buffer_2_events.lock()),
 333        vec![Event::Edited, Event::DirtyChanged]
 334    );
 335
 336    buffer1.update(cx, |buffer, cx| {
 337        // Undoing the first transaction emits edited event, followed by a
 338        // dirty changed event, since the buffer is again in a clean state.
 339        buffer.undo(cx);
 340    });
 341    // Incorporating the remote ops again emits a single edited event,
 342    // followed by a dirty changed event.
 343    buffer2.update(cx, |buffer, cx| {
 344        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 345    });
 346    assert_eq!(
 347        mem::take(&mut *buffer_1_events.lock()),
 348        vec![Event::Edited, Event::DirtyChanged,]
 349    );
 350    assert_eq!(
 351        mem::take(&mut *buffer_2_events.lock()),
 352        vec![Event::Edited, Event::DirtyChanged]
 353    );
 354}
 355
 356#[gpui::test]
 357async fn test_apply_diff(cx: &mut TestAppContext) {
 358    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 359    let buffer = cx.new_model(|cx| Buffer::local(text, cx));
 360    let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 361
 362    let text = "a\nccc\ndddd\nffffff\n";
 363    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 364    buffer.update(cx, |buffer, cx| {
 365        buffer.apply_diff(diff, cx).unwrap();
 366        assert_eq!(buffer.text(), text);
 367        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 368    });
 369
 370    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 371    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 372    buffer.update(cx, |buffer, cx| {
 373        buffer.apply_diff(diff, cx).unwrap();
 374        assert_eq!(buffer.text(), text);
 375        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 376    });
 377}
 378
 379#[gpui::test(iterations = 10)]
 380async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 381    let text = [
 382        "zero",     //
 383        "one  ",    // 2 trailing spaces
 384        "two",      //
 385        "three   ", // 3 trailing spaces
 386        "four",     //
 387        "five    ", // 4 trailing spaces
 388    ]
 389    .join("\n");
 390
 391    let buffer = cx.new_model(|cx| Buffer::local(text, cx));
 392
 393    // Spawn a task to format the buffer's whitespace.
 394    // Pause so that the foratting task starts running.
 395    let format = buffer.update(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 396    smol::future::yield_now().await;
 397
 398    // Edit the buffer while the normalization task is running.
 399    let version_before_edit = buffer.update(cx, |buffer, _| buffer.version());
 400    buffer.update(cx, |buffer, cx| {
 401        buffer.edit(
 402            [
 403                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 404                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 405            ],
 406            None,
 407            cx,
 408        );
 409    });
 410
 411    let format_diff = format.await;
 412    buffer.update(cx, |buffer, cx| {
 413        let version_before_format = format_diff.base_version.clone();
 414        buffer.apply_diff(format_diff, cx);
 415
 416        // The outcome depends on the order of concurrent tasks.
 417        //
 418        // If the edit occurred while searching for trailing whitespace ranges,
 419        // then the trailing whitespace region touched by the edit is left intact.
 420        if version_before_format == version_before_edit {
 421            assert_eq!(
 422                buffer.text(),
 423                [
 424                    "zEEero",      //
 425                    "one",         //
 426                    "two",         //
 427                    "threeEEE   ", //
 428                    "four",        //
 429                    "five",        //
 430                ]
 431                .join("\n")
 432            );
 433        }
 434        // Otherwise, all trailing whitespace is removed.
 435        else {
 436            assert_eq!(
 437                buffer.text(),
 438                [
 439                    "zEEero",   //
 440                    "one",      //
 441                    "two",      //
 442                    "threeEEE", //
 443                    "four",     //
 444                    "five",     //
 445                ]
 446                .join("\n")
 447            );
 448        }
 449    });
 450}
 451
 452#[gpui::test]
 453async fn test_reparse(cx: &mut gpui::TestAppContext) {
 454    let text = "fn a() {}";
 455    let buffer =
 456        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 457
 458    // Wait for the initial text to parse
 459    cx.executor().run_until_parked();
 460    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 461    assert_eq!(
 462        get_tree_sexp(&buffer, cx),
 463        concat!(
 464            "(source_file (function_item name: (identifier) ",
 465            "parameters: (parameters) ",
 466            "body: (block)))"
 467        )
 468    );
 469
 470    buffer.update(cx, |buffer, _| {
 471        buffer.set_sync_parse_timeout(Duration::ZERO)
 472    });
 473
 474    // Perform some edits (add parameter and variable reference)
 475    // Parsing doesn't begin until the transaction is complete
 476    buffer.update(cx, |buf, cx| {
 477        buf.start_transaction();
 478
 479        let offset = buf.text().find(')').unwrap();
 480        buf.edit([(offset..offset, "b: C")], None, cx);
 481        assert!(!buf.is_parsing());
 482
 483        let offset = buf.text().find('}').unwrap();
 484        buf.edit([(offset..offset, " d; ")], None, cx);
 485        assert!(!buf.is_parsing());
 486
 487        buf.end_transaction(cx);
 488        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 489        assert!(buf.is_parsing());
 490    });
 491    cx.executor().run_until_parked();
 492    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 493    assert_eq!(
 494        get_tree_sexp(&buffer, cx),
 495        concat!(
 496            "(source_file (function_item name: (identifier) ",
 497            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 498            "body: (block (expression_statement (identifier)))))"
 499        )
 500    );
 501
 502    // Perform a series of edits without waiting for the current parse to complete:
 503    // * turn identifier into a field expression
 504    // * turn field expression into a method call
 505    // * add a turbofish to the method call
 506    buffer.update(cx, |buf, cx| {
 507        let offset = buf.text().find(';').unwrap();
 508        buf.edit([(offset..offset, ".e")], None, cx);
 509        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 510        assert!(buf.is_parsing());
 511    });
 512    buffer.update(cx, |buf, cx| {
 513        let offset = buf.text().find(';').unwrap();
 514        buf.edit([(offset..offset, "(f)")], None, cx);
 515        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 516        assert!(buf.is_parsing());
 517    });
 518    buffer.update(cx, |buf, cx| {
 519        let offset = buf.text().find("(f)").unwrap();
 520        buf.edit([(offset..offset, "::<G>")], None, cx);
 521        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 522        assert!(buf.is_parsing());
 523    });
 524    cx.executor().run_until_parked();
 525    assert_eq!(
 526        get_tree_sexp(&buffer, cx),
 527        concat!(
 528            "(source_file (function_item name: (identifier) ",
 529            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 530            "body: (block (expression_statement (call_expression ",
 531            "function: (generic_function ",
 532            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 533            "type_arguments: (type_arguments (type_identifier))) ",
 534            "arguments: (arguments (identifier)))))))",
 535        )
 536    );
 537
 538    buffer.update(cx, |buf, cx| {
 539        buf.undo(cx);
 540        buf.undo(cx);
 541        buf.undo(cx);
 542        buf.undo(cx);
 543        assert_eq!(buf.text(), "fn a() {}");
 544        assert!(buf.is_parsing());
 545    });
 546
 547    cx.executor().run_until_parked();
 548    assert_eq!(
 549        get_tree_sexp(&buffer, cx),
 550        concat!(
 551            "(source_file (function_item name: (identifier) ",
 552            "parameters: (parameters) ",
 553            "body: (block)))"
 554        )
 555    );
 556
 557    buffer.update(cx, |buf, cx| {
 558        buf.redo(cx);
 559        buf.redo(cx);
 560        buf.redo(cx);
 561        buf.redo(cx);
 562        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 563        assert!(buf.is_parsing());
 564    });
 565    cx.executor().run_until_parked();
 566    assert_eq!(
 567        get_tree_sexp(&buffer, cx),
 568        concat!(
 569            "(source_file (function_item name: (identifier) ",
 570            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 571            "body: (block (expression_statement (call_expression ",
 572            "function: (generic_function ",
 573            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 574            "type_arguments: (type_arguments (type_identifier))) ",
 575            "arguments: (arguments (identifier)))))))",
 576        )
 577    );
 578}
 579
 580#[gpui::test]
 581async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 582    let buffer = cx.new_model(|cx| {
 583        let mut buffer = Buffer::local("{}", cx).with_language(Arc::new(rust_lang()), cx);
 584        buffer.set_sync_parse_timeout(Duration::ZERO);
 585        buffer
 586    });
 587
 588    // Wait for the initial text to parse
 589    cx.executor().run_until_parked();
 590    assert_eq!(
 591        get_tree_sexp(&buffer, cx),
 592        "(source_file (expression_statement (block)))"
 593    );
 594
 595    buffer.update(cx, |buffer, cx| {
 596        buffer.set_language(Some(Arc::new(json_lang())), cx)
 597    });
 598    cx.executor().run_until_parked();
 599    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 600}
 601
 602#[gpui::test]
 603async fn test_outline(cx: &mut gpui::TestAppContext) {
 604    let text = r#"
 605        struct Person {
 606            name: String,
 607            age: usize,
 608        }
 609
 610        mod module {
 611            enum LoginState {
 612                LoggedOut,
 613                LoggingOn,
 614                LoggedIn {
 615                    person: Person,
 616                    time: Instant,
 617                }
 618            }
 619        }
 620
 621        impl Eq for Person {}
 622
 623        impl Drop for Person {
 624            fn drop(&mut self) {
 625                println!("bye");
 626            }
 627        }
 628    "#
 629    .unindent();
 630
 631    let buffer =
 632        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 633    let outline = buffer
 634        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 635        .unwrap();
 636
 637    assert_eq!(
 638        outline
 639            .items
 640            .iter()
 641            .map(|item| (item.text.as_str(), item.depth))
 642            .collect::<Vec<_>>(),
 643        &[
 644            ("struct Person", 0),
 645            ("name", 1),
 646            ("age", 1),
 647            ("mod module", 0),
 648            ("enum LoginState", 1),
 649            ("LoggedOut", 2),
 650            ("LoggingOn", 2),
 651            ("LoggedIn", 2),
 652            ("person", 3),
 653            ("time", 3),
 654            ("impl Eq for Person", 0),
 655            ("impl Drop for Person", 0),
 656            ("fn drop", 1),
 657        ]
 658    );
 659
 660    // Without space, we only match on names
 661    assert_eq!(
 662        search(&outline, "oon", cx).await,
 663        &[
 664            ("mod module", vec![]),                    // included as the parent of a match
 665            ("enum LoginState", vec![]),               // included as the parent of a match
 666            ("LoggingOn", vec![1, 7, 8]),              // matches
 667            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 668        ]
 669    );
 670
 671    assert_eq!(
 672        search(&outline, "dp p", cx).await,
 673        &[
 674            ("impl Drop for Person", vec![5, 8, 9, 14]),
 675            ("fn drop", vec![]),
 676        ]
 677    );
 678    assert_eq!(
 679        search(&outline, "dpn", cx).await,
 680        &[("impl Drop for Person", vec![5, 14, 19])]
 681    );
 682    assert_eq!(
 683        search(&outline, "impl ", cx).await,
 684        &[
 685            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 686            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 687            ("fn drop", vec![]),
 688        ]
 689    );
 690
 691    async fn search<'a>(
 692        outline: &'a Outline<Anchor>,
 693        query: &'a str,
 694        cx: &'a gpui::TestAppContext,
 695    ) -> Vec<(&'a str, Vec<usize>)> {
 696        let matches = cx
 697            .update(|cx| outline.search(query, cx.background_executor().clone()))
 698            .await;
 699        matches
 700            .into_iter()
 701            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 702            .collect::<Vec<_>>()
 703    }
 704}
 705
 706#[gpui::test]
 707async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 708    let text = r#"
 709        impl A for B<
 710            C
 711        > {
 712        };
 713    "#
 714    .unindent();
 715
 716    let buffer =
 717        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 718    let outline = buffer
 719        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 720        .unwrap();
 721
 722    assert_eq!(
 723        outline
 724            .items
 725            .iter()
 726            .map(|item| (item.text.as_str(), item.depth))
 727            .collect::<Vec<_>>(),
 728        &[("impl A for B<", 0)]
 729    );
 730}
 731
 732#[gpui::test]
 733async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
 734    let language = javascript_lang()
 735        .with_outline_query(
 736            r#"
 737            (function_declaration
 738                "function" @context
 739                name: (_) @name
 740                parameters: (formal_parameters
 741                    "(" @context.extra
 742                    ")" @context.extra)) @item
 743            "#,
 744        )
 745        .unwrap();
 746
 747    let text = r#"
 748        function a() {}
 749        function b(c) {}
 750    "#
 751    .unindent();
 752
 753    let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(language), cx));
 754    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 755
 756    // extra context nodes are included in the outline.
 757    let outline = snapshot.outline(None).unwrap();
 758    assert_eq!(
 759        outline
 760            .items
 761            .iter()
 762            .map(|item| (item.text.as_str(), item.depth))
 763            .collect::<Vec<_>>(),
 764        &[("function a()", 0), ("function b( )", 0),]
 765    );
 766
 767    // extra context nodes do not appear in breadcrumbs.
 768    let symbols = snapshot.symbols_containing(3, None).unwrap();
 769    assert_eq!(
 770        symbols
 771            .iter()
 772            .map(|item| (item.text.as_str(), item.depth))
 773            .collect::<Vec<_>>(),
 774        &[("function a", 0)]
 775    );
 776}
 777
 778#[gpui::test]
 779async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 780    let text = r#"
 781        impl Person {
 782            fn one() {
 783                1
 784            }
 785
 786            fn two() {
 787                2
 788            }fn three() {
 789                3
 790            }
 791        }
 792    "#
 793    .unindent();
 794
 795    let buffer =
 796        cx.new_model(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
 797    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 798
 799    // point is at the start of an item
 800    assert_eq!(
 801        symbols_containing(Point::new(1, 4), &snapshot),
 802        vec![
 803            (
 804                "impl Person".to_string(),
 805                Point::new(0, 0)..Point::new(10, 1)
 806            ),
 807            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 808        ]
 809    );
 810
 811    // point is in the middle of an item
 812    assert_eq!(
 813        symbols_containing(Point::new(2, 8), &snapshot),
 814        vec![
 815            (
 816                "impl Person".to_string(),
 817                Point::new(0, 0)..Point::new(10, 1)
 818            ),
 819            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 820        ]
 821    );
 822
 823    // point is at the end of an item
 824    assert_eq!(
 825        symbols_containing(Point::new(3, 5), &snapshot),
 826        vec![
 827            (
 828                "impl Person".to_string(),
 829                Point::new(0, 0)..Point::new(10, 1)
 830            ),
 831            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 832        ]
 833    );
 834
 835    // point is in between two adjacent items
 836    assert_eq!(
 837        symbols_containing(Point::new(7, 5), &snapshot),
 838        vec![
 839            (
 840                "impl Person".to_string(),
 841                Point::new(0, 0)..Point::new(10, 1)
 842            ),
 843            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 844        ]
 845    );
 846
 847    fn symbols_containing(
 848        position: Point,
 849        snapshot: &BufferSnapshot,
 850    ) -> Vec<(String, Range<Point>)> {
 851        snapshot
 852            .symbols_containing(position, None)
 853            .unwrap()
 854            .into_iter()
 855            .map(|item| {
 856                (
 857                    item.text,
 858                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 859                )
 860            })
 861            .collect()
 862    }
 863}
 864
 865#[gpui::test]
 866fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 867    let mut assert = |selection_text, range_markers| {
 868        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 869    };
 870
 871    assert(
 872        indoc! {"
 873            mod x {
 874                moˇd y {
 875
 876                }
 877            }
 878            let foo = 1;"},
 879        vec![indoc! {"
 880            mod x «{»
 881                mod y {
 882
 883                }
 884            «}»
 885            let foo = 1;"}],
 886    );
 887
 888    assert(
 889        indoc! {"
 890            mod x {
 891                mod y ˇ{
 892
 893                }
 894            }
 895            let foo = 1;"},
 896        vec![
 897            indoc! {"
 898                mod x «{»
 899                    mod y {
 900
 901                    }
 902                «}»
 903                let foo = 1;"},
 904            indoc! {"
 905                mod x {
 906                    mod y «{»
 907
 908                    «}»
 909                }
 910                let foo = 1;"},
 911        ],
 912    );
 913
 914    assert(
 915        indoc! {"
 916            mod x {
 917                mod y {
 918
 919 920            }
 921            let foo = 1;"},
 922        vec![
 923            indoc! {"
 924                mod x «{»
 925                    mod y {
 926
 927                    }
 928                «}»
 929                let foo = 1;"},
 930            indoc! {"
 931                mod x {
 932                    mod y «{»
 933
 934                    «}»
 935                }
 936                let foo = 1;"},
 937        ],
 938    );
 939
 940    assert(
 941        indoc! {"
 942            mod x {
 943                mod y {
 944
 945                }
 946            ˇ}
 947            let foo = 1;"},
 948        vec![indoc! {"
 949            mod x «{»
 950                mod y {
 951
 952                }
 953            «}»
 954            let foo = 1;"}],
 955    );
 956
 957    assert(
 958        indoc! {"
 959            mod x {
 960                mod y {
 961
 962                }
 963            }
 964            let fˇoo = 1;"},
 965        vec![],
 966    );
 967
 968    // Regression test: avoid crash when querying at the end of the buffer.
 969    assert(
 970        indoc! {"
 971            mod x {
 972                mod y {
 973
 974                }
 975            }
 976            let foo = 1;ˇ"},
 977        vec![],
 978    );
 979}
 980
 981#[gpui::test]
 982fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 983    let mut assert = |selection_text, bracket_pair_texts| {
 984        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 985    };
 986
 987    assert(
 988        indoc! {"
 989        for (const a in b)ˇ {
 990            // a comment that's longer than the for-loop header
 991        }"},
 992        vec![indoc! {"
 993        for «(»const a in b«)» {
 994            // a comment that's longer than the for-loop header
 995        }"}],
 996    );
 997
 998    // Regression test: even though the parent node of the parentheses (the for loop) does
 999    // intersect the given range, the parentheses themselves do not contain the range, so
1000    // they should not be returned. Only the curly braces contain the range.
1001    assert(
1002        indoc! {"
1003        for (const a in b) {ˇ
1004            // a comment that's longer than the for-loop header
1005        }"},
1006        vec![indoc! {"
1007        for (const a in b) «{»
1008            // a comment that's longer than the for-loop header
1009        «}»"}],
1010    );
1011}
1012
1013#[gpui::test]
1014fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
1015    cx.new_model(|cx| {
1016        let text = "fn a() { b(|c| {}) }";
1017        let buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1018        let snapshot = buffer.snapshot();
1019
1020        assert_eq!(
1021            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
1022            Some(range_of(text, "|"))
1023        );
1024        assert_eq!(
1025            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
1026            Some(range_of(text, "|c|"))
1027        );
1028        assert_eq!(
1029            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
1030            Some(range_of(text, "|c| {}"))
1031        );
1032        assert_eq!(
1033            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
1034            Some(range_of(text, "(|c| {})"))
1035        );
1036
1037        buffer
1038    });
1039
1040    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
1041        let start = text.find(part).unwrap();
1042        start..start
1043    }
1044
1045    fn range_of(text: &str, part: &str) -> Range<usize> {
1046        let start = text.find(part).unwrap();
1047        start..start + part.len()
1048    }
1049}
1050
1051#[gpui::test]
1052fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
1053    init_settings(cx, |_| {});
1054
1055    cx.new_model(|cx| {
1056        let text = "fn a() {}";
1057        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1058
1059        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1060        assert_eq!(buffer.text(), "fn a() {\n    \n}");
1061
1062        buffer.edit(
1063            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
1064            Some(AutoindentMode::EachLine),
1065            cx,
1066        );
1067        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
1068
1069        // Create a field expression on a new line, causing that line
1070        // to be indented.
1071        buffer.edit(
1072            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
1073            Some(AutoindentMode::EachLine),
1074            cx,
1075        );
1076        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
1077
1078        // Remove the dot so that the line is no longer a field expression,
1079        // causing the line to be outdented.
1080        buffer.edit(
1081            [(Point::new(2, 8)..Point::new(2, 9), "")],
1082            Some(AutoindentMode::EachLine),
1083            cx,
1084        );
1085        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
1086
1087        buffer
1088    });
1089}
1090
1091#[gpui::test]
1092fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
1093    init_settings(cx, |settings| {
1094        settings.defaults.hard_tabs = Some(true);
1095    });
1096
1097    cx.new_model(|cx| {
1098        let text = "fn a() {}";
1099        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1100
1101        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1102        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
1103
1104        buffer.edit(
1105            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
1106            Some(AutoindentMode::EachLine),
1107            cx,
1108        );
1109        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1110
1111        // Create a field expression on a new line, causing that line
1112        // to be indented.
1113        buffer.edit(
1114            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1115            Some(AutoindentMode::EachLine),
1116            cx,
1117        );
1118        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1119
1120        // Remove the dot so that the line is no longer a field expression,
1121        // causing the line to be outdented.
1122        buffer.edit(
1123            [(Point::new(2, 2)..Point::new(2, 3), "")],
1124            Some(AutoindentMode::EachLine),
1125            cx,
1126        );
1127        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1128
1129        buffer
1130    });
1131}
1132
1133#[gpui::test]
1134fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1135    init_settings(cx, |_| {});
1136
1137    cx.new_model(|cx| {
1138        let mut buffer = Buffer::local(
1139            "
1140            fn a() {
1141            c;
1142            d;
1143            }
1144            "
1145            .unindent(),
1146            cx,
1147        )
1148        .with_language(Arc::new(rust_lang()), cx);
1149
1150        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1151        // their indentation is not adjusted.
1152        buffer.edit_via_marked_text(
1153            &"
1154            fn a() {
1155            c«()»;
1156            d«()»;
1157            }
1158            "
1159            .unindent(),
1160            Some(AutoindentMode::EachLine),
1161            cx,
1162        );
1163        assert_eq!(
1164            buffer.text(),
1165            "
1166            fn a() {
1167            c();
1168            d();
1169            }
1170            "
1171            .unindent()
1172        );
1173
1174        // When appending new content after these lines, the indentation is based on the
1175        // preceding lines' actual indentation.
1176        buffer.edit_via_marked_text(
1177            &"
1178            fn a() {
11791180            .f
1181            .g()»;
11821183            .f
1184            .g()»;
1185            }
1186            "
1187            .unindent(),
1188            Some(AutoindentMode::EachLine),
1189            cx,
1190        );
1191
1192        assert_eq!(
1193            buffer.text(),
1194            "
1195            fn a() {
1196            c
1197                .f
1198                .g();
1199            d
1200                .f
1201                .g();
1202            }
1203            "
1204            .unindent()
1205        );
1206        buffer
1207    });
1208
1209    cx.new_model(|cx| {
1210        eprintln!("second buffer: {:?}", cx.entity_id());
1211
1212        let mut buffer = Buffer::local(
1213            "
1214            fn a() {
1215                b();
1216                |
1217            "
1218            .replace('|', "") // marker to preserve trailing whitespace
1219            .unindent(),
1220            cx,
1221        )
1222        .with_language(Arc::new(rust_lang()), cx);
1223
1224        // Insert a closing brace. It is outdented.
1225        buffer.edit_via_marked_text(
1226            &"
1227            fn a() {
1228                b();
1229                «}»
1230            "
1231            .unindent(),
1232            Some(AutoindentMode::EachLine),
1233            cx,
1234        );
1235        assert_eq!(
1236            buffer.text(),
1237            "
1238            fn a() {
1239                b();
1240            }
1241            "
1242            .unindent()
1243        );
1244
1245        // Manually edit the leading whitespace. The edit is preserved.
1246        buffer.edit_via_marked_text(
1247            &"
1248            fn a() {
1249                b();
1250            «    »}
1251            "
1252            .unindent(),
1253            Some(AutoindentMode::EachLine),
1254            cx,
1255        );
1256        assert_eq!(
1257            buffer.text(),
1258            "
1259            fn a() {
1260                b();
1261                }
1262            "
1263            .unindent()
1264        );
1265        buffer
1266    });
1267
1268    eprintln!("DONE");
1269}
1270
1271#[gpui::test]
1272fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1273    init_settings(cx, |_| {});
1274
1275    cx.new_model(|cx| {
1276        let mut buffer = Buffer::local(
1277            "
1278            fn a() {
1279                i
1280            }
1281            "
1282            .unindent(),
1283            cx,
1284        )
1285        .with_language(Arc::new(rust_lang()), cx);
1286
1287        // Regression test: line does not get outdented due to syntax error
1288        buffer.edit_via_marked_text(
1289            &"
1290            fn a() {
1291                i«f let Some(x) = y»
1292            }
1293            "
1294            .unindent(),
1295            Some(AutoindentMode::EachLine),
1296            cx,
1297        );
1298        assert_eq!(
1299            buffer.text(),
1300            "
1301            fn a() {
1302                if let Some(x) = y
1303            }
1304            "
1305            .unindent()
1306        );
1307
1308        buffer.edit_via_marked_text(
1309            &"
1310            fn a() {
1311                if let Some(x) = y« {»
1312            }
1313            "
1314            .unindent(),
1315            Some(AutoindentMode::EachLine),
1316            cx,
1317        );
1318        assert_eq!(
1319            buffer.text(),
1320            "
1321            fn a() {
1322                if let Some(x) = y {
1323            }
1324            "
1325            .unindent()
1326        );
1327
1328        buffer
1329    });
1330}
1331
1332#[gpui::test]
1333fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1334    init_settings(cx, |_| {});
1335
1336    cx.new_model(|cx| {
1337        let mut buffer = Buffer::local(
1338            "
1339            fn a() {}
1340            "
1341            .unindent(),
1342            cx,
1343        )
1344        .with_language(Arc::new(rust_lang()), cx);
1345
1346        buffer.edit_via_marked_text(
1347            &"
1348            fn a(«
1349            b») {}
1350            "
1351            .unindent(),
1352            Some(AutoindentMode::EachLine),
1353            cx,
1354        );
1355        assert_eq!(
1356            buffer.text(),
1357            "
1358            fn a(
1359                b) {}
1360            "
1361            .unindent()
1362        );
1363
1364        // The indentation suggestion changed because `@end` node (a close paren)
1365        // is now at the beginning of the line.
1366        buffer.edit_via_marked_text(
1367            &"
1368            fn a(
1369                ˇ) {}
1370            "
1371            .unindent(),
1372            Some(AutoindentMode::EachLine),
1373            cx,
1374        );
1375        assert_eq!(
1376            buffer.text(),
1377            "
1378                fn a(
1379                ) {}
1380            "
1381            .unindent()
1382        );
1383
1384        buffer
1385    });
1386}
1387
1388#[gpui::test]
1389fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1390    init_settings(cx, |_| {});
1391
1392    cx.new_model(|cx| {
1393        let text = "a\nb";
1394        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1395        buffer.edit(
1396            [(0..1, "\n"), (2..3, "\n")],
1397            Some(AutoindentMode::EachLine),
1398            cx,
1399        );
1400        assert_eq!(buffer.text(), "\n\n\n");
1401        buffer
1402    });
1403}
1404
1405#[gpui::test]
1406fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1407    init_settings(cx, |_| {});
1408
1409    cx.new_model(|cx| {
1410        let text = "
1411            const a: usize = 1;
1412            fn b() {
1413                if c {
1414                    let d = 2;
1415                }
1416            }
1417        "
1418        .unindent();
1419
1420        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1421        buffer.edit(
1422            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1423            Some(AutoindentMode::EachLine),
1424            cx,
1425        );
1426        assert_eq!(
1427            buffer.text(),
1428            "
1429                const a: usize = 1;
1430                fn b() {
1431                    if c {
1432                        e(
1433                            f()
1434                        );
1435                        let d = 2;
1436                    }
1437                }
1438            "
1439            .unindent()
1440        );
1441
1442        buffer
1443    });
1444}
1445
1446#[gpui::test]
1447fn test_autoindent_block_mode(cx: &mut AppContext) {
1448    init_settings(cx, |_| {});
1449
1450    cx.new_model(|cx| {
1451        let text = r#"
1452            fn a() {
1453                b();
1454            }
1455        "#
1456        .unindent();
1457        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1458
1459        // When this text was copied, both of the quotation marks were at the same
1460        // indent level, but the indentation of the first line was not included in
1461        // the copied text. This information is retained in the
1462        // 'original_indent_columns' vector.
1463        let original_indent_columns = vec![4];
1464        let inserted_text = r#"
1465            "
1466                  c
1467                    d
1468                      e
1469                "
1470        "#
1471        .unindent();
1472
1473        // Insert the block at column zero. The entire block is indented
1474        // so that the first line matches the previous line's indentation.
1475        buffer.edit(
1476            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1477            Some(AutoindentMode::Block {
1478                original_indent_columns: original_indent_columns.clone(),
1479            }),
1480            cx,
1481        );
1482        assert_eq!(
1483            buffer.text(),
1484            r#"
1485            fn a() {
1486                b();
1487                "
1488                  c
1489                    d
1490                      e
1491                "
1492            }
1493            "#
1494            .unindent()
1495        );
1496
1497        // Grouping is disabled in tests, so we need 2 undos
1498        buffer.undo(cx); // Undo the auto-indent
1499        buffer.undo(cx); // Undo the original edit
1500
1501        // Insert the block at a deeper indent level. The entire block is outdented.
1502        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1503        buffer.edit(
1504            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1505            Some(AutoindentMode::Block {
1506                original_indent_columns: original_indent_columns.clone(),
1507            }),
1508            cx,
1509        );
1510        assert_eq!(
1511            buffer.text(),
1512            r#"
1513            fn a() {
1514                b();
1515                "
1516                  c
1517                    d
1518                      e
1519                "
1520            }
1521            "#
1522            .unindent()
1523        );
1524
1525        buffer
1526    });
1527}
1528
1529#[gpui::test]
1530fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1531    init_settings(cx, |_| {});
1532
1533    cx.new_model(|cx| {
1534        let text = r#"
1535            fn a() {
1536                if b() {
1537
1538                }
1539            }
1540        "#
1541        .unindent();
1542        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1543
1544        // The original indent columns are not known, so this text is
1545        // auto-indented in a block as if the first line was copied in
1546        // its entirety.
1547        let original_indent_columns = Vec::new();
1548        let inserted_text = "    c\n        .d()\n        .e();";
1549
1550        // Insert the block at column zero. The entire block is indented
1551        // so that the first line matches the previous line's indentation.
1552        buffer.edit(
1553            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1554            Some(AutoindentMode::Block {
1555                original_indent_columns: original_indent_columns.clone(),
1556            }),
1557            cx,
1558        );
1559        assert_eq!(
1560            buffer.text(),
1561            r#"
1562            fn a() {
1563                if b() {
1564                    c
1565                        .d()
1566                        .e();
1567                }
1568            }
1569            "#
1570            .unindent()
1571        );
1572
1573        // Grouping is disabled in tests, so we need 2 undos
1574        buffer.undo(cx); // Undo the auto-indent
1575        buffer.undo(cx); // Undo the original edit
1576
1577        // Insert the block at a deeper indent level. The entire block is outdented.
1578        buffer.edit(
1579            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1580            None,
1581            cx,
1582        );
1583        buffer.edit(
1584            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1585            Some(AutoindentMode::Block {
1586                original_indent_columns: Vec::new(),
1587            }),
1588            cx,
1589        );
1590        assert_eq!(
1591            buffer.text(),
1592            r#"
1593            fn a() {
1594                if b() {
1595                    c
1596                        .d()
1597                        .e();
1598                }
1599            }
1600            "#
1601            .unindent()
1602        );
1603
1604        buffer
1605    });
1606}
1607
1608#[gpui::test]
1609fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1610    init_settings(cx, |_| {});
1611
1612    cx.new_model(|cx| {
1613        let text = "
1614            * one
1615                - a
1616                - b
1617            * two
1618        "
1619        .unindent();
1620
1621        let mut buffer = Buffer::local(text, cx).with_language(
1622            Arc::new(Language::new(
1623                LanguageConfig {
1624                    name: "Markdown".into(),
1625                    auto_indent_using_last_non_empty_line: false,
1626                    ..Default::default()
1627                },
1628                Some(tree_sitter_json::language()),
1629            )),
1630            cx,
1631        );
1632        buffer.edit(
1633            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1634            Some(AutoindentMode::EachLine),
1635            cx,
1636        );
1637        assert_eq!(
1638            buffer.text(),
1639            "
1640            * one
1641                - a
1642                - b
1643
1644            * two
1645            "
1646            .unindent()
1647        );
1648        buffer
1649    });
1650}
1651
1652#[gpui::test]
1653fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1654    init_settings(cx, |settings| {
1655        settings.languages.extend([
1656            (
1657                "HTML".into(),
1658                LanguageSettingsContent {
1659                    tab_size: Some(2.try_into().unwrap()),
1660                    ..Default::default()
1661                },
1662            ),
1663            (
1664                "JavaScript".into(),
1665                LanguageSettingsContent {
1666                    tab_size: Some(8.try_into().unwrap()),
1667                    ..Default::default()
1668                },
1669            ),
1670        ])
1671    });
1672
1673    let html_language = Arc::new(html_lang());
1674
1675    let javascript_language = Arc::new(javascript_lang());
1676
1677    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1678    language_registry.add(html_language.clone());
1679    language_registry.add(javascript_language.clone());
1680
1681    cx.new_model(|cx| {
1682        let (text, ranges) = marked_text_ranges(
1683            &"
1684                <div>ˇ
1685                </div>
1686                <script>
1687                    init({ˇ
1688                    })
1689                </script>
1690                <span>ˇ
1691                </span>
1692            "
1693            .unindent(),
1694            false,
1695        );
1696
1697        let mut buffer = Buffer::local(text, cx);
1698        buffer.set_language_registry(language_registry);
1699        buffer.set_language(Some(html_language), cx);
1700        buffer.edit(
1701            ranges.into_iter().map(|range| (range, "\na")),
1702            Some(AutoindentMode::EachLine),
1703            cx,
1704        );
1705        assert_eq!(
1706            buffer.text(),
1707            "
1708                <div>
1709                  a
1710                </div>
1711                <script>
1712                    init({
1713                            a
1714                    })
1715                </script>
1716                <span>
1717                  a
1718                </span>
1719            "
1720            .unindent()
1721        );
1722        buffer
1723    });
1724}
1725
1726#[gpui::test]
1727fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1728    init_settings(cx, |settings| {
1729        settings.defaults.tab_size = Some(2.try_into().unwrap());
1730    });
1731
1732    cx.new_model(|cx| {
1733        let mut buffer = Buffer::local("", cx).with_language(Arc::new(ruby_lang()), cx);
1734
1735        let text = r#"
1736            class C
1737            def a(b, c)
1738            puts b
1739            puts c
1740            rescue
1741            puts "errored"
1742            exit 1
1743            end
1744            end
1745        "#
1746        .unindent();
1747
1748        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1749
1750        assert_eq!(
1751            buffer.text(),
1752            r#"
1753                class C
1754                  def a(b, c)
1755                    puts b
1756                    puts c
1757                  rescue
1758                    puts "errored"
1759                    exit 1
1760                  end
1761                end
1762            "#
1763            .unindent()
1764        );
1765
1766        buffer
1767    });
1768}
1769
1770#[gpui::test]
1771fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1772    init_settings(cx, |_| {});
1773
1774    cx.new_model(|cx| {
1775        let language = Language::new(
1776            LanguageConfig {
1777                name: "JavaScript".into(),
1778                line_comments: vec!["// ".into()],
1779                brackets: BracketPairConfig {
1780                    pairs: vec![
1781                        BracketPair {
1782                            start: "{".into(),
1783                            end: "}".into(),
1784                            close: true,
1785                            newline: false,
1786                        },
1787                        BracketPair {
1788                            start: "'".into(),
1789                            end: "'".into(),
1790                            close: true,
1791                            newline: false,
1792                        },
1793                    ],
1794                    disabled_scopes_by_bracket_ix: vec![
1795                        Vec::new(), //
1796                        vec!["string".into()],
1797                    ],
1798                },
1799                overrides: [(
1800                    "element".into(),
1801                    LanguageConfigOverride {
1802                        line_comments: Override::Remove { remove: true },
1803                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1804                        ..Default::default()
1805                    },
1806                )]
1807                .into_iter()
1808                .collect(),
1809                ..Default::default()
1810            },
1811            Some(tree_sitter_typescript::language_tsx()),
1812        )
1813        .with_override_query(
1814            r#"
1815                (jsx_element) @element
1816                (string) @string
1817                [
1818                    (jsx_opening_element)
1819                    (jsx_closing_element)
1820                    (jsx_expression)
1821                ] @default
1822            "#,
1823        )
1824        .unwrap();
1825
1826        let text = r#"
1827            a["b"] = <C d="e">
1828                <F></F>
1829                { g() }
1830            </C>;
1831        "#
1832        .unindent();
1833
1834        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
1835        let snapshot = buffer.snapshot();
1836
1837        let config = snapshot.language_scope_at(0).unwrap();
1838        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
1839        // Both bracket pairs are enabled
1840        assert_eq!(
1841            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1842            &[true, true]
1843        );
1844
1845        let string_config = snapshot
1846            .language_scope_at(text.find("b\"").unwrap())
1847            .unwrap();
1848        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
1849        // Second bracket pair is disabled
1850        assert_eq!(
1851            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1852            &[true, false]
1853        );
1854
1855        // In between JSX tags: use the `element` override.
1856        let element_config = snapshot
1857            .language_scope_at(text.find("<F>").unwrap())
1858            .unwrap();
1859        assert_eq!(element_config.line_comment_prefixes(), &[]);
1860        assert_eq!(
1861            element_config.block_comment_delimiters(),
1862            Some((&"{/*".into(), &"*/}".into()))
1863        );
1864        assert_eq!(
1865            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1866            &[true, true]
1867        );
1868
1869        // Within a JSX tag: use the default config.
1870        let tag_config = snapshot
1871            .language_scope_at(text.find(" d=").unwrap() + 1)
1872            .unwrap();
1873        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
1874        assert_eq!(
1875            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1876            &[true, true]
1877        );
1878
1879        // In a JSX expression: use the default config.
1880        let expression_in_element_config = snapshot
1881            .language_scope_at(text.find('{').unwrap() + 1)
1882            .unwrap();
1883        assert_eq!(
1884            expression_in_element_config.line_comment_prefixes(),
1885            &[Arc::from("// ")]
1886        );
1887        assert_eq!(
1888            expression_in_element_config
1889                .brackets()
1890                .map(|e| e.1)
1891                .collect::<Vec<_>>(),
1892            &[true, true]
1893        );
1894
1895        buffer
1896    });
1897}
1898
1899#[gpui::test]
1900fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1901    init_settings(cx, |_| {});
1902
1903    cx.new_model(|cx| {
1904        let language = Language::new(
1905            LanguageConfig {
1906                name: "Rust".into(),
1907                brackets: BracketPairConfig {
1908                    pairs: vec![
1909                        BracketPair {
1910                            start: "{".into(),
1911                            end: "}".into(),
1912                            close: true,
1913                            newline: false,
1914                        },
1915                        BracketPair {
1916                            start: "'".into(),
1917                            end: "'".into(),
1918                            close: true,
1919                            newline: false,
1920                        },
1921                    ],
1922                    disabled_scopes_by_bracket_ix: vec![
1923                        Vec::new(), //
1924                        vec!["string".into()],
1925                    ],
1926                },
1927                ..Default::default()
1928            },
1929            Some(tree_sitter_rust::language()),
1930        )
1931        .with_override_query(
1932            r#"
1933                (string_literal) @string
1934            "#,
1935        )
1936        .unwrap();
1937
1938        let text = r#"
1939            const S: &'static str = "hello";
1940        "#
1941        .unindent();
1942
1943        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
1944        let snapshot = buffer.snapshot();
1945
1946        // By default, all brackets are enabled
1947        let config = snapshot.language_scope_at(0).unwrap();
1948        assert_eq!(
1949            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1950            &[true, true]
1951        );
1952
1953        // Within a string, the quotation brackets are disabled.
1954        let string_config = snapshot
1955            .language_scope_at(text.find("ello").unwrap())
1956            .unwrap();
1957        assert_eq!(
1958            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1959            &[true, false]
1960        );
1961
1962        buffer
1963    });
1964}
1965
1966#[gpui::test]
1967fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1968    init_settings(cx, |_| {});
1969
1970    cx.new_model(|cx| {
1971        let text = r#"
1972            <ol>
1973            <% people.each do |person| %>
1974                <li>
1975                    <%= person.name %>
1976                </li>
1977            <% end %>
1978            </ol>
1979        "#
1980        .unindent();
1981
1982        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1983        language_registry.add(Arc::new(ruby_lang()));
1984        language_registry.add(Arc::new(html_lang()));
1985        language_registry.add(Arc::new(erb_lang()));
1986
1987        let mut buffer = Buffer::local(text, cx);
1988        buffer.set_language_registry(language_registry.clone());
1989        buffer.set_language(
1990            language_registry
1991                .language_for_name("ERB")
1992                .now_or_never()
1993                .unwrap()
1994                .ok(),
1995            cx,
1996        );
1997
1998        let snapshot = buffer.snapshot();
1999        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2000        assert_eq!(html_config.line_comment_prefixes(), &[]);
2001        assert_eq!(
2002            html_config.block_comment_delimiters(),
2003            Some((&"<!--".into(), &"-->".into()))
2004        );
2005
2006        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2007        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2008        assert_eq!(ruby_config.block_comment_delimiters(), None);
2009
2010        buffer
2011    });
2012}
2013
2014#[gpui::test]
2015fn test_serialization(cx: &mut gpui::AppContext) {
2016    let mut now = Instant::now();
2017
2018    let buffer1 = cx.new_model(|cx| {
2019        let mut buffer = Buffer::local("abc", cx);
2020        buffer.edit([(3..3, "D")], None, cx);
2021
2022        now += Duration::from_secs(1);
2023        buffer.start_transaction_at(now);
2024        buffer.edit([(4..4, "E")], None, cx);
2025        buffer.end_transaction_at(now, cx);
2026        assert_eq!(buffer.text(), "abcDE");
2027
2028        buffer.undo(cx);
2029        assert_eq!(buffer.text(), "abcD");
2030
2031        buffer.edit([(4..4, "F")], None, cx);
2032        assert_eq!(buffer.text(), "abcDF");
2033        buffer
2034    });
2035    assert_eq!(buffer1.read(cx).text(), "abcDF");
2036
2037    let state = buffer1.read(cx).to_proto();
2038    let ops = cx
2039        .background_executor()
2040        .block(buffer1.read(cx).serialize_ops(None, cx));
2041    let buffer2 = cx.new_model(|cx| {
2042        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2043        buffer
2044            .apply_ops(
2045                ops.into_iter()
2046                    .map(|op| proto::deserialize_operation(op).unwrap()),
2047                cx,
2048            )
2049            .unwrap();
2050        buffer
2051    });
2052    assert_eq!(buffer2.read(cx).text(), "abcDF");
2053}
2054
2055#[gpui::test(iterations = 100)]
2056fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2057    let min_peers = env::var("MIN_PEERS")
2058        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2059        .unwrap_or(1);
2060    let max_peers = env::var("MAX_PEERS")
2061        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2062        .unwrap_or(5);
2063    let operations = env::var("OPERATIONS")
2064        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2065        .unwrap_or(10);
2066
2067    let base_text_len = rng.gen_range(0..10);
2068    let base_text = RandomCharIter::new(&mut rng)
2069        .take(base_text_len)
2070        .collect::<String>();
2071    let mut replica_ids = Vec::new();
2072    let mut buffers = Vec::new();
2073    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2074    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2075
2076    for i in 0..rng.gen_range(min_peers..=max_peers) {
2077        let buffer = cx.new_model(|cx| {
2078            let state = base_buffer.read(cx).to_proto();
2079            let ops = cx
2080                .background_executor()
2081                .block(base_buffer.read(cx).serialize_ops(None, cx));
2082            let mut buffer =
2083                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2084            buffer
2085                .apply_ops(
2086                    ops.into_iter()
2087                        .map(|op| proto::deserialize_operation(op).unwrap()),
2088                    cx,
2089                )
2090                .unwrap();
2091            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2092            let network = network.clone();
2093            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2094                if let Event::Operation(op) = event {
2095                    network
2096                        .lock()
2097                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2098                }
2099            })
2100            .detach();
2101            buffer
2102        });
2103
2104        buffers.push(buffer);
2105        replica_ids.push(i as ReplicaId);
2106        network.lock().add_peer(i as ReplicaId);
2107        log::info!("Adding initial peer with replica id {}", i);
2108    }
2109
2110    log::info!("initial text: {:?}", base_text);
2111
2112    let mut now = Instant::now();
2113    let mut mutation_count = operations;
2114    let mut next_diagnostic_id = 0;
2115    let mut active_selections = BTreeMap::default();
2116    loop {
2117        let replica_index = rng.gen_range(0..replica_ids.len());
2118        let replica_id = replica_ids[replica_index];
2119        let buffer = &mut buffers[replica_index];
2120        let mut new_buffer = None;
2121        match rng.gen_range(0..100) {
2122            0..=29 if mutation_count != 0 => {
2123                buffer.update(cx, |buffer, cx| {
2124                    buffer.start_transaction_at(now);
2125                    buffer.randomly_edit(&mut rng, 5, cx);
2126                    buffer.end_transaction_at(now, cx);
2127                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2128                });
2129                mutation_count -= 1;
2130            }
2131            30..=39 if mutation_count != 0 => {
2132                buffer.update(cx, |buffer, cx| {
2133                    if rng.gen_bool(0.2) {
2134                        log::info!("peer {} clearing active selections", replica_id);
2135                        active_selections.remove(&replica_id);
2136                        buffer.remove_active_selections(cx);
2137                    } else {
2138                        let mut selections = Vec::new();
2139                        for id in 0..rng.gen_range(1..=5) {
2140                            let range = buffer.random_byte_range(0, &mut rng);
2141                            selections.push(Selection {
2142                                id,
2143                                start: buffer.anchor_before(range.start),
2144                                end: buffer.anchor_before(range.end),
2145                                reversed: false,
2146                                goal: SelectionGoal::None,
2147                            });
2148                        }
2149                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2150                        log::info!(
2151                            "peer {} setting active selections: {:?}",
2152                            replica_id,
2153                            selections
2154                        );
2155                        active_selections.insert(replica_id, selections.clone());
2156                        buffer.set_active_selections(selections, false, Default::default(), cx);
2157                    }
2158                });
2159                mutation_count -= 1;
2160            }
2161            40..=49 if mutation_count != 0 && replica_id == 0 => {
2162                let entry_count = rng.gen_range(1..=5);
2163                buffer.update(cx, |buffer, cx| {
2164                    let diagnostics = DiagnosticSet::new(
2165                        (0..entry_count).map(|_| {
2166                            let range = buffer.random_byte_range(0, &mut rng);
2167                            let range = range.to_point_utf16(buffer);
2168                            let range = range.start..range.end;
2169                            DiagnosticEntry {
2170                                range,
2171                                diagnostic: Diagnostic {
2172                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2173                                    ..Default::default()
2174                                },
2175                            }
2176                        }),
2177                        buffer,
2178                    );
2179                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2180                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2181                });
2182                mutation_count -= 1;
2183            }
2184            50..=59 if replica_ids.len() < max_peers => {
2185                let old_buffer_state = buffer.read(cx).to_proto();
2186                let old_buffer_ops = cx
2187                    .background_executor()
2188                    .block(buffer.read(cx).serialize_ops(None, cx));
2189                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2190                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2191                    .choose(&mut rng)
2192                    .unwrap();
2193                log::info!(
2194                    "Adding new replica {} (replicating from {})",
2195                    new_replica_id,
2196                    replica_id
2197                );
2198                new_buffer = Some(cx.new_model(|cx| {
2199                    let mut new_buffer = Buffer::from_proto(
2200                        new_replica_id,
2201                        Capability::ReadWrite,
2202                        old_buffer_state,
2203                        None,
2204                    )
2205                    .unwrap();
2206                    new_buffer
2207                        .apply_ops(
2208                            old_buffer_ops
2209                                .into_iter()
2210                                .map(|op| deserialize_operation(op).unwrap()),
2211                            cx,
2212                        )
2213                        .unwrap();
2214                    log::info!(
2215                        "New replica {} text: {:?}",
2216                        new_buffer.replica_id(),
2217                        new_buffer.text()
2218                    );
2219                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2220                    let network = network.clone();
2221                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2222                        if let Event::Operation(op) = event {
2223                            network.lock().broadcast(
2224                                buffer.replica_id(),
2225                                vec![proto::serialize_operation(op)],
2226                            );
2227                        }
2228                    })
2229                    .detach();
2230                    new_buffer
2231                }));
2232                network.lock().replicate(replica_id, new_replica_id);
2233
2234                if new_replica_id as usize == replica_ids.len() {
2235                    replica_ids.push(new_replica_id);
2236                } else {
2237                    let new_buffer = new_buffer.take().unwrap();
2238                    while network.lock().has_unreceived(new_replica_id) {
2239                        let ops = network
2240                            .lock()
2241                            .receive(new_replica_id)
2242                            .into_iter()
2243                            .map(|op| proto::deserialize_operation(op).unwrap());
2244                        if ops.len() > 0 {
2245                            log::info!(
2246                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2247                                new_replica_id,
2248                                buffer.read(cx).version(),
2249                                ops.len(),
2250                                ops
2251                            );
2252                            new_buffer.update(cx, |new_buffer, cx| {
2253                                new_buffer.apply_ops(ops, cx).unwrap();
2254                            });
2255                        }
2256                    }
2257                    buffers[new_replica_id as usize] = new_buffer;
2258                }
2259            }
2260            60..=69 if mutation_count != 0 => {
2261                buffer.update(cx, |buffer, cx| {
2262                    buffer.randomly_undo_redo(&mut rng, cx);
2263                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2264                });
2265                mutation_count -= 1;
2266            }
2267            _ if network.lock().has_unreceived(replica_id) => {
2268                let ops = network
2269                    .lock()
2270                    .receive(replica_id)
2271                    .into_iter()
2272                    .map(|op| proto::deserialize_operation(op).unwrap());
2273                if ops.len() > 0 {
2274                    log::info!(
2275                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2276                        replica_id,
2277                        buffer.read(cx).version(),
2278                        ops.len(),
2279                        ops
2280                    );
2281                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2282                }
2283            }
2284            _ => {}
2285        }
2286
2287        now += Duration::from_millis(rng.gen_range(0..=200));
2288        buffers.extend(new_buffer);
2289
2290        for buffer in &buffers {
2291            buffer.read(cx).check_invariants();
2292        }
2293
2294        if mutation_count == 0 && network.lock().is_idle() {
2295            break;
2296        }
2297    }
2298
2299    let first_buffer = buffers[0].read(cx).snapshot();
2300    for buffer in &buffers[1..] {
2301        let buffer = buffer.read(cx).snapshot();
2302        assert_eq!(
2303            buffer.version(),
2304            first_buffer.version(),
2305            "Replica {} version != Replica 0 version",
2306            buffer.replica_id()
2307        );
2308        assert_eq!(
2309            buffer.text(),
2310            first_buffer.text(),
2311            "Replica {} text != Replica 0 text",
2312            buffer.replica_id()
2313        );
2314        assert_eq!(
2315            buffer
2316                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2317                .collect::<Vec<_>>(),
2318            first_buffer
2319                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2320                .collect::<Vec<_>>(),
2321            "Replica {} diagnostics != Replica 0 diagnostics",
2322            buffer.replica_id()
2323        );
2324    }
2325
2326    for buffer in &buffers {
2327        let buffer = buffer.read(cx).snapshot();
2328        let actual_remote_selections = buffer
2329            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2330            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2331            .collect::<Vec<_>>();
2332        let expected_remote_selections = active_selections
2333            .iter()
2334            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2335            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2336            .collect::<Vec<_>>();
2337        assert_eq!(
2338            actual_remote_selections,
2339            expected_remote_selections,
2340            "Replica {} remote selections != expected selections",
2341            buffer.replica_id()
2342        );
2343    }
2344}
2345
2346#[test]
2347fn test_contiguous_ranges() {
2348    assert_eq!(
2349        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2350        &[1..4, 5..7, 9..13]
2351    );
2352
2353    // Respects the `max_len` parameter
2354    assert_eq!(
2355        contiguous_ranges(
2356            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2357            3
2358        )
2359        .collect::<Vec<_>>(),
2360        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2361    );
2362}
2363
2364#[gpui::test(iterations = 500)]
2365fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2366    // Generate a random multi-line string containing
2367    // some lines with trailing whitespace.
2368    let mut text = String::new();
2369    for _ in 0..rng.gen_range(0..16) {
2370        for _ in 0..rng.gen_range(0..36) {
2371            text.push(match rng.gen_range(0..10) {
2372                0..=1 => ' ',
2373                3 => '\t',
2374                _ => rng.gen_range('a'..'z'),
2375            });
2376        }
2377        text.push('\n');
2378    }
2379
2380    match rng.gen_range(0..10) {
2381        // sometimes remove the last newline
2382        0..=1 => drop(text.pop()), //
2383
2384        // sometimes add extra newlines
2385        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2386        _ => {}
2387    }
2388
2389    let rope = Rope::from(text.as_str());
2390    let actual_ranges = trailing_whitespace_ranges(&rope);
2391    let expected_ranges = TRAILING_WHITESPACE_REGEX
2392        .find_iter(&text)
2393        .map(|m| m.range())
2394        .collect::<Vec<_>>();
2395    assert_eq!(
2396        actual_ranges,
2397        expected_ranges,
2398        "wrong ranges for text lines:\n{:?}",
2399        text.split('\n').collect::<Vec<_>>()
2400    );
2401}
2402
2403fn ruby_lang() -> Language {
2404    Language::new(
2405        LanguageConfig {
2406            name: "Ruby".into(),
2407            matcher: LanguageMatcher {
2408                path_suffixes: vec!["rb".to_string()],
2409                ..Default::default()
2410            },
2411            line_comments: vec!["# ".into()],
2412            ..Default::default()
2413        },
2414        Some(tree_sitter_ruby::language()),
2415    )
2416    .with_indents_query(
2417        r#"
2418            (class "end" @end) @indent
2419            (method "end" @end) @indent
2420            (rescue) @outdent
2421            (then) @indent
2422        "#,
2423    )
2424    .unwrap()
2425}
2426
2427fn html_lang() -> Language {
2428    Language::new(
2429        LanguageConfig {
2430            name: "HTML".into(),
2431            block_comment: Some(("<!--".into(), "-->".into())),
2432            ..Default::default()
2433        },
2434        Some(tree_sitter_html::language()),
2435    )
2436    .with_indents_query(
2437        "
2438        (element
2439          (start_tag) @start
2440          (end_tag)? @end) @indent
2441        ",
2442    )
2443    .unwrap()
2444    .with_injection_query(
2445        r#"
2446        (script_element
2447            (raw_text) @content
2448            (#set! "language" "javascript"))
2449        "#,
2450    )
2451    .unwrap()
2452}
2453
2454fn erb_lang() -> Language {
2455    Language::new(
2456        LanguageConfig {
2457            name: "ERB".into(),
2458            matcher: LanguageMatcher {
2459                path_suffixes: vec!["erb".to_string()],
2460                ..Default::default()
2461            },
2462            block_comment: Some(("<%#".into(), "%>".into())),
2463            ..Default::default()
2464        },
2465        Some(tree_sitter_embedded_template::language()),
2466    )
2467    .with_injection_query(
2468        r#"
2469            (
2470                (code) @content
2471                (#set! "language" "ruby")
2472                (#set! "combined")
2473            )
2474
2475            (
2476                (content) @content
2477                (#set! "language" "html")
2478                (#set! "combined")
2479            )
2480        "#,
2481    )
2482    .unwrap()
2483}
2484
2485fn rust_lang() -> Language {
2486    Language::new(
2487        LanguageConfig {
2488            name: "Rust".into(),
2489            matcher: LanguageMatcher {
2490                path_suffixes: vec!["rs".to_string()],
2491                ..Default::default()
2492            },
2493            ..Default::default()
2494        },
2495        Some(tree_sitter_rust::language()),
2496    )
2497    .with_indents_query(
2498        r#"
2499        (call_expression) @indent
2500        (field_expression) @indent
2501        (_ "(" ")" @end) @indent
2502        (_ "{" "}" @end) @indent
2503        "#,
2504    )
2505    .unwrap()
2506    .with_brackets_query(
2507        r#"
2508        ("{" @open "}" @close)
2509        "#,
2510    )
2511    .unwrap()
2512    .with_outline_query(
2513        r#"
2514        (struct_item
2515            "struct" @context
2516            name: (_) @name) @item
2517        (enum_item
2518            "enum" @context
2519            name: (_) @name) @item
2520        (enum_variant
2521            name: (_) @name) @item
2522        (field_declaration
2523            name: (_) @name) @item
2524        (impl_item
2525            "impl" @context
2526            trait: (_)? @name
2527            "for"? @context
2528            type: (_) @name) @item
2529        (function_item
2530            "fn" @context
2531            name: (_) @name) @item
2532        (mod_item
2533            "mod" @context
2534            name: (_) @name) @item
2535        "#,
2536    )
2537    .unwrap()
2538}
2539
2540fn json_lang() -> Language {
2541    Language::new(
2542        LanguageConfig {
2543            name: "Json".into(),
2544            matcher: LanguageMatcher {
2545                path_suffixes: vec!["js".to_string()],
2546                ..Default::default()
2547            },
2548            ..Default::default()
2549        },
2550        Some(tree_sitter_json::language()),
2551    )
2552}
2553
2554fn javascript_lang() -> Language {
2555    Language::new(
2556        LanguageConfig {
2557            name: "JavaScript".into(),
2558            ..Default::default()
2559        },
2560        Some(tree_sitter_typescript::language_tsx()),
2561    )
2562    .with_brackets_query(
2563        r#"
2564        ("{" @open "}" @close)
2565        ("(" @open ")" @close)
2566        "#,
2567    )
2568    .unwrap()
2569    .with_indents_query(
2570        r#"
2571        (object "}" @end) @indent
2572        "#,
2573    )
2574    .unwrap()
2575}
2576
2577fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2578    buffer.update(cx, |buffer, _| {
2579        let snapshot = buffer.snapshot();
2580        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2581        layers[0].node().to_sexp()
2582    })
2583}
2584
2585// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2586fn assert_bracket_pairs(
2587    selection_text: &'static str,
2588    bracket_pair_texts: Vec<&'static str>,
2589    language: Language,
2590    cx: &mut AppContext,
2591) {
2592    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2593    let buffer = cx.new_model(|cx| {
2594        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2595    });
2596    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2597
2598    let selection_range = selection_ranges[0].clone();
2599
2600    let bracket_pairs = bracket_pair_texts
2601        .into_iter()
2602        .map(|pair_text| {
2603            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2604            assert_eq!(bracket_text, expected_text);
2605            (ranges[0].clone(), ranges[1].clone())
2606        })
2607        .collect::<Vec<_>>();
2608
2609    assert_set_eq!(
2610        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2611        bracket_pairs
2612    );
2613}
2614
2615fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2616    let settings_store = SettingsStore::test(cx);
2617    cx.set_global(settings_store);
2618    crate::init(cx);
2619    cx.update_global::<SettingsStore, _>(|settings, cx| {
2620        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2621    });
2622}