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_language_at_with_hidden_languages(cx: &mut AppContext) {
2221    init_settings(cx, |_| {});
2222
2223    cx.new_model(|cx| {
2224        let text = r#"
2225            this is an *emphasized* word.
2226        "#
2227        .unindent();
2228
2229        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2230        language_registry.add(Arc::new(markdown_lang()));
2231        language_registry.add(Arc::new(markdown_inline_lang()));
2232
2233        let mut buffer = Buffer::local(text, cx);
2234        buffer.set_language_registry(language_registry.clone());
2235        buffer.set_language(
2236            language_registry
2237                .language_for_name("Markdown")
2238                .now_or_never()
2239                .unwrap()
2240                .ok(),
2241            cx,
2242        );
2243
2244        let snapshot = buffer.snapshot();
2245
2246        for point in [Point::new(0, 4), Point::new(0, 16)] {
2247            let config = snapshot.language_scope_at(point).unwrap();
2248            assert_eq!(config.language_name().as_ref(), "Markdown");
2249
2250            let language = snapshot.language_at(point).unwrap();
2251            assert_eq!(language.name().as_ref(), "Markdown");
2252        }
2253
2254        buffer
2255    });
2256}
2257
2258#[gpui::test]
2259fn test_serialization(cx: &mut gpui::AppContext) {
2260    let mut now = Instant::now();
2261
2262    let buffer1 = cx.new_model(|cx| {
2263        let mut buffer = Buffer::local("abc", cx);
2264        buffer.edit([(3..3, "D")], None, cx);
2265
2266        now += Duration::from_secs(1);
2267        buffer.start_transaction_at(now);
2268        buffer.edit([(4..4, "E")], None, cx);
2269        buffer.end_transaction_at(now, cx);
2270        assert_eq!(buffer.text(), "abcDE");
2271
2272        buffer.undo(cx);
2273        assert_eq!(buffer.text(), "abcD");
2274
2275        buffer.edit([(4..4, "F")], None, cx);
2276        assert_eq!(buffer.text(), "abcDF");
2277        buffer
2278    });
2279    assert_eq!(buffer1.read(cx).text(), "abcDF");
2280
2281    let state = buffer1.read(cx).to_proto(cx);
2282    let ops = cx
2283        .background_executor()
2284        .block(buffer1.read(cx).serialize_ops(None, cx));
2285    let buffer2 = cx.new_model(|cx| {
2286        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2287        buffer
2288            .apply_ops(
2289                ops.into_iter()
2290                    .map(|op| proto::deserialize_operation(op).unwrap()),
2291                cx,
2292            )
2293            .unwrap();
2294        buffer
2295    });
2296    assert_eq!(buffer2.read(cx).text(), "abcDF");
2297}
2298
2299#[gpui::test]
2300async fn test_find_matching_indent(cx: &mut TestAppContext) {
2301    cx.update(|cx| init_settings(cx, |_| {}));
2302
2303    async fn enclosing_indent(
2304        text: impl Into<String>,
2305        buffer_row: u32,
2306        cx: &mut TestAppContext,
2307    ) -> Option<(Range<u32>, LineIndent)> {
2308        let buffer = cx.new_model(|cx| Buffer::local(text, cx));
2309        let snapshot = cx.read(|cx| buffer.read(cx).snapshot());
2310        snapshot.enclosing_indent(buffer_row).await
2311    }
2312
2313    assert_eq!(
2314        enclosing_indent(
2315            "
2316        fn b() {
2317            if c {
2318                let d = 2;
2319            }
2320        }"
2321            .unindent(),
2322            1,
2323            cx,
2324        )
2325        .await,
2326        Some((
2327            1..2,
2328            LineIndent {
2329                tabs: 0,
2330                spaces: 4,
2331                line_blank: false,
2332            }
2333        ))
2334    );
2335
2336    assert_eq!(
2337        enclosing_indent(
2338            "
2339        fn b() {
2340            if c {
2341                let d = 2;
2342            }
2343        }"
2344            .unindent(),
2345            2,
2346            cx,
2347        )
2348        .await,
2349        Some((
2350            1..2,
2351            LineIndent {
2352                tabs: 0,
2353                spaces: 4,
2354                line_blank: false,
2355            }
2356        ))
2357    );
2358
2359    assert_eq!(
2360        enclosing_indent(
2361            "
2362        fn b() {
2363            if c {
2364                let d = 2;
2365
2366                let e = 5;
2367            }
2368        }"
2369            .unindent(),
2370            3,
2371            cx,
2372        )
2373        .await,
2374        Some((
2375            1..4,
2376            LineIndent {
2377                tabs: 0,
2378                spaces: 4,
2379                line_blank: false,
2380            }
2381        ))
2382    );
2383}
2384
2385#[gpui::test(iterations = 100)]
2386fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2387    let min_peers = env::var("MIN_PEERS")
2388        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2389        .unwrap_or(1);
2390    let max_peers = env::var("MAX_PEERS")
2391        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2392        .unwrap_or(5);
2393    let operations = env::var("OPERATIONS")
2394        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2395        .unwrap_or(10);
2396
2397    let base_text_len = rng.gen_range(0..10);
2398    let base_text = RandomCharIter::new(&mut rng)
2399        .take(base_text_len)
2400        .collect::<String>();
2401    let mut replica_ids = Vec::new();
2402    let mut buffers = Vec::new();
2403    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2404    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2405
2406    for i in 0..rng.gen_range(min_peers..=max_peers) {
2407        let buffer = cx.new_model(|cx| {
2408            let state = base_buffer.read(cx).to_proto(cx);
2409            let ops = cx
2410                .background_executor()
2411                .block(base_buffer.read(cx).serialize_ops(None, cx));
2412            let mut buffer =
2413                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2414            buffer
2415                .apply_ops(
2416                    ops.into_iter()
2417                        .map(|op| proto::deserialize_operation(op).unwrap()),
2418                    cx,
2419                )
2420                .unwrap();
2421            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2422            let network = network.clone();
2423            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2424                if let Event::Operation(op) = event {
2425                    network
2426                        .lock()
2427                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2428                }
2429            })
2430            .detach();
2431            buffer
2432        });
2433
2434        buffers.push(buffer);
2435        replica_ids.push(i as ReplicaId);
2436        network.lock().add_peer(i as ReplicaId);
2437        log::info!("Adding initial peer with replica id {}", i);
2438    }
2439
2440    log::info!("initial text: {:?}", base_text);
2441
2442    let mut now = Instant::now();
2443    let mut mutation_count = operations;
2444    let mut next_diagnostic_id = 0;
2445    let mut active_selections = BTreeMap::default();
2446    loop {
2447        let replica_index = rng.gen_range(0..replica_ids.len());
2448        let replica_id = replica_ids[replica_index];
2449        let buffer = &mut buffers[replica_index];
2450        let mut new_buffer = None;
2451        match rng.gen_range(0..100) {
2452            0..=29 if mutation_count != 0 => {
2453                buffer.update(cx, |buffer, cx| {
2454                    buffer.start_transaction_at(now);
2455                    buffer.randomly_edit(&mut rng, 5, cx);
2456                    buffer.end_transaction_at(now, cx);
2457                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2458                });
2459                mutation_count -= 1;
2460            }
2461            30..=39 if mutation_count != 0 => {
2462                buffer.update(cx, |buffer, cx| {
2463                    if rng.gen_bool(0.2) {
2464                        log::info!("peer {} clearing active selections", replica_id);
2465                        active_selections.remove(&replica_id);
2466                        buffer.remove_active_selections(cx);
2467                    } else {
2468                        let mut selections = Vec::new();
2469                        for id in 0..rng.gen_range(1..=5) {
2470                            let range = buffer.random_byte_range(0, &mut rng);
2471                            selections.push(Selection {
2472                                id,
2473                                start: buffer.anchor_before(range.start),
2474                                end: buffer.anchor_before(range.end),
2475                                reversed: false,
2476                                goal: SelectionGoal::None,
2477                            });
2478                        }
2479                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2480                        log::info!(
2481                            "peer {} setting active selections: {:?}",
2482                            replica_id,
2483                            selections
2484                        );
2485                        active_selections.insert(replica_id, selections.clone());
2486                        buffer.set_active_selections(selections, false, Default::default(), cx);
2487                    }
2488                });
2489                mutation_count -= 1;
2490            }
2491            40..=49 if mutation_count != 0 && replica_id == 0 => {
2492                let entry_count = rng.gen_range(1..=5);
2493                buffer.update(cx, |buffer, cx| {
2494                    let diagnostics = DiagnosticSet::new(
2495                        (0..entry_count).map(|_| {
2496                            let range = buffer.random_byte_range(0, &mut rng);
2497                            let range = range.to_point_utf16(buffer);
2498                            let range = range.start..range.end;
2499                            DiagnosticEntry {
2500                                range,
2501                                diagnostic: Diagnostic {
2502                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2503                                    ..Default::default()
2504                                },
2505                            }
2506                        }),
2507                        buffer,
2508                    );
2509                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2510                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2511                });
2512                mutation_count -= 1;
2513            }
2514            50..=59 if replica_ids.len() < max_peers => {
2515                let old_buffer_state = buffer.read(cx).to_proto(cx);
2516                let old_buffer_ops = cx
2517                    .background_executor()
2518                    .block(buffer.read(cx).serialize_ops(None, cx));
2519                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2520                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2521                    .choose(&mut rng)
2522                    .unwrap();
2523                log::info!(
2524                    "Adding new replica {} (replicating from {})",
2525                    new_replica_id,
2526                    replica_id
2527                );
2528                new_buffer = Some(cx.new_model(|cx| {
2529                    let mut new_buffer = Buffer::from_proto(
2530                        new_replica_id,
2531                        Capability::ReadWrite,
2532                        old_buffer_state,
2533                        None,
2534                    )
2535                    .unwrap();
2536                    new_buffer
2537                        .apply_ops(
2538                            old_buffer_ops
2539                                .into_iter()
2540                                .map(|op| deserialize_operation(op).unwrap()),
2541                            cx,
2542                        )
2543                        .unwrap();
2544                    log::info!(
2545                        "New replica {} text: {:?}",
2546                        new_buffer.replica_id(),
2547                        new_buffer.text()
2548                    );
2549                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2550                    let network = network.clone();
2551                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2552                        if let Event::Operation(op) = event {
2553                            network.lock().broadcast(
2554                                buffer.replica_id(),
2555                                vec![proto::serialize_operation(op)],
2556                            );
2557                        }
2558                    })
2559                    .detach();
2560                    new_buffer
2561                }));
2562                network.lock().replicate(replica_id, new_replica_id);
2563
2564                if new_replica_id as usize == replica_ids.len() {
2565                    replica_ids.push(new_replica_id);
2566                } else {
2567                    let new_buffer = new_buffer.take().unwrap();
2568                    while network.lock().has_unreceived(new_replica_id) {
2569                        let ops = network
2570                            .lock()
2571                            .receive(new_replica_id)
2572                            .into_iter()
2573                            .map(|op| proto::deserialize_operation(op).unwrap());
2574                        if ops.len() > 0 {
2575                            log::info!(
2576                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2577                                new_replica_id,
2578                                buffer.read(cx).version(),
2579                                ops.len(),
2580                                ops
2581                            );
2582                            new_buffer.update(cx, |new_buffer, cx| {
2583                                new_buffer.apply_ops(ops, cx).unwrap();
2584                            });
2585                        }
2586                    }
2587                    buffers[new_replica_id as usize] = new_buffer;
2588                }
2589            }
2590            60..=69 if mutation_count != 0 => {
2591                buffer.update(cx, |buffer, cx| {
2592                    buffer.randomly_undo_redo(&mut rng, cx);
2593                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2594                });
2595                mutation_count -= 1;
2596            }
2597            _ if network.lock().has_unreceived(replica_id) => {
2598                let ops = network
2599                    .lock()
2600                    .receive(replica_id)
2601                    .into_iter()
2602                    .map(|op| proto::deserialize_operation(op).unwrap());
2603                if ops.len() > 0 {
2604                    log::info!(
2605                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2606                        replica_id,
2607                        buffer.read(cx).version(),
2608                        ops.len(),
2609                        ops
2610                    );
2611                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2612                }
2613            }
2614            _ => {}
2615        }
2616
2617        now += Duration::from_millis(rng.gen_range(0..=200));
2618        buffers.extend(new_buffer);
2619
2620        for buffer in &buffers {
2621            buffer.read(cx).check_invariants();
2622        }
2623
2624        if mutation_count == 0 && network.lock().is_idle() {
2625            break;
2626        }
2627    }
2628
2629    let first_buffer = buffers[0].read(cx).snapshot();
2630    for buffer in &buffers[1..] {
2631        let buffer = buffer.read(cx).snapshot();
2632        assert_eq!(
2633            buffer.version(),
2634            first_buffer.version(),
2635            "Replica {} version != Replica 0 version",
2636            buffer.replica_id()
2637        );
2638        assert_eq!(
2639            buffer.text(),
2640            first_buffer.text(),
2641            "Replica {} text != Replica 0 text",
2642            buffer.replica_id()
2643        );
2644        assert_eq!(
2645            buffer
2646                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2647                .collect::<Vec<_>>(),
2648            first_buffer
2649                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2650                .collect::<Vec<_>>(),
2651            "Replica {} diagnostics != Replica 0 diagnostics",
2652            buffer.replica_id()
2653        );
2654    }
2655
2656    for buffer in &buffers {
2657        let buffer = buffer.read(cx).snapshot();
2658        let actual_remote_selections = buffer
2659            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
2660            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2661            .collect::<Vec<_>>();
2662        let expected_remote_selections = active_selections
2663            .iter()
2664            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2665            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2666            .collect::<Vec<_>>();
2667        assert_eq!(
2668            actual_remote_selections,
2669            expected_remote_selections,
2670            "Replica {} remote selections != expected selections",
2671            buffer.replica_id()
2672        );
2673    }
2674}
2675
2676#[test]
2677fn test_contiguous_ranges() {
2678    assert_eq!(
2679        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2680        &[1..4, 5..7, 9..13]
2681    );
2682
2683    // Respects the `max_len` parameter
2684    assert_eq!(
2685        contiguous_ranges(
2686            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2687            3
2688        )
2689        .collect::<Vec<_>>(),
2690        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2691    );
2692}
2693
2694#[gpui::test(iterations = 500)]
2695fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2696    // Generate a random multi-line string containing
2697    // some lines with trailing whitespace.
2698    let mut text = String::new();
2699    for _ in 0..rng.gen_range(0..16) {
2700        for _ in 0..rng.gen_range(0..36) {
2701            text.push(match rng.gen_range(0..10) {
2702                0..=1 => ' ',
2703                3 => '\t',
2704                _ => rng.gen_range('a'..='z'),
2705            });
2706        }
2707        text.push('\n');
2708    }
2709
2710    match rng.gen_range(0..10) {
2711        // sometimes remove the last newline
2712        0..=1 => drop(text.pop()), //
2713
2714        // sometimes add extra newlines
2715        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2716        _ => {}
2717    }
2718
2719    let rope = Rope::from(text.as_str());
2720    let actual_ranges = trailing_whitespace_ranges(&rope);
2721    let expected_ranges = TRAILING_WHITESPACE_REGEX
2722        .find_iter(&text)
2723        .map(|m| m.range())
2724        .collect::<Vec<_>>();
2725    assert_eq!(
2726        actual_ranges,
2727        expected_ranges,
2728        "wrong ranges for text lines:\n{:?}",
2729        text.split('\n').collect::<Vec<_>>()
2730    );
2731}
2732
2733fn ruby_lang() -> Language {
2734    Language::new(
2735        LanguageConfig {
2736            name: "Ruby".into(),
2737            matcher: LanguageMatcher {
2738                path_suffixes: vec!["rb".to_string()],
2739                ..Default::default()
2740            },
2741            line_comments: vec!["# ".into()],
2742            ..Default::default()
2743        },
2744        Some(tree_sitter_ruby::language()),
2745    )
2746    .with_indents_query(
2747        r#"
2748            (class "end" @end) @indent
2749            (method "end" @end) @indent
2750            (rescue) @outdent
2751            (then) @indent
2752        "#,
2753    )
2754    .unwrap()
2755}
2756
2757fn html_lang() -> Language {
2758    Language::new(
2759        LanguageConfig {
2760            name: "HTML".into(),
2761            block_comment: Some(("<!--".into(), "-->".into())),
2762            ..Default::default()
2763        },
2764        Some(tree_sitter_html::language()),
2765    )
2766    .with_indents_query(
2767        "
2768        (element
2769          (start_tag) @start
2770          (end_tag)? @end) @indent
2771        ",
2772    )
2773    .unwrap()
2774    .with_injection_query(
2775        r#"
2776        (script_element
2777            (raw_text) @content
2778            (#set! "language" "javascript"))
2779        "#,
2780    )
2781    .unwrap()
2782}
2783
2784fn erb_lang() -> Language {
2785    Language::new(
2786        LanguageConfig {
2787            name: "ERB".into(),
2788            matcher: LanguageMatcher {
2789                path_suffixes: vec!["erb".to_string()],
2790                ..Default::default()
2791            },
2792            block_comment: Some(("<%#".into(), "%>".into())),
2793            ..Default::default()
2794        },
2795        Some(tree_sitter_embedded_template::language()),
2796    )
2797    .with_injection_query(
2798        r#"
2799            (
2800                (code) @content
2801                (#set! "language" "ruby")
2802                (#set! "combined")
2803            )
2804
2805            (
2806                (content) @content
2807                (#set! "language" "html")
2808                (#set! "combined")
2809            )
2810        "#,
2811    )
2812    .unwrap()
2813}
2814
2815fn rust_lang() -> Language {
2816    Language::new(
2817        LanguageConfig {
2818            name: "Rust".into(),
2819            matcher: LanguageMatcher {
2820                path_suffixes: vec!["rs".to_string()],
2821                ..Default::default()
2822            },
2823            ..Default::default()
2824        },
2825        Some(tree_sitter_rust::language()),
2826    )
2827    .with_indents_query(
2828        r#"
2829        (call_expression) @indent
2830        (field_expression) @indent
2831        (_ "(" ")" @end) @indent
2832        (_ "{" "}" @end) @indent
2833        "#,
2834    )
2835    .unwrap()
2836    .with_brackets_query(
2837        r#"
2838        ("{" @open "}" @close)
2839        "#,
2840    )
2841    .unwrap()
2842    .with_outline_query(
2843        r#"
2844        (line_comment) @annotation
2845
2846        (struct_item
2847            "struct" @context
2848            name: (_) @name) @item
2849        (enum_item
2850            "enum" @context
2851            name: (_) @name) @item
2852        (enum_variant
2853            name: (_) @name) @item
2854        (field_declaration
2855            name: (_) @name) @item
2856        (impl_item
2857            "impl" @context
2858            trait: (_)? @name
2859            "for"? @context
2860            type: (_) @name
2861            body: (_ "{" (_)* "}")) @item
2862        (function_item
2863            "fn" @context
2864            name: (_) @name) @item
2865        (mod_item
2866            "mod" @context
2867            name: (_) @name) @item
2868        "#,
2869    )
2870    .unwrap()
2871}
2872
2873fn json_lang() -> Language {
2874    Language::new(
2875        LanguageConfig {
2876            name: "Json".into(),
2877            matcher: LanguageMatcher {
2878                path_suffixes: vec!["js".to_string()],
2879                ..Default::default()
2880            },
2881            ..Default::default()
2882        },
2883        Some(tree_sitter_json::language()),
2884    )
2885}
2886
2887fn javascript_lang() -> Language {
2888    Language::new(
2889        LanguageConfig {
2890            name: "JavaScript".into(),
2891            ..Default::default()
2892        },
2893        Some(tree_sitter_typescript::language_tsx()),
2894    )
2895    .with_brackets_query(
2896        r#"
2897        ("{" @open "}" @close)
2898        ("(" @open ")" @close)
2899        "#,
2900    )
2901    .unwrap()
2902    .with_indents_query(
2903        r#"
2904        (object "}" @end) @indent
2905        "#,
2906    )
2907    .unwrap()
2908}
2909
2910pub fn markdown_lang() -> Language {
2911    Language::new(
2912        LanguageConfig {
2913            name: "Markdown".into(),
2914            matcher: LanguageMatcher {
2915                path_suffixes: vec!["md".into()],
2916                ..Default::default()
2917            },
2918            ..Default::default()
2919        },
2920        Some(tree_sitter_md::language()),
2921    )
2922    .with_injection_query(
2923        r#"
2924            (fenced_code_block
2925                (info_string
2926                    (language) @language)
2927                (code_fence_content) @content)
2928
2929            ((inline) @content
2930                (#set! "language" "markdown-inline"))
2931        "#,
2932    )
2933    .unwrap()
2934}
2935
2936pub fn markdown_inline_lang() -> Language {
2937    Language::new(
2938        LanguageConfig {
2939            name: "Markdown-Inline".into(),
2940            hidden: true,
2941            ..LanguageConfig::default()
2942        },
2943        Some(tree_sitter_md::inline_language()),
2944    )
2945    .with_highlights_query("(emphasis) @emphasis")
2946    .unwrap()
2947}
2948
2949fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2950    buffer.update(cx, |buffer, _| {
2951        let snapshot = buffer.snapshot();
2952        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2953        layers[0].node().to_sexp()
2954    })
2955}
2956
2957// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2958fn assert_bracket_pairs(
2959    selection_text: &'static str,
2960    bracket_pair_texts: Vec<&'static str>,
2961    language: Language,
2962    cx: &mut AppContext,
2963) {
2964    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2965    let buffer = cx.new_model(|cx| {
2966        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
2967    });
2968    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2969
2970    let selection_range = selection_ranges[0].clone();
2971
2972    let bracket_pairs = bracket_pair_texts
2973        .into_iter()
2974        .map(|pair_text| {
2975            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2976            assert_eq!(bracket_text, expected_text);
2977            (ranges[0].clone(), ranges[1].clone())
2978        })
2979        .collect::<Vec<_>>();
2980
2981    assert_set_eq!(
2982        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2983        bracket_pairs
2984    );
2985}
2986
2987fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2988    let settings_store = SettingsStore::test(cx);
2989    cx.set_global(settings_store);
2990    crate::init(cx);
2991    cx.update_global::<SettingsStore, _>(|settings, cx| {
2992        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2993    });
2994}