buffer_tests.rs

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