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