buffer_tests.rs

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