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    branch_buffer.update(cx, |branch_buffer, cx| {
2475        branch_buffer.merge_into_base(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
2487#[gpui::test]
2488fn test_merge_into_base(cx: &mut AppContext) {
2489    init_settings(cx, |_| {});
2490    let base = cx.new_model(|cx| Buffer::local("abcdefghijk", cx));
2491    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2492    branch.update(cx, |branch, cx| {
2493        branch.edit([(0..3, "ABC"), (7..9, "HI")], None, cx);
2494        branch.merge_into_base(Some(5..8), cx);
2495    });
2496    assert_eq!(base.read(cx).text(), "abcdefgHIjk");
2497}
2498
2499fn start_recalculating_diff(buffer: &Model<Buffer>, cx: &mut TestAppContext) {
2500    buffer
2501        .update(cx, |buffer, cx| buffer.recalculate_diff(cx).unwrap())
2502        .detach();
2503}
2504
2505#[track_caller]
2506fn assert_diff_hunks(
2507    buffer: &Model<Buffer>,
2508    cx: &mut TestAppContext,
2509    expected_hunks: &[(Range<u32>, &str, &str)],
2510) {
2511    let (snapshot, diff_base) = buffer.read_with(cx, |buffer, _| {
2512        (buffer.snapshot(), buffer.diff_base().unwrap().to_string())
2513    });
2514    assert_hunks(
2515        snapshot.git_diff_hunks_intersecting_range(Anchor::MIN..Anchor::MAX),
2516        &snapshot,
2517        &diff_base,
2518        expected_hunks,
2519    );
2520}
2521
2522#[gpui::test(iterations = 100)]
2523fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2524    let min_peers = env::var("MIN_PEERS")
2525        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2526        .unwrap_or(1);
2527    let max_peers = env::var("MAX_PEERS")
2528        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2529        .unwrap_or(5);
2530    let operations = env::var("OPERATIONS")
2531        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2532        .unwrap_or(10);
2533
2534    let base_text_len = rng.gen_range(0..10);
2535    let base_text = RandomCharIter::new(&mut rng)
2536        .take(base_text_len)
2537        .collect::<String>();
2538    let mut replica_ids = Vec::new();
2539    let mut buffers = Vec::new();
2540    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2541    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2542
2543    for i in 0..rng.gen_range(min_peers..=max_peers) {
2544        let buffer = cx.new_model(|cx| {
2545            let state = base_buffer.read(cx).to_proto(cx);
2546            let ops = cx
2547                .background_executor()
2548                .block(base_buffer.read(cx).serialize_ops(None, cx));
2549            let mut buffer =
2550                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2551            buffer.apply_ops(
2552                ops.into_iter()
2553                    .map(|op| proto::deserialize_operation(op).unwrap()),
2554                cx,
2555            );
2556            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2557            let network = network.clone();
2558            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2559                if let BufferEvent::Operation {
2560                    operation,
2561                    is_local: true,
2562                } = event
2563                {
2564                    network.lock().broadcast(
2565                        buffer.replica_id(),
2566                        vec![proto::serialize_operation(operation)],
2567                    );
2568                }
2569            })
2570            .detach();
2571            buffer
2572        });
2573
2574        buffers.push(buffer);
2575        replica_ids.push(i as ReplicaId);
2576        network.lock().add_peer(i as ReplicaId);
2577        log::info!("Adding initial peer with replica id {}", i);
2578    }
2579
2580    log::info!("initial text: {:?}", base_text);
2581
2582    let mut now = Instant::now();
2583    let mut mutation_count = operations;
2584    let mut next_diagnostic_id = 0;
2585    let mut active_selections = BTreeMap::default();
2586    loop {
2587        let replica_index = rng.gen_range(0..replica_ids.len());
2588        let replica_id = replica_ids[replica_index];
2589        let buffer = &mut buffers[replica_index];
2590        let mut new_buffer = None;
2591        match rng.gen_range(0..100) {
2592            0..=29 if mutation_count != 0 => {
2593                buffer.update(cx, |buffer, cx| {
2594                    buffer.start_transaction_at(now);
2595                    buffer.randomly_edit(&mut rng, 5, cx);
2596                    buffer.end_transaction_at(now, cx);
2597                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2598                });
2599                mutation_count -= 1;
2600            }
2601            30..=39 if mutation_count != 0 => {
2602                buffer.update(cx, |buffer, cx| {
2603                    if rng.gen_bool(0.2) {
2604                        log::info!("peer {} clearing active selections", replica_id);
2605                        active_selections.remove(&replica_id);
2606                        buffer.remove_active_selections(cx);
2607                    } else {
2608                        let mut selections = Vec::new();
2609                        for id in 0..rng.gen_range(1..=5) {
2610                            let range = buffer.random_byte_range(0, &mut rng);
2611                            selections.push(Selection {
2612                                id,
2613                                start: buffer.anchor_before(range.start),
2614                                end: buffer.anchor_before(range.end),
2615                                reversed: false,
2616                                goal: SelectionGoal::None,
2617                            });
2618                        }
2619                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2620                        log::info!(
2621                            "peer {} setting active selections: {:?}",
2622                            replica_id,
2623                            selections
2624                        );
2625                        active_selections.insert(replica_id, selections.clone());
2626                        buffer.set_active_selections(selections, false, Default::default(), cx);
2627                    }
2628                });
2629                mutation_count -= 1;
2630            }
2631            40..=49 if mutation_count != 0 && replica_id == 0 => {
2632                let entry_count = rng.gen_range(1..=5);
2633                buffer.update(cx, |buffer, cx| {
2634                    let diagnostics = DiagnosticSet::new(
2635                        (0..entry_count).map(|_| {
2636                            let range = buffer.random_byte_range(0, &mut rng);
2637                            let range = range.to_point_utf16(buffer);
2638                            let range = range.start..range.end;
2639                            DiagnosticEntry {
2640                                range,
2641                                diagnostic: Diagnostic {
2642                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2643                                    ..Default::default()
2644                                },
2645                            }
2646                        }),
2647                        buffer,
2648                    );
2649                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2650                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2651                });
2652                mutation_count -= 1;
2653            }
2654            50..=59 if replica_ids.len() < max_peers => {
2655                let old_buffer_state = buffer.read(cx).to_proto(cx);
2656                let old_buffer_ops = cx
2657                    .background_executor()
2658                    .block(buffer.read(cx).serialize_ops(None, cx));
2659                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2660                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2661                    .choose(&mut rng)
2662                    .unwrap();
2663                log::info!(
2664                    "Adding new replica {} (replicating from {})",
2665                    new_replica_id,
2666                    replica_id
2667                );
2668                new_buffer = Some(cx.new_model(|cx| {
2669                    let mut new_buffer = Buffer::from_proto(
2670                        new_replica_id,
2671                        Capability::ReadWrite,
2672                        old_buffer_state,
2673                        None,
2674                    )
2675                    .unwrap();
2676                    new_buffer.apply_ops(
2677                        old_buffer_ops
2678                            .into_iter()
2679                            .map(|op| deserialize_operation(op).unwrap()),
2680                        cx,
2681                    );
2682                    log::info!(
2683                        "New replica {} text: {:?}",
2684                        new_buffer.replica_id(),
2685                        new_buffer.text()
2686                    );
2687                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2688                    let network = network.clone();
2689                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2690                        if let BufferEvent::Operation {
2691                            operation,
2692                            is_local: true,
2693                        } = event
2694                        {
2695                            network.lock().broadcast(
2696                                buffer.replica_id(),
2697                                vec![proto::serialize_operation(operation)],
2698                            );
2699                        }
2700                    })
2701                    .detach();
2702                    new_buffer
2703                }));
2704                network.lock().replicate(replica_id, new_replica_id);
2705
2706                if new_replica_id as usize == replica_ids.len() {
2707                    replica_ids.push(new_replica_id);
2708                } else {
2709                    let new_buffer = new_buffer.take().unwrap();
2710                    while network.lock().has_unreceived(new_replica_id) {
2711                        let ops = network
2712                            .lock()
2713                            .receive(new_replica_id)
2714                            .into_iter()
2715                            .map(|op| proto::deserialize_operation(op).unwrap());
2716                        if ops.len() > 0 {
2717                            log::info!(
2718                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2719                                new_replica_id,
2720                                buffer.read(cx).version(),
2721                                ops.len(),
2722                                ops
2723                            );
2724                            new_buffer.update(cx, |new_buffer, cx| {
2725                                new_buffer.apply_ops(ops, cx);
2726                            });
2727                        }
2728                    }
2729                    buffers[new_replica_id as usize] = new_buffer;
2730                }
2731            }
2732            60..=69 if mutation_count != 0 => {
2733                buffer.update(cx, |buffer, cx| {
2734                    buffer.randomly_undo_redo(&mut rng, cx);
2735                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2736                });
2737                mutation_count -= 1;
2738            }
2739            _ if network.lock().has_unreceived(replica_id) => {
2740                let ops = network
2741                    .lock()
2742                    .receive(replica_id)
2743                    .into_iter()
2744                    .map(|op| proto::deserialize_operation(op).unwrap());
2745                if ops.len() > 0 {
2746                    log::info!(
2747                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2748                        replica_id,
2749                        buffer.read(cx).version(),
2750                        ops.len(),
2751                        ops
2752                    );
2753                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx));
2754                }
2755            }
2756            _ => {}
2757        }
2758
2759        now += Duration::from_millis(rng.gen_range(0..=200));
2760        buffers.extend(new_buffer);
2761
2762        for buffer in &buffers {
2763            buffer.read(cx).check_invariants();
2764        }
2765
2766        if mutation_count == 0 && network.lock().is_idle() {
2767            break;
2768        }
2769    }
2770
2771    let first_buffer = buffers[0].read(cx).snapshot();
2772    for buffer in &buffers[1..] {
2773        let buffer = buffer.read(cx).snapshot();
2774        assert_eq!(
2775            buffer.version(),
2776            first_buffer.version(),
2777            "Replica {} version != Replica 0 version",
2778            buffer.replica_id()
2779        );
2780        assert_eq!(
2781            buffer.text(),
2782            first_buffer.text(),
2783            "Replica {} text != Replica 0 text",
2784            buffer.replica_id()
2785        );
2786        assert_eq!(
2787            buffer
2788                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2789                .collect::<Vec<_>>(),
2790            first_buffer
2791                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2792                .collect::<Vec<_>>(),
2793            "Replica {} diagnostics != Replica 0 diagnostics",
2794            buffer.replica_id()
2795        );
2796    }
2797
2798    for buffer in &buffers {
2799        let buffer = buffer.read(cx).snapshot();
2800        let actual_remote_selections = buffer
2801            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
2802            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2803            .collect::<Vec<_>>();
2804        let expected_remote_selections = active_selections
2805            .iter()
2806            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2807            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2808            .collect::<Vec<_>>();
2809        assert_eq!(
2810            actual_remote_selections,
2811            expected_remote_selections,
2812            "Replica {} remote selections != expected selections",
2813            buffer.replica_id()
2814        );
2815    }
2816}
2817
2818#[test]
2819fn test_contiguous_ranges() {
2820    assert_eq!(
2821        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2822        &[1..4, 5..7, 9..13]
2823    );
2824
2825    // Respects the `max_len` parameter
2826    assert_eq!(
2827        contiguous_ranges(
2828            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2829            3
2830        )
2831        .collect::<Vec<_>>(),
2832        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2833    );
2834}
2835
2836#[gpui::test(iterations = 500)]
2837fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2838    // Generate a random multi-line string containing
2839    // some lines with trailing whitespace.
2840    let mut text = String::new();
2841    for _ in 0..rng.gen_range(0..16) {
2842        for _ in 0..rng.gen_range(0..36) {
2843            text.push(match rng.gen_range(0..10) {
2844                0..=1 => ' ',
2845                3 => '\t',
2846                _ => rng.gen_range('a'..='z'),
2847            });
2848        }
2849        text.push('\n');
2850    }
2851
2852    match rng.gen_range(0..10) {
2853        // sometimes remove the last newline
2854        0..=1 => drop(text.pop()), //
2855
2856        // sometimes add extra newlines
2857        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2858        _ => {}
2859    }
2860
2861    let rope = Rope::from(text.as_str());
2862    let actual_ranges = trailing_whitespace_ranges(&rope);
2863    let expected_ranges = TRAILING_WHITESPACE_REGEX
2864        .find_iter(&text)
2865        .map(|m| m.range())
2866        .collect::<Vec<_>>();
2867    assert_eq!(
2868        actual_ranges,
2869        expected_ranges,
2870        "wrong ranges for text lines:\n{:?}",
2871        text.split('\n').collect::<Vec<_>>()
2872    );
2873}
2874
2875fn ruby_lang() -> Language {
2876    Language::new(
2877        LanguageConfig {
2878            name: "Ruby".into(),
2879            matcher: LanguageMatcher {
2880                path_suffixes: vec!["rb".to_string()],
2881                ..Default::default()
2882            },
2883            line_comments: vec!["# ".into()],
2884            ..Default::default()
2885        },
2886        Some(tree_sitter_ruby::LANGUAGE.into()),
2887    )
2888    .with_indents_query(
2889        r#"
2890            (class "end" @end) @indent
2891            (method "end" @end) @indent
2892            (rescue) @outdent
2893            (then) @indent
2894        "#,
2895    )
2896    .unwrap()
2897}
2898
2899fn html_lang() -> Language {
2900    Language::new(
2901        LanguageConfig {
2902            name: LanguageName::new("HTML"),
2903            block_comment: Some(("<!--".into(), "-->".into())),
2904            ..Default::default()
2905        },
2906        Some(tree_sitter_html::language()),
2907    )
2908    .with_indents_query(
2909        "
2910        (element
2911          (start_tag) @start
2912          (end_tag)? @end) @indent
2913        ",
2914    )
2915    .unwrap()
2916    .with_injection_query(
2917        r#"
2918        (script_element
2919            (raw_text) @content
2920            (#set! "language" "javascript"))
2921        "#,
2922    )
2923    .unwrap()
2924}
2925
2926fn erb_lang() -> Language {
2927    Language::new(
2928        LanguageConfig {
2929            name: "ERB".into(),
2930            matcher: LanguageMatcher {
2931                path_suffixes: vec!["erb".to_string()],
2932                ..Default::default()
2933            },
2934            block_comment: Some(("<%#".into(), "%>".into())),
2935            ..Default::default()
2936        },
2937        Some(tree_sitter_embedded_template::LANGUAGE.into()),
2938    )
2939    .with_injection_query(
2940        r#"
2941            (
2942                (code) @content
2943                (#set! "language" "ruby")
2944                (#set! "combined")
2945            )
2946
2947            (
2948                (content) @content
2949                (#set! "language" "html")
2950                (#set! "combined")
2951            )
2952        "#,
2953    )
2954    .unwrap()
2955}
2956
2957fn rust_lang() -> Language {
2958    Language::new(
2959        LanguageConfig {
2960            name: "Rust".into(),
2961            matcher: LanguageMatcher {
2962                path_suffixes: vec!["rs".to_string()],
2963                ..Default::default()
2964            },
2965            ..Default::default()
2966        },
2967        Some(tree_sitter_rust::LANGUAGE.into()),
2968    )
2969    .with_indents_query(
2970        r#"
2971        (call_expression) @indent
2972        (field_expression) @indent
2973        (_ "(" ")" @end) @indent
2974        (_ "{" "}" @end) @indent
2975        "#,
2976    )
2977    .unwrap()
2978    .with_brackets_query(
2979        r#"
2980        ("{" @open "}" @close)
2981        "#,
2982    )
2983    .unwrap()
2984    .with_outline_query(
2985        r#"
2986        (line_comment) @annotation
2987
2988        (struct_item
2989            "struct" @context
2990            name: (_) @name) @item
2991        (enum_item
2992            "enum" @context
2993            name: (_) @name) @item
2994        (enum_variant
2995            name: (_) @name) @item
2996        (field_declaration
2997            name: (_) @name) @item
2998        (impl_item
2999            "impl" @context
3000            trait: (_)? @name
3001            "for"? @context
3002            type: (_) @name
3003            body: (_ "{" (_)* "}")) @item
3004        (function_item
3005            "fn" @context
3006            name: (_) @name) @item
3007        (mod_item
3008            "mod" @context
3009            name: (_) @name) @item
3010        "#,
3011    )
3012    .unwrap()
3013}
3014
3015fn json_lang() -> Language {
3016    Language::new(
3017        LanguageConfig {
3018            name: "Json".into(),
3019            matcher: LanguageMatcher {
3020                path_suffixes: vec!["js".to_string()],
3021                ..Default::default()
3022            },
3023            ..Default::default()
3024        },
3025        Some(tree_sitter_json::LANGUAGE.into()),
3026    )
3027}
3028
3029fn javascript_lang() -> Language {
3030    Language::new(
3031        LanguageConfig {
3032            name: "JavaScript".into(),
3033            ..Default::default()
3034        },
3035        Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
3036    )
3037    .with_brackets_query(
3038        r#"
3039        ("{" @open "}" @close)
3040        ("(" @open ")" @close)
3041        "#,
3042    )
3043    .unwrap()
3044    .with_indents_query(
3045        r#"
3046        (object "}" @end) @indent
3047        "#,
3048    )
3049    .unwrap()
3050}
3051
3052pub fn markdown_lang() -> Language {
3053    Language::new(
3054        LanguageConfig {
3055            name: "Markdown".into(),
3056            matcher: LanguageMatcher {
3057                path_suffixes: vec!["md".into()],
3058                ..Default::default()
3059            },
3060            ..Default::default()
3061        },
3062        Some(tree_sitter_md::LANGUAGE.into()),
3063    )
3064    .with_injection_query(
3065        r#"
3066            (fenced_code_block
3067                (info_string
3068                    (language) @language)
3069                (code_fence_content) @content)
3070
3071            ((inline) @content
3072                (#set! "language" "markdown-inline"))
3073        "#,
3074    )
3075    .unwrap()
3076}
3077
3078pub fn markdown_inline_lang() -> Language {
3079    Language::new(
3080        LanguageConfig {
3081            name: "Markdown-Inline".into(),
3082            hidden: true,
3083            ..LanguageConfig::default()
3084        },
3085        Some(tree_sitter_md::INLINE_LANGUAGE.into()),
3086    )
3087    .with_highlights_query("(emphasis) @emphasis")
3088    .unwrap()
3089}
3090
3091fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
3092    buffer.update(cx, |buffer, _| {
3093        let snapshot = buffer.snapshot();
3094        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
3095        layers[0].node().to_sexp()
3096    })
3097}
3098
3099// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
3100fn assert_bracket_pairs(
3101    selection_text: &'static str,
3102    bracket_pair_texts: Vec<&'static str>,
3103    language: Language,
3104    cx: &mut AppContext,
3105) {
3106    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
3107    let buffer = cx.new_model(|cx| {
3108        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
3109    });
3110    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
3111
3112    let selection_range = selection_ranges[0].clone();
3113
3114    let bracket_pairs = bracket_pair_texts
3115        .into_iter()
3116        .map(|pair_text| {
3117            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
3118            assert_eq!(bracket_text, expected_text);
3119            (ranges[0].clone(), ranges[1].clone())
3120        })
3121        .collect::<Vec<_>>();
3122
3123    assert_set_eq!(
3124        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
3125        bracket_pairs
3126    );
3127}
3128
3129fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
3130    let settings_store = SettingsStore::test(cx);
3131    cx.set_global(settings_store);
3132    crate::init(cx);
3133    cx.update_global::<SettingsStore, _>(|settings, cx| {
3134        settings.update_user_settings::<AllLanguageSettings>(cx, f);
3135    });
3136}