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