buffer_tests.rs

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