buffer_tests.rs

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