buffer_tests.rs

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