buffer_tests.rs

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