buffer_tests.rs

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