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