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(), &[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!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
1832        // Second bracket pair is disabled
1833        assert_eq!(
1834            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1835            &[true, false]
1836        );
1837
1838        // In between JSX tags: use the `element` override.
1839        let element_config = snapshot
1840            .language_scope_at(text.find("<F>").unwrap())
1841            .unwrap();
1842        assert_eq!(element_config.line_comment_prefixes(), &[]);
1843        assert_eq!(
1844            element_config.block_comment_delimiters(),
1845            Some((&"{/*".into(), &"*/}".into()))
1846        );
1847        assert_eq!(
1848            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1849            &[true, true]
1850        );
1851
1852        // Within a JSX tag: use the default config.
1853        let tag_config = snapshot
1854            .language_scope_at(text.find(" d=").unwrap() + 1)
1855            .unwrap();
1856        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
1857        assert_eq!(
1858            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1859            &[true, true]
1860        );
1861
1862        // In a JSX expression: use the default config.
1863        let expression_in_element_config = snapshot
1864            .language_scope_at(text.find('{').unwrap() + 1)
1865            .unwrap();
1866        assert_eq!(
1867            expression_in_element_config.line_comment_prefixes(),
1868            &[Arc::from("// ")]
1869        );
1870        assert_eq!(
1871            expression_in_element_config
1872                .brackets()
1873                .map(|e| e.1)
1874                .collect::<Vec<_>>(),
1875            &[true, true]
1876        );
1877
1878        buffer
1879    });
1880}
1881
1882#[gpui::test]
1883fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1884    init_settings(cx, |_| {});
1885
1886    cx.new_model(|cx| {
1887        let language = Language::new(
1888            LanguageConfig {
1889                name: "Rust".into(),
1890                brackets: BracketPairConfig {
1891                    pairs: vec![
1892                        BracketPair {
1893                            start: "{".into(),
1894                            end: "}".into(),
1895                            close: true,
1896                            newline: false,
1897                        },
1898                        BracketPair {
1899                            start: "'".into(),
1900                            end: "'".into(),
1901                            close: true,
1902                            newline: false,
1903                        },
1904                    ],
1905                    disabled_scopes_by_bracket_ix: vec![
1906                        Vec::new(), //
1907                        vec!["string".into()],
1908                    ],
1909                },
1910                ..Default::default()
1911            },
1912            Some(tree_sitter_rust::language()),
1913        )
1914        .with_override_query(
1915            r#"
1916                (string_literal) @string
1917            "#,
1918        )
1919        .unwrap();
1920
1921        let text = r#"
1922            const S: &'static str = "hello";
1923        "#
1924        .unindent();
1925
1926        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
1927        let snapshot = buffer.snapshot();
1928
1929        // By default, all brackets are enabled
1930        let config = snapshot.language_scope_at(0).unwrap();
1931        assert_eq!(
1932            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1933            &[true, true]
1934        );
1935
1936        // Within a string, the quotation brackets are disabled.
1937        let string_config = snapshot
1938            .language_scope_at(text.find("ello").unwrap())
1939            .unwrap();
1940        assert_eq!(
1941            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1942            &[true, false]
1943        );
1944
1945        buffer
1946    });
1947}
1948
1949#[gpui::test]
1950fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1951    init_settings(cx, |_| {});
1952
1953    cx.new_model(|cx| {
1954        let text = r#"
1955            <ol>
1956            <% people.each do |person| %>
1957                <li>
1958                    <%= person.name %>
1959                </li>
1960            <% end %>
1961            </ol>
1962        "#
1963        .unindent();
1964
1965        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1966        language_registry.add(Arc::new(ruby_lang()));
1967        language_registry.add(Arc::new(html_lang()));
1968        language_registry.add(Arc::new(erb_lang()));
1969
1970        let mut buffer = Buffer::local(text, cx);
1971        buffer.set_language_registry(language_registry.clone());
1972        buffer.set_language(
1973            language_registry
1974                .language_for_name("ERB")
1975                .now_or_never()
1976                .unwrap()
1977                .ok(),
1978            cx,
1979        );
1980
1981        let snapshot = buffer.snapshot();
1982        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1983        assert_eq!(html_config.line_comment_prefixes(), &[]);
1984        assert_eq!(
1985            html_config.block_comment_delimiters(),
1986            Some((&"<!--".into(), &"-->".into()))
1987        );
1988
1989        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1990        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
1991        assert_eq!(ruby_config.block_comment_delimiters(), None);
1992
1993        buffer
1994    });
1995}
1996
1997#[gpui::test]
1998fn test_serialization(cx: &mut gpui::AppContext) {
1999    let mut now = Instant::now();
2000
2001    let buffer1 = cx.new_model(|cx| {
2002        let mut buffer = Buffer::local("abc", cx);
2003        buffer.edit([(3..3, "D")], None, cx);
2004
2005        now += Duration::from_secs(1);
2006        buffer.start_transaction_at(now);
2007        buffer.edit([(4..4, "E")], None, cx);
2008        buffer.end_transaction_at(now, cx);
2009        assert_eq!(buffer.text(), "abcDE");
2010
2011        buffer.undo(cx);
2012        assert_eq!(buffer.text(), "abcD");
2013
2014        buffer.edit([(4..4, "F")], None, cx);
2015        assert_eq!(buffer.text(), "abcDF");
2016        buffer
2017    });
2018    assert_eq!(buffer1.read(cx).text(), "abcDF");
2019
2020    let state = buffer1.read(cx).to_proto();
2021    let ops = cx
2022        .background_executor()
2023        .block(buffer1.read(cx).serialize_ops(None, cx));
2024    let buffer2 = cx.new_model(|cx| {
2025        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2026        buffer
2027            .apply_ops(
2028                ops.into_iter()
2029                    .map(|op| proto::deserialize_operation(op).unwrap()),
2030                cx,
2031            )
2032            .unwrap();
2033        buffer
2034    });
2035    assert_eq!(buffer2.read(cx).text(), "abcDF");
2036}
2037
2038#[gpui::test(iterations = 100)]
2039fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2040    let min_peers = env::var("MIN_PEERS")
2041        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2042        .unwrap_or(1);
2043    let max_peers = env::var("MAX_PEERS")
2044        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2045        .unwrap_or(5);
2046    let operations = env::var("OPERATIONS")
2047        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2048        .unwrap_or(10);
2049
2050    let base_text_len = rng.gen_range(0..10);
2051    let base_text = RandomCharIter::new(&mut rng)
2052        .take(base_text_len)
2053        .collect::<String>();
2054    let mut replica_ids = Vec::new();
2055    let mut buffers = Vec::new();
2056    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2057    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2058
2059    for i in 0..rng.gen_range(min_peers..=max_peers) {
2060        let buffer = cx.new_model(|cx| {
2061            let state = base_buffer.read(cx).to_proto();
2062            let ops = cx
2063                .background_executor()
2064                .block(base_buffer.read(cx).serialize_ops(None, cx));
2065            let mut buffer =
2066                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2067            buffer
2068                .apply_ops(
2069                    ops.into_iter()
2070                        .map(|op| proto::deserialize_operation(op).unwrap()),
2071                    cx,
2072                )
2073                .unwrap();
2074            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2075            let network = network.clone();
2076            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2077                if let Event::Operation(op) = event {
2078                    network
2079                        .lock()
2080                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2081                }
2082            })
2083            .detach();
2084            buffer
2085        });
2086
2087        buffers.push(buffer);
2088        replica_ids.push(i as ReplicaId);
2089        network.lock().add_peer(i as ReplicaId);
2090        log::info!("Adding initial peer with replica id {}", i);
2091    }
2092
2093    log::info!("initial text: {:?}", base_text);
2094
2095    let mut now = Instant::now();
2096    let mut mutation_count = operations;
2097    let mut next_diagnostic_id = 0;
2098    let mut active_selections = BTreeMap::default();
2099    loop {
2100        let replica_index = rng.gen_range(0..replica_ids.len());
2101        let replica_id = replica_ids[replica_index];
2102        let buffer = &mut buffers[replica_index];
2103        let mut new_buffer = None;
2104        match rng.gen_range(0..100) {
2105            0..=29 if mutation_count != 0 => {
2106                buffer.update(cx, |buffer, cx| {
2107                    buffer.start_transaction_at(now);
2108                    buffer.randomly_edit(&mut rng, 5, cx);
2109                    buffer.end_transaction_at(now, cx);
2110                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2111                });
2112                mutation_count -= 1;
2113            }
2114            30..=39 if mutation_count != 0 => {
2115                buffer.update(cx, |buffer, cx| {
2116                    if rng.gen_bool(0.2) {
2117                        log::info!("peer {} clearing active selections", replica_id);
2118                        active_selections.remove(&replica_id);
2119                        buffer.remove_active_selections(cx);
2120                    } else {
2121                        let mut selections = Vec::new();
2122                        for id in 0..rng.gen_range(1..=5) {
2123                            let range = buffer.random_byte_range(0, &mut rng);
2124                            selections.push(Selection {
2125                                id,
2126                                start: buffer.anchor_before(range.start),
2127                                end: buffer.anchor_before(range.end),
2128                                reversed: false,
2129                                goal: SelectionGoal::None,
2130                            });
2131                        }
2132                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2133                        log::info!(
2134                            "peer {} setting active selections: {:?}",
2135                            replica_id,
2136                            selections
2137                        );
2138                        active_selections.insert(replica_id, selections.clone());
2139                        buffer.set_active_selections(selections, false, Default::default(), cx);
2140                    }
2141                });
2142                mutation_count -= 1;
2143            }
2144            40..=49 if mutation_count != 0 && replica_id == 0 => {
2145                let entry_count = rng.gen_range(1..=5);
2146                buffer.update(cx, |buffer, cx| {
2147                    let diagnostics = DiagnosticSet::new(
2148                        (0..entry_count).map(|_| {
2149                            let range = buffer.random_byte_range(0, &mut rng);
2150                            let range = range.to_point_utf16(buffer);
2151                            let range = range.start..range.end;
2152                            DiagnosticEntry {
2153                                range,
2154                                diagnostic: Diagnostic {
2155                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2156                                    ..Default::default()
2157                                },
2158                            }
2159                        }),
2160                        buffer,
2161                    );
2162                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2163                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2164                });
2165                mutation_count -= 1;
2166            }
2167            50..=59 if replica_ids.len() < max_peers => {
2168                let old_buffer_state = buffer.read(cx).to_proto();
2169                let old_buffer_ops = cx
2170                    .background_executor()
2171                    .block(buffer.read(cx).serialize_ops(None, cx));
2172                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2173                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2174                    .choose(&mut rng)
2175                    .unwrap();
2176                log::info!(
2177                    "Adding new replica {} (replicating from {})",
2178                    new_replica_id,
2179                    replica_id
2180                );
2181                new_buffer = Some(cx.new_model(|cx| {
2182                    let mut new_buffer = Buffer::from_proto(
2183                        new_replica_id,
2184                        Capability::ReadWrite,
2185                        old_buffer_state,
2186                        None,
2187                    )
2188                    .unwrap();
2189                    new_buffer
2190                        .apply_ops(
2191                            old_buffer_ops
2192                                .into_iter()
2193                                .map(|op| deserialize_operation(op).unwrap()),
2194                            cx,
2195                        )
2196                        .unwrap();
2197                    log::info!(
2198                        "New replica {} text: {:?}",
2199                        new_buffer.replica_id(),
2200                        new_buffer.text()
2201                    );
2202                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2203                    let network = network.clone();
2204                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2205                        if let Event::Operation(op) = event {
2206                            network.lock().broadcast(
2207                                buffer.replica_id(),
2208                                vec![proto::serialize_operation(op)],
2209                            );
2210                        }
2211                    })
2212                    .detach();
2213                    new_buffer
2214                }));
2215                network.lock().replicate(replica_id, new_replica_id);
2216
2217                if new_replica_id as usize == replica_ids.len() {
2218                    replica_ids.push(new_replica_id);
2219                } else {
2220                    let new_buffer = new_buffer.take().unwrap();
2221                    while network.lock().has_unreceived(new_replica_id) {
2222                        let ops = network
2223                            .lock()
2224                            .receive(new_replica_id)
2225                            .into_iter()
2226                            .map(|op| proto::deserialize_operation(op).unwrap());
2227                        if ops.len() > 0 {
2228                            log::info!(
2229                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2230                                new_replica_id,
2231                                buffer.read(cx).version(),
2232                                ops.len(),
2233                                ops
2234                            );
2235                            new_buffer.update(cx, |new_buffer, cx| {
2236                                new_buffer.apply_ops(ops, cx).unwrap();
2237                            });
2238                        }
2239                    }
2240                    buffers[new_replica_id as usize] = new_buffer;
2241                }
2242            }
2243            60..=69 if mutation_count != 0 => {
2244                buffer.update(cx, |buffer, cx| {
2245                    buffer.randomly_undo_redo(&mut rng, cx);
2246                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2247                });
2248                mutation_count -= 1;
2249            }
2250            _ if network.lock().has_unreceived(replica_id) => {
2251                let ops = network
2252                    .lock()
2253                    .receive(replica_id)
2254                    .into_iter()
2255                    .map(|op| proto::deserialize_operation(op).unwrap());
2256                if ops.len() > 0 {
2257                    log::info!(
2258                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2259                        replica_id,
2260                        buffer.read(cx).version(),
2261                        ops.len(),
2262                        ops
2263                    );
2264                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2265                }
2266            }
2267            _ => {}
2268        }
2269
2270        now += Duration::from_millis(rng.gen_range(0..=200));
2271        buffers.extend(new_buffer);
2272
2273        for buffer in &buffers {
2274            buffer.read(cx).check_invariants();
2275        }
2276
2277        if mutation_count == 0 && network.lock().is_idle() {
2278            break;
2279        }
2280    }
2281
2282    let first_buffer = buffers[0].read(cx).snapshot();
2283    for buffer in &buffers[1..] {
2284        let buffer = buffer.read(cx).snapshot();
2285        assert_eq!(
2286            buffer.version(),
2287            first_buffer.version(),
2288            "Replica {} version != Replica 0 version",
2289            buffer.replica_id()
2290        );
2291        assert_eq!(
2292            buffer.text(),
2293            first_buffer.text(),
2294            "Replica {} text != Replica 0 text",
2295            buffer.replica_id()
2296        );
2297        assert_eq!(
2298            buffer
2299                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2300                .collect::<Vec<_>>(),
2301            first_buffer
2302                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2303                .collect::<Vec<_>>(),
2304            "Replica {} diagnostics != Replica 0 diagnostics",
2305            buffer.replica_id()
2306        );
2307    }
2308
2309    for buffer in &buffers {
2310        let buffer = buffer.read(cx).snapshot();
2311        let actual_remote_selections = buffer
2312            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2313            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2314            .collect::<Vec<_>>();
2315        let expected_remote_selections = active_selections
2316            .iter()
2317            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2318            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2319            .collect::<Vec<_>>();
2320        assert_eq!(
2321            actual_remote_selections,
2322            expected_remote_selections,
2323            "Replica {} remote selections != expected selections",
2324            buffer.replica_id()
2325        );
2326    }
2327}
2328
2329#[test]
2330fn test_contiguous_ranges() {
2331    assert_eq!(
2332        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2333        &[1..4, 5..7, 9..13]
2334    );
2335
2336    // Respects the `max_len` parameter
2337    assert_eq!(
2338        contiguous_ranges(
2339            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2340            3
2341        )
2342        .collect::<Vec<_>>(),
2343        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2344    );
2345}
2346
2347#[gpui::test(iterations = 500)]
2348fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2349    // Generate a random multi-line string containing
2350    // some lines with trailing whitespace.
2351    let mut text = String::new();
2352    for _ in 0..rng.gen_range(0..16) {
2353        for _ in 0..rng.gen_range(0..36) {
2354            text.push(match rng.gen_range(0..10) {
2355                0..=1 => ' ',
2356                3 => '\t',
2357                _ => rng.gen_range('a'..'z'),
2358            });
2359        }
2360        text.push('\n');
2361    }
2362
2363    match rng.gen_range(0..10) {
2364        // sometimes remove the last newline
2365        0..=1 => drop(text.pop()), //
2366
2367        // sometimes add extra newlines
2368        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2369        _ => {}
2370    }
2371
2372    let rope = Rope::from(text.as_str());
2373    let actual_ranges = trailing_whitespace_ranges(&rope);
2374    let expected_ranges = TRAILING_WHITESPACE_REGEX
2375        .find_iter(&text)
2376        .map(|m| m.range())
2377        .collect::<Vec<_>>();
2378    assert_eq!(
2379        actual_ranges,
2380        expected_ranges,
2381        "wrong ranges for text lines:\n{:?}",
2382        text.split('\n').collect::<Vec<_>>()
2383    );
2384}
2385
2386fn ruby_lang() -> Language {
2387    Language::new(
2388        LanguageConfig {
2389            name: "Ruby".into(),
2390            matcher: LanguageMatcher {
2391                path_suffixes: vec!["rb".to_string()],
2392                ..Default::default()
2393            },
2394            line_comments: vec!["# ".into()],
2395            ..Default::default()
2396        },
2397        Some(tree_sitter_ruby::language()),
2398    )
2399    .with_indents_query(
2400        r#"
2401            (class "end" @end) @indent
2402            (method "end" @end) @indent
2403            (rescue) @outdent
2404            (then) @indent
2405        "#,
2406    )
2407    .unwrap()
2408}
2409
2410fn html_lang() -> Language {
2411    Language::new(
2412        LanguageConfig {
2413            name: "HTML".into(),
2414            block_comment: Some(("<!--".into(), "-->".into())),
2415            ..Default::default()
2416        },
2417        Some(tree_sitter_html::language()),
2418    )
2419    .with_indents_query(
2420        "
2421        (element
2422          (start_tag) @start
2423          (end_tag)? @end) @indent
2424        ",
2425    )
2426    .unwrap()
2427    .with_injection_query(
2428        r#"
2429        (script_element
2430            (raw_text) @content
2431            (#set! "language" "javascript"))
2432        "#,
2433    )
2434    .unwrap()
2435}
2436
2437fn erb_lang() -> Language {
2438    Language::new(
2439        LanguageConfig {
2440            name: "ERB".into(),
2441            matcher: LanguageMatcher {
2442                path_suffixes: vec!["erb".to_string()],
2443                ..Default::default()
2444            },
2445            block_comment: Some(("<%#".into(), "%>".into())),
2446            ..Default::default()
2447        },
2448        Some(tree_sitter_embedded_template::language()),
2449    )
2450    .with_injection_query(
2451        r#"
2452            (
2453                (code) @content
2454                (#set! "language" "ruby")
2455                (#set! "combined")
2456            )
2457
2458            (
2459                (content) @content
2460                (#set! "language" "html")
2461                (#set! "combined")
2462            )
2463        "#,
2464    )
2465    .unwrap()
2466}
2467
2468fn rust_lang() -> Language {
2469    Language::new(
2470        LanguageConfig {
2471            name: "Rust".into(),
2472            matcher: LanguageMatcher {
2473                path_suffixes: vec!["rs".to_string()],
2474                ..Default::default()
2475            },
2476            ..Default::default()
2477        },
2478        Some(tree_sitter_rust::language()),
2479    )
2480    .with_indents_query(
2481        r#"
2482        (call_expression) @indent
2483        (field_expression) @indent
2484        (_ "(" ")" @end) @indent
2485        (_ "{" "}" @end) @indent
2486        "#,
2487    )
2488    .unwrap()
2489    .with_brackets_query(
2490        r#"
2491        ("{" @open "}" @close)
2492        "#,
2493    )
2494    .unwrap()
2495    .with_outline_query(
2496        r#"
2497        (struct_item
2498            "struct" @context
2499            name: (_) @name) @item
2500        (enum_item
2501            "enum" @context
2502            name: (_) @name) @item
2503        (enum_variant
2504            name: (_) @name) @item
2505        (field_declaration
2506            name: (_) @name) @item
2507        (impl_item
2508            "impl" @context
2509            trait: (_)? @name
2510            "for"? @context
2511            type: (_) @name) @item
2512        (function_item
2513            "fn" @context
2514            name: (_) @name) @item
2515        (mod_item
2516            "mod" @context
2517            name: (_) @name) @item
2518        "#,
2519    )
2520    .unwrap()
2521}
2522
2523fn json_lang() -> Language {
2524    Language::new(
2525        LanguageConfig {
2526            name: "Json".into(),
2527            matcher: LanguageMatcher {
2528                path_suffixes: vec!["js".to_string()],
2529                ..Default::default()
2530            },
2531            ..Default::default()
2532        },
2533        Some(tree_sitter_json::language()),
2534    )
2535}
2536
2537fn javascript_lang() -> Language {
2538    Language::new(
2539        LanguageConfig {
2540            name: "JavaScript".into(),
2541            ..Default::default()
2542        },
2543        Some(tree_sitter_typescript::language_tsx()),
2544    )
2545    .with_brackets_query(
2546        r#"
2547        ("{" @open "}" @close)
2548        ("(" @open ")" @close)
2549        "#,
2550    )
2551    .unwrap()
2552    .with_indents_query(
2553        r#"
2554        (object "}" @end) @indent
2555        "#,
2556    )
2557    .unwrap()
2558}
2559
2560fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2561    buffer.update(cx, |buffer, _| {
2562        let snapshot = buffer.snapshot();
2563        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2564        layers[0].node().to_sexp()
2565    })
2566}
2567
2568// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2569fn assert_bracket_pairs(
2570    selection_text: &'static str,
2571    bracket_pair_texts: Vec<&'static str>,
2572    language: Language,
2573    cx: &mut AppContext,
2574) {
2575    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2576    let buffer = cx.new_model(|cx| {
2577        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2578    });
2579    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2580
2581    let selection_range = selection_ranges[0].clone();
2582
2583    let bracket_pairs = bracket_pair_texts
2584        .into_iter()
2585        .map(|pair_text| {
2586            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2587            assert_eq!(bracket_text, expected_text);
2588            (ranges[0].clone(), ranges[1].clone())
2589        })
2590        .collect::<Vec<_>>();
2591
2592    assert_set_eq!(
2593        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2594        bracket_pairs
2595    );
2596}
2597
2598fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2599    let settings_store = SettingsStore::test(cx);
2600    cx.set_global(settings_store);
2601    crate::init(cx);
2602    cx.update_global::<SettingsStore, _>(|settings, cx| {
2603        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2604    });
2605}