buffer_tests.rs

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