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