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};
  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]
2479fn test_branch_and_merge(cx: &mut TestAppContext) {
2480    cx.update(|cx| init_settings(cx, |_| {}));
2481
2482    let base = cx.new_model(|cx| Buffer::local("one\ntwo\nthree\n", cx));
2483
2484    // Create a remote replica of the base buffer.
2485    let base_replica = cx.new_model(|cx| {
2486        Buffer::from_proto(1, Capability::ReadWrite, base.read(cx).to_proto(cx), None).unwrap()
2487    });
2488    base.update(cx, |_buffer, cx| {
2489        cx.subscribe(&base_replica, |this, _, event, cx| {
2490            if let BufferEvent::Operation {
2491                operation,
2492                is_local: true,
2493            } = event
2494            {
2495                this.apply_ops([operation.clone()], cx);
2496            }
2497        })
2498        .detach();
2499    });
2500
2501    // Create a branch, which initially has the same state as the base buffer.
2502    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2503    branch.read_with(cx, |buffer, _| {
2504        assert_eq!(buffer.text(), "one\ntwo\nthree\n");
2505    });
2506
2507    // Edits to the branch are not applied to the base.
2508    branch.update(cx, |buffer, cx| {
2509        buffer.edit(
2510            [
2511                (Point::new(1, 0)..Point::new(1, 0), "1.5\n"),
2512                (Point::new(2, 0)..Point::new(2, 5), "THREE"),
2513            ],
2514            None,
2515            cx,
2516        )
2517    });
2518    branch.read_with(cx, |buffer, cx| {
2519        assert_eq!(base.read(cx).text(), "one\ntwo\nthree\n");
2520        assert_eq!(buffer.text(), "one\n1.5\ntwo\nTHREE\n");
2521    });
2522
2523    // Convert from branch buffer ranges to the corresoponing ranges in the
2524    // base buffer.
2525    branch.read_with(cx, |buffer, cx| {
2526        assert_eq!(
2527            buffer.range_to_version(4..7, &base.read(cx).version()),
2528            4..4
2529        );
2530        assert_eq!(
2531            buffer.range_to_version(2..9, &base.read(cx).version()),
2532            2..5
2533        );
2534    });
2535
2536    // Edits to the base are applied to the branch.
2537    base.update(cx, |buffer, cx| {
2538        buffer.edit([(Point::new(0, 0)..Point::new(0, 0), "ZERO\n")], None, cx)
2539    });
2540    branch.read_with(cx, |buffer, cx| {
2541        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\nthree\n");
2542        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\nTHREE\n");
2543    });
2544
2545    // Edits to any replica of the base are applied to the branch.
2546    base_replica.update(cx, |buffer, cx| {
2547        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "2.5\n")], None, cx)
2548    });
2549    branch.read_with(cx, |buffer, cx| {
2550        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\n2.5\nthree\n");
2551        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2552    });
2553
2554    // Merging the branch applies all of its changes to the base.
2555    branch.update(cx, |buffer, cx| {
2556        buffer.merge_into_base(Vec::new(), cx);
2557    });
2558
2559    branch.update(cx, |buffer, cx| {
2560        assert_eq!(base.read(cx).text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2561        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2562    });
2563}
2564
2565#[gpui::test]
2566fn test_merge_into_base(cx: &mut TestAppContext) {
2567    cx.update(|cx| init_settings(cx, |_| {}));
2568
2569    let base = cx.new_model(|cx| Buffer::local("abcdefghijk", cx));
2570    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2571
2572    // Make 3 edits, merge one into the base.
2573    branch.update(cx, |branch, cx| {
2574        branch.edit([(0..3, "ABC"), (7..9, "HI"), (11..11, "LMN")], None, cx);
2575        branch.merge_into_base(vec![5..8], cx);
2576    });
2577
2578    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjkLMN"));
2579    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2580
2581    // Undo the one already-merged edit. Merge that into the base.
2582    branch.update(cx, |branch, cx| {
2583        branch.edit([(7..9, "hi")], None, cx);
2584        branch.merge_into_base(vec![5..8], cx);
2585    });
2586    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2587
2588    // Merge an insertion into the base.
2589    branch.update(cx, |branch, cx| {
2590        branch.merge_into_base(vec![11..11], cx);
2591    });
2592
2593    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefghijkLMN"));
2594    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijkLMN"));
2595
2596    // Deleted the inserted text and merge that into the base.
2597    branch.update(cx, |branch, cx| {
2598        branch.edit([(11..14, "")], None, cx);
2599        branch.merge_into_base(vec![10..11], cx);
2600    });
2601
2602    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2603}
2604
2605#[gpui::test]
2606fn test_undo_after_merge_into_base(cx: &mut TestAppContext) {
2607    cx.update(|cx| init_settings(cx, |_| {}));
2608
2609    let base = cx.new_model(|cx| Buffer::local("abcdefghijk", cx));
2610    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2611
2612    // Make 2 edits, merge one into the base.
2613    branch.update(cx, |branch, cx| {
2614        branch.edit([(0..3, "ABC"), (7..9, "HI")], None, cx);
2615        branch.merge_into_base(vec![7..7], cx);
2616    });
2617    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2618    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2619
2620    // Undo the merge in the base buffer.
2621    base.update(cx, |base, cx| {
2622        base.undo(cx);
2623    });
2624    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2625    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2626
2627    // Merge that operation into the base again.
2628    branch.update(cx, |branch, cx| {
2629        branch.merge_into_base(vec![7..7], cx);
2630    });
2631    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2632    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2633}
2634
2635#[gpui::test]
2636async fn test_preview_edits(cx: &mut TestAppContext) {
2637    cx.update(|cx| {
2638        init_settings(cx, |_| {});
2639        theme::init(theme::LoadThemes::JustBase, cx);
2640    });
2641
2642    let text = indoc! {r#"
2643        struct Person {
2644            first_name: String,
2645        }
2646
2647        impl Person {
2648            fn last_name(&self) -> &String {
2649                &self.last_name
2650            }
2651        }"#
2652    };
2653
2654    let language = Arc::new(Language::new(
2655        LanguageConfig::default(),
2656        Some(tree_sitter_rust::LANGUAGE.into()),
2657    ));
2658    let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
2659    let highlighted_edits = preview_edits(
2660        &buffer,
2661        cx,
2662        [
2663            (Point::new(5, 7)..Point::new(5, 11), "first"),
2664            (Point::new(6, 14)..Point::new(6, 18), "first"),
2665        ],
2666    )
2667    .await;
2668
2669    assert_eq!(
2670        highlighted_edits.text,
2671        "    fn lastfirst_name(&self) -> &String {\n        &self.lastfirst_name"
2672    );
2673
2674    async fn preview_edits(
2675        buffer: &Model<Buffer>,
2676        cx: &mut TestAppContext,
2677        edits: impl IntoIterator<Item = (Range<Point>, &'static str)>,
2678    ) -> HighlightedEdits {
2679        let edits = buffer.read_with(cx, |buffer, _| {
2680            edits
2681                .into_iter()
2682                .map(|(range, text)| {
2683                    (
2684                        buffer.anchor_before(range.start)..buffer.anchor_after(range.end),
2685                        text.to_string(),
2686                    )
2687                })
2688                .collect::<Vec<_>>()
2689        });
2690        let edit_preview = buffer
2691            .read_with(cx, |buffer, cx| {
2692                buffer.preview_edits(edits.clone().into(), cx)
2693            })
2694            .await;
2695        cx.read(|cx| edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, true, cx))
2696    }
2697}
2698
2699#[gpui::test]
2700async fn test_preview_edits_interpolate(cx: &mut TestAppContext) {
2701    use theme::ActiveTheme;
2702    cx.update(|cx| {
2703        init_settings(cx, |_| {});
2704        theme::init(theme::LoadThemes::JustBase, cx);
2705    });
2706
2707    let text = indoc! {r#"
2708        struct Person {
2709            _name: String
2710        }"#
2711    };
2712
2713    let language = Arc::new(Language::new(
2714        LanguageConfig::default(),
2715        Some(tree_sitter_rust::LANGUAGE.into()),
2716    ));
2717    let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
2718
2719    let edits = construct_edits(&buffer, [(Point::new(1, 4)..Point::new(1, 4), "first")], cx);
2720    let edit_preview = buffer
2721        .read_with(cx, |buffer, cx| buffer.preview_edits(edits.clone(), cx))
2722        .await;
2723
2724    let highlighted_edits =
2725        cx.read(|cx| edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, false, cx));
2726
2727    let created_background = cx.read(|cx| cx.theme().status().created_background);
2728
2729    assert_eq!(highlighted_edits.text, "    first_name: String");
2730    assert_eq!(highlighted_edits.highlights.len(), 1);
2731    assert_eq!(highlighted_edits.highlights[0].0, 4..9);
2732    assert_eq!(
2733        highlighted_edits.highlights[0].1.background_color,
2734        Some(created_background)
2735    );
2736
2737    let edits = construct_edits(&buffer, [(Point::new(1, 4)..Point::new(1, 4), "f")], cx);
2738    cx.update(|cx| {
2739        buffer.update(cx, |buffer, cx| {
2740            buffer.edit(edits.iter().cloned(), None, cx);
2741        })
2742    });
2743
2744    let edits = construct_edits(&buffer, [(Point::new(1, 5)..Point::new(1, 5), "irst")], cx);
2745    let highlighted_edits =
2746        cx.read(|cx| edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, false, cx));
2747
2748    assert_eq!(highlighted_edits.text, "    first_name: String");
2749    assert_eq!(highlighted_edits.highlights.len(), 1);
2750    assert_eq!(highlighted_edits.highlights[0].0, (5..9));
2751    assert_eq!(
2752        highlighted_edits.highlights[0].1.background_color,
2753        Some(created_background)
2754    );
2755
2756    fn construct_edits(
2757        buffer: &Model<Buffer>,
2758        edits: impl IntoIterator<Item = (Range<Point>, &'static str)>,
2759        cx: &mut TestAppContext,
2760    ) -> Arc<[(Range<Anchor>, String)]> {
2761        buffer
2762            .read_with(cx, |buffer, _| {
2763                edits
2764                    .into_iter()
2765                    .map(|(range, text)| {
2766                        (
2767                            buffer.anchor_after(range.start)..buffer.anchor_before(range.end),
2768                            text.to_string(),
2769                        )
2770                    })
2771                    .collect::<Vec<_>>()
2772            })
2773            .into()
2774    }
2775}
2776
2777#[gpui::test(iterations = 100)]
2778fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2779    let min_peers = env::var("MIN_PEERS")
2780        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2781        .unwrap_or(1);
2782    let max_peers = env::var("MAX_PEERS")
2783        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2784        .unwrap_or(5);
2785    let operations = env::var("OPERATIONS")
2786        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2787        .unwrap_or(10);
2788
2789    let base_text_len = rng.gen_range(0..10);
2790    let base_text = RandomCharIter::new(&mut rng)
2791        .take(base_text_len)
2792        .collect::<String>();
2793    let mut replica_ids = Vec::new();
2794    let mut buffers = Vec::new();
2795    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2796    let base_buffer = cx.new_model(|cx| Buffer::local(base_text.as_str(), cx));
2797
2798    for i in 0..rng.gen_range(min_peers..=max_peers) {
2799        let buffer = cx.new_model(|cx| {
2800            let state = base_buffer.read(cx).to_proto(cx);
2801            let ops = cx
2802                .background_executor()
2803                .block(base_buffer.read(cx).serialize_ops(None, cx));
2804            let mut buffer =
2805                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2806            buffer.apply_ops(
2807                ops.into_iter()
2808                    .map(|op| proto::deserialize_operation(op).unwrap()),
2809                cx,
2810            );
2811            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2812            let network = network.clone();
2813            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2814                if let BufferEvent::Operation {
2815                    operation,
2816                    is_local: true,
2817                } = event
2818                {
2819                    network.lock().broadcast(
2820                        buffer.replica_id(),
2821                        vec![proto::serialize_operation(operation)],
2822                    );
2823                }
2824            })
2825            .detach();
2826            buffer
2827        });
2828
2829        buffers.push(buffer);
2830        replica_ids.push(i as ReplicaId);
2831        network.lock().add_peer(i as ReplicaId);
2832        log::info!("Adding initial peer with replica id {}", i);
2833    }
2834
2835    log::info!("initial text: {:?}", base_text);
2836
2837    let mut now = Instant::now();
2838    let mut mutation_count = operations;
2839    let mut next_diagnostic_id = 0;
2840    let mut active_selections = BTreeMap::default();
2841    loop {
2842        let replica_index = rng.gen_range(0..replica_ids.len());
2843        let replica_id = replica_ids[replica_index];
2844        let buffer = &mut buffers[replica_index];
2845        let mut new_buffer = None;
2846        match rng.gen_range(0..100) {
2847            0..=29 if mutation_count != 0 => {
2848                buffer.update(cx, |buffer, cx| {
2849                    buffer.start_transaction_at(now);
2850                    buffer.randomly_edit(&mut rng, 5, cx);
2851                    buffer.end_transaction_at(now, cx);
2852                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2853                });
2854                mutation_count -= 1;
2855            }
2856            30..=39 if mutation_count != 0 => {
2857                buffer.update(cx, |buffer, cx| {
2858                    if rng.gen_bool(0.2) {
2859                        log::info!("peer {} clearing active selections", replica_id);
2860                        active_selections.remove(&replica_id);
2861                        buffer.remove_active_selections(cx);
2862                    } else {
2863                        let mut selections = Vec::new();
2864                        for id in 0..rng.gen_range(1..=5) {
2865                            let range = buffer.random_byte_range(0, &mut rng);
2866                            selections.push(Selection {
2867                                id,
2868                                start: buffer.anchor_before(range.start),
2869                                end: buffer.anchor_before(range.end),
2870                                reversed: false,
2871                                goal: SelectionGoal::None,
2872                            });
2873                        }
2874                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2875                        log::info!(
2876                            "peer {} setting active selections: {:?}",
2877                            replica_id,
2878                            selections
2879                        );
2880                        active_selections.insert(replica_id, selections.clone());
2881                        buffer.set_active_selections(selections, false, Default::default(), cx);
2882                    }
2883                });
2884                mutation_count -= 1;
2885            }
2886            40..=49 if mutation_count != 0 && replica_id == 0 => {
2887                let entry_count = rng.gen_range(1..=5);
2888                buffer.update(cx, |buffer, cx| {
2889                    let diagnostics = DiagnosticSet::new(
2890                        (0..entry_count).map(|_| {
2891                            let range = buffer.random_byte_range(0, &mut rng);
2892                            let range = range.to_point_utf16(buffer);
2893                            let range = range.start..range.end;
2894                            DiagnosticEntry {
2895                                range,
2896                                diagnostic: Diagnostic {
2897                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2898                                    ..Default::default()
2899                                },
2900                            }
2901                        }),
2902                        buffer,
2903                    );
2904                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2905                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2906                });
2907                mutation_count -= 1;
2908            }
2909            50..=59 if replica_ids.len() < max_peers => {
2910                let old_buffer_state = buffer.read(cx).to_proto(cx);
2911                let old_buffer_ops = cx
2912                    .background_executor()
2913                    .block(buffer.read(cx).serialize_ops(None, cx));
2914                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2915                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2916                    .choose(&mut rng)
2917                    .unwrap();
2918                log::info!(
2919                    "Adding new replica {} (replicating from {})",
2920                    new_replica_id,
2921                    replica_id
2922                );
2923                new_buffer = Some(cx.new_model(|cx| {
2924                    let mut new_buffer = Buffer::from_proto(
2925                        new_replica_id,
2926                        Capability::ReadWrite,
2927                        old_buffer_state,
2928                        None,
2929                    )
2930                    .unwrap();
2931                    new_buffer.apply_ops(
2932                        old_buffer_ops
2933                            .into_iter()
2934                            .map(|op| deserialize_operation(op).unwrap()),
2935                        cx,
2936                    );
2937                    log::info!(
2938                        "New replica {} text: {:?}",
2939                        new_buffer.replica_id(),
2940                        new_buffer.text()
2941                    );
2942                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2943                    let network = network.clone();
2944                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2945                        if let BufferEvent::Operation {
2946                            operation,
2947                            is_local: true,
2948                        } = event
2949                        {
2950                            network.lock().broadcast(
2951                                buffer.replica_id(),
2952                                vec![proto::serialize_operation(operation)],
2953                            );
2954                        }
2955                    })
2956                    .detach();
2957                    new_buffer
2958                }));
2959                network.lock().replicate(replica_id, new_replica_id);
2960
2961                if new_replica_id as usize == replica_ids.len() {
2962                    replica_ids.push(new_replica_id);
2963                } else {
2964                    let new_buffer = new_buffer.take().unwrap();
2965                    while network.lock().has_unreceived(new_replica_id) {
2966                        let ops = network
2967                            .lock()
2968                            .receive(new_replica_id)
2969                            .into_iter()
2970                            .map(|op| proto::deserialize_operation(op).unwrap());
2971                        if ops.len() > 0 {
2972                            log::info!(
2973                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2974                                new_replica_id,
2975                                buffer.read(cx).version(),
2976                                ops.len(),
2977                                ops
2978                            );
2979                            new_buffer.update(cx, |new_buffer, cx| {
2980                                new_buffer.apply_ops(ops, cx);
2981                            });
2982                        }
2983                    }
2984                    buffers[new_replica_id as usize] = new_buffer;
2985                }
2986            }
2987            60..=69 if mutation_count != 0 => {
2988                buffer.update(cx, |buffer, cx| {
2989                    buffer.randomly_undo_redo(&mut rng, cx);
2990                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2991                });
2992                mutation_count -= 1;
2993            }
2994            _ if network.lock().has_unreceived(replica_id) => {
2995                let ops = network
2996                    .lock()
2997                    .receive(replica_id)
2998                    .into_iter()
2999                    .map(|op| proto::deserialize_operation(op).unwrap());
3000                if ops.len() > 0 {
3001                    log::info!(
3002                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3003                        replica_id,
3004                        buffer.read(cx).version(),
3005                        ops.len(),
3006                        ops
3007                    );
3008                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx));
3009                }
3010            }
3011            _ => {}
3012        }
3013
3014        now += Duration::from_millis(rng.gen_range(0..=200));
3015        buffers.extend(new_buffer);
3016
3017        for buffer in &buffers {
3018            buffer.read(cx).check_invariants();
3019        }
3020
3021        if mutation_count == 0 && network.lock().is_idle() {
3022            break;
3023        }
3024    }
3025
3026    let first_buffer = buffers[0].read(cx).snapshot();
3027    for buffer in &buffers[1..] {
3028        let buffer = buffer.read(cx).snapshot();
3029        assert_eq!(
3030            buffer.version(),
3031            first_buffer.version(),
3032            "Replica {} version != Replica 0 version",
3033            buffer.replica_id()
3034        );
3035        assert_eq!(
3036            buffer.text(),
3037            first_buffer.text(),
3038            "Replica {} text != Replica 0 text",
3039            buffer.replica_id()
3040        );
3041        assert_eq!(
3042            buffer
3043                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
3044                .collect::<Vec<_>>(),
3045            first_buffer
3046                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
3047                .collect::<Vec<_>>(),
3048            "Replica {} diagnostics != Replica 0 diagnostics",
3049            buffer.replica_id()
3050        );
3051    }
3052
3053    for buffer in &buffers {
3054        let buffer = buffer.read(cx).snapshot();
3055        let actual_remote_selections = buffer
3056            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
3057            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
3058            .collect::<Vec<_>>();
3059        let expected_remote_selections = active_selections
3060            .iter()
3061            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
3062            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
3063            .collect::<Vec<_>>();
3064        assert_eq!(
3065            actual_remote_selections,
3066            expected_remote_selections,
3067            "Replica {} remote selections != expected selections",
3068            buffer.replica_id()
3069        );
3070    }
3071}
3072
3073#[test]
3074fn test_contiguous_ranges() {
3075    assert_eq!(
3076        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
3077        &[1..4, 5..7, 9..13]
3078    );
3079
3080    // Respects the `max_len` parameter
3081    assert_eq!(
3082        contiguous_ranges(
3083            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
3084            3
3085        )
3086        .collect::<Vec<_>>(),
3087        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
3088    );
3089}
3090
3091#[gpui::test(iterations = 500)]
3092fn test_trailing_whitespace_ranges(mut rng: StdRng) {
3093    // Generate a random multi-line string containing
3094    // some lines with trailing whitespace.
3095    let mut text = String::new();
3096    for _ in 0..rng.gen_range(0..16) {
3097        for _ in 0..rng.gen_range(0..36) {
3098            text.push(match rng.gen_range(0..10) {
3099                0..=1 => ' ',
3100                3 => '\t',
3101                _ => rng.gen_range('a'..='z'),
3102            });
3103        }
3104        text.push('\n');
3105    }
3106
3107    match rng.gen_range(0..10) {
3108        // sometimes remove the last newline
3109        0..=1 => drop(text.pop()), //
3110
3111        // sometimes add extra newlines
3112        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
3113        _ => {}
3114    }
3115
3116    let rope = Rope::from(text.as_str());
3117    let actual_ranges = trailing_whitespace_ranges(&rope);
3118    let expected_ranges = TRAILING_WHITESPACE_REGEX
3119        .find_iter(&text)
3120        .map(|m| m.range())
3121        .collect::<Vec<_>>();
3122    assert_eq!(
3123        actual_ranges,
3124        expected_ranges,
3125        "wrong ranges for text lines:\n{:?}",
3126        text.split('\n').collect::<Vec<_>>()
3127    );
3128}
3129
3130fn ruby_lang() -> Language {
3131    Language::new(
3132        LanguageConfig {
3133            name: "Ruby".into(),
3134            matcher: LanguageMatcher {
3135                path_suffixes: vec!["rb".to_string()],
3136                ..Default::default()
3137            },
3138            line_comments: vec!["# ".into()],
3139            ..Default::default()
3140        },
3141        Some(tree_sitter_ruby::LANGUAGE.into()),
3142    )
3143    .with_indents_query(
3144        r#"
3145            (class "end" @end) @indent
3146            (method "end" @end) @indent
3147            (rescue) @outdent
3148            (then) @indent
3149        "#,
3150    )
3151    .unwrap()
3152}
3153
3154fn html_lang() -> Language {
3155    Language::new(
3156        LanguageConfig {
3157            name: LanguageName::new("HTML"),
3158            block_comment: Some(("<!--".into(), "-->".into())),
3159            ..Default::default()
3160        },
3161        Some(tree_sitter_html::language()),
3162    )
3163    .with_indents_query(
3164        "
3165        (element
3166          (start_tag) @start
3167          (end_tag)? @end) @indent
3168        ",
3169    )
3170    .unwrap()
3171    .with_injection_query(
3172        r#"
3173        (script_element
3174            (raw_text) @injection.content
3175            (#set! injection.language "javascript"))
3176        "#,
3177    )
3178    .unwrap()
3179}
3180
3181fn erb_lang() -> Language {
3182    Language::new(
3183        LanguageConfig {
3184            name: "ERB".into(),
3185            matcher: LanguageMatcher {
3186                path_suffixes: vec!["erb".to_string()],
3187                ..Default::default()
3188            },
3189            block_comment: Some(("<%#".into(), "%>".into())),
3190            ..Default::default()
3191        },
3192        Some(tree_sitter_embedded_template::LANGUAGE.into()),
3193    )
3194    .with_injection_query(
3195        r#"
3196            (
3197                (code) @injection.content
3198                (#set! injection.language "ruby")
3199                (#set! injection.combined)
3200            )
3201
3202            (
3203                (content) @injection.content
3204                (#set! injection.language "html")
3205                (#set! injection.combined)
3206            )
3207        "#,
3208    )
3209    .unwrap()
3210}
3211
3212fn rust_lang() -> Language {
3213    Language::new(
3214        LanguageConfig {
3215            name: "Rust".into(),
3216            matcher: LanguageMatcher {
3217                path_suffixes: vec!["rs".to_string()],
3218                ..Default::default()
3219            },
3220            ..Default::default()
3221        },
3222        Some(tree_sitter_rust::LANGUAGE.into()),
3223    )
3224    .with_indents_query(
3225        r#"
3226        (call_expression) @indent
3227        (field_expression) @indent
3228        (_ "(" ")" @end) @indent
3229        (_ "{" "}" @end) @indent
3230        "#,
3231    )
3232    .unwrap()
3233    .with_brackets_query(
3234        r#"
3235        ("{" @open "}" @close)
3236        "#,
3237    )
3238    .unwrap()
3239    .with_text_object_query(
3240        r#"
3241        (function_item
3242            body: (_
3243                "{"
3244                (_)* @function.inside
3245                "}" )) @function.around
3246
3247        (line_comment)+ @comment.around
3248
3249        (block_comment) @comment.around
3250        "#,
3251    )
3252    .unwrap()
3253    .with_outline_query(
3254        r#"
3255        (line_comment) @annotation
3256
3257        (struct_item
3258            "struct" @context
3259            name: (_) @name) @item
3260        (enum_item
3261            "enum" @context
3262            name: (_) @name) @item
3263        (enum_variant
3264            name: (_) @name) @item
3265        (field_declaration
3266            name: (_) @name) @item
3267        (impl_item
3268            "impl" @context
3269            trait: (_)? @name
3270            "for"? @context
3271            type: (_) @name
3272            body: (_ "{" (_)* "}")) @item
3273        (function_item
3274            "fn" @context
3275            name: (_) @name) @item
3276        (mod_item
3277            "mod" @context
3278            name: (_) @name) @item
3279        "#,
3280    )
3281    .unwrap()
3282}
3283
3284fn json_lang() -> Language {
3285    Language::new(
3286        LanguageConfig {
3287            name: "Json".into(),
3288            matcher: LanguageMatcher {
3289                path_suffixes: vec!["js".to_string()],
3290                ..Default::default()
3291            },
3292            ..Default::default()
3293        },
3294        Some(tree_sitter_json::LANGUAGE.into()),
3295    )
3296}
3297
3298fn javascript_lang() -> Language {
3299    Language::new(
3300        LanguageConfig {
3301            name: "JavaScript".into(),
3302            ..Default::default()
3303        },
3304        Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
3305    )
3306    .with_brackets_query(
3307        r#"
3308        ("{" @open "}" @close)
3309        ("(" @open ")" @close)
3310        "#,
3311    )
3312    .unwrap()
3313    .with_indents_query(
3314        r#"
3315        (object "}" @end) @indent
3316        "#,
3317    )
3318    .unwrap()
3319}
3320
3321pub fn markdown_lang() -> Language {
3322    Language::new(
3323        LanguageConfig {
3324            name: "Markdown".into(),
3325            matcher: LanguageMatcher {
3326                path_suffixes: vec!["md".into()],
3327                ..Default::default()
3328            },
3329            ..Default::default()
3330        },
3331        Some(tree_sitter_md::LANGUAGE.into()),
3332    )
3333    .with_injection_query(
3334        r#"
3335            (fenced_code_block
3336                (info_string
3337                    (language) @injection.language)
3338                (code_fence_content) @injection.content)
3339
3340                ((inline) @injection.content
3341                (#set! injection.language "markdown-inline"))
3342        "#,
3343    )
3344    .unwrap()
3345}
3346
3347pub fn markdown_inline_lang() -> Language {
3348    Language::new(
3349        LanguageConfig {
3350            name: "Markdown-Inline".into(),
3351            hidden: true,
3352            ..LanguageConfig::default()
3353        },
3354        Some(tree_sitter_md::INLINE_LANGUAGE.into()),
3355    )
3356    .with_highlights_query("(emphasis) @emphasis")
3357    .unwrap()
3358}
3359
3360fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
3361    buffer.update(cx, |buffer, _| {
3362        let snapshot = buffer.snapshot();
3363        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
3364        layers[0].node().to_sexp()
3365    })
3366}
3367
3368// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
3369fn assert_bracket_pairs(
3370    selection_text: &'static str,
3371    bracket_pair_texts: Vec<&'static str>,
3372    language: Language,
3373    cx: &mut AppContext,
3374) {
3375    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
3376    let buffer = cx.new_model(|cx| {
3377        Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx)
3378    });
3379    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
3380
3381    let selection_range = selection_ranges[0].clone();
3382
3383    let bracket_pairs = bracket_pair_texts
3384        .into_iter()
3385        .map(|pair_text| {
3386            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
3387            assert_eq!(bracket_text, expected_text);
3388            (ranges[0].clone(), ranges[1].clone())
3389        })
3390        .collect::<Vec<_>>();
3391
3392    assert_set_eq!(
3393        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
3394        bracket_pairs
3395    );
3396}
3397
3398fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
3399    let settings_store = SettingsStore::test(cx);
3400    cx.set_global(settings_store);
3401    crate::init(cx);
3402    cx.update_global::<SettingsStore, _>(|settings, cx| {
3403        settings.update_user_settings::<AllLanguageSettings>(cx, f);
3404    });
3405}