buffer_tests.rs

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