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