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