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_with_newline(cx: &mut App) {
1717    init_settings(cx, |_| {});
1718
1719    cx.new(|cx| {
1720        let text = r#"
1721            fn a() {
1722                b();
1723            }
1724        "#
1725        .unindent();
1726        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1727
1728        // First line contains just '\n', it's indentation is stored in "original_indent_columns"
1729        let original_indent_columns = vec![Some(4)];
1730        let inserted_text = r#"
1731
1732                c();
1733                    d();
1734                        e();
1735        "#
1736        .unindent();
1737        buffer.edit(
1738            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1739            Some(AutoindentMode::Block {
1740                original_indent_columns: original_indent_columns.clone(),
1741            }),
1742            cx,
1743        );
1744
1745        // While making edit, we ignore first line as it only contains '\n'
1746        // hence second line indent is used to calculate delta
1747        assert_eq!(
1748            buffer.text(),
1749            r#"
1750            fn a() {
1751                b();
1752
1753                c();
1754                    d();
1755                        e();
1756            }
1757            "#
1758            .unindent()
1759        );
1760
1761        buffer
1762    });
1763}
1764
1765#[gpui::test]
1766fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut App) {
1767    init_settings(cx, |_| {});
1768
1769    cx.new(|cx| {
1770        let text = r#"
1771            fn a() {
1772                if b() {
1773
1774                }
1775            }
1776        "#
1777        .unindent();
1778        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1779
1780        // The original indent columns are not known, so this text is
1781        // auto-indented in a block as if the first line was copied in
1782        // its entirety.
1783        let original_indent_columns = Vec::new();
1784        let inserted_text = "    c\n        .d()\n        .e();";
1785
1786        // Insert the block at column zero. The entire block is indented
1787        // so that the first line matches the previous line's indentation.
1788        buffer.edit(
1789            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1790            Some(AutoindentMode::Block {
1791                original_indent_columns: original_indent_columns.clone(),
1792            }),
1793            cx,
1794        );
1795        assert_eq!(
1796            buffer.text(),
1797            r#"
1798            fn a() {
1799                if b() {
1800                    c
1801                        .d()
1802                        .e();
1803                }
1804            }
1805            "#
1806            .unindent()
1807        );
1808
1809        // Grouping is disabled in tests, so we need 2 undos
1810        buffer.undo(cx); // Undo the auto-indent
1811        buffer.undo(cx); // Undo the original edit
1812
1813        // Insert the block at a deeper indent level. The entire block is outdented.
1814        buffer.edit(
1815            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1816            None,
1817            cx,
1818        );
1819        buffer.edit(
1820            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1821            Some(AutoindentMode::Block {
1822                original_indent_columns: Vec::new(),
1823            }),
1824            cx,
1825        );
1826        assert_eq!(
1827            buffer.text(),
1828            r#"
1829            fn a() {
1830                if b() {
1831                    c
1832                        .d()
1833                        .e();
1834                }
1835            }
1836            "#
1837            .unindent()
1838        );
1839
1840        buffer
1841    });
1842}
1843
1844#[gpui::test]
1845fn test_autoindent_block_mode_multiple_adjacent_ranges(cx: &mut App) {
1846    init_settings(cx, |_| {});
1847
1848    cx.new(|cx| {
1849        let (text, ranges_to_replace) = marked_text_ranges(
1850            &"
1851            mod numbers {
1852                «fn one() {
1853                    1
1854                }
1855            »
1856                «fn two() {
1857                    2
1858                }
1859            »
1860                «fn three() {
1861                    3
1862                }
1863            »}
1864            "
1865            .unindent(),
1866            false,
1867        );
1868
1869        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1870
1871        buffer.edit(
1872            [
1873                (ranges_to_replace[0].clone(), "fn one() {\n    101\n}\n"),
1874                (ranges_to_replace[1].clone(), "fn two() {\n    102\n}\n"),
1875                (ranges_to_replace[2].clone(), "fn three() {\n    103\n}\n"),
1876            ],
1877            Some(AutoindentMode::Block {
1878                original_indent_columns: vec![Some(0), Some(0), Some(0)],
1879            }),
1880            cx,
1881        );
1882
1883        pretty_assertions::assert_eq!(
1884            buffer.text(),
1885            "
1886            mod numbers {
1887                fn one() {
1888                    101
1889                }
1890
1891                fn two() {
1892                    102
1893                }
1894
1895                fn three() {
1896                    103
1897                }
1898            }
1899            "
1900            .unindent()
1901        );
1902
1903        buffer
1904    });
1905}
1906
1907#[gpui::test]
1908fn test_autoindent_language_without_indents_query(cx: &mut App) {
1909    init_settings(cx, |_| {});
1910
1911    cx.new(|cx| {
1912        let text = "
1913            * one
1914                - a
1915                - b
1916            * two
1917        "
1918        .unindent();
1919
1920        let mut buffer = Buffer::local(text, cx).with_language(
1921            Arc::new(Language::new(
1922                LanguageConfig {
1923                    name: "Markdown".into(),
1924                    auto_indent_using_last_non_empty_line: false,
1925                    ..Default::default()
1926                },
1927                Some(tree_sitter_json::LANGUAGE.into()),
1928            )),
1929            cx,
1930        );
1931        buffer.edit(
1932            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1933            Some(AutoindentMode::EachLine),
1934            cx,
1935        );
1936        assert_eq!(
1937            buffer.text(),
1938            "
1939            * one
1940                - a
1941                - b
1942
1943            * two
1944            "
1945            .unindent()
1946        );
1947        buffer
1948    });
1949}
1950
1951#[gpui::test]
1952fn test_autoindent_with_injected_languages(cx: &mut App) {
1953    init_settings(cx, |settings| {
1954        settings.languages.extend([
1955            (
1956                "HTML".into(),
1957                LanguageSettingsContent {
1958                    tab_size: Some(2.try_into().unwrap()),
1959                    ..Default::default()
1960                },
1961            ),
1962            (
1963                "JavaScript".into(),
1964                LanguageSettingsContent {
1965                    tab_size: Some(8.try_into().unwrap()),
1966                    ..Default::default()
1967                },
1968            ),
1969        ])
1970    });
1971
1972    let html_language = Arc::new(html_lang());
1973
1974    let javascript_language = Arc::new(javascript_lang());
1975
1976    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1977    language_registry.add(html_language.clone());
1978    language_registry.add(javascript_language.clone());
1979
1980    cx.new(|cx| {
1981        let (text, ranges) = marked_text_ranges(
1982            &"
1983                <div>ˇ
1984                </div>
1985                <script>
1986                    init({ˇ
1987                    })
1988                </script>
1989                <span>ˇ
1990                </span>
1991            "
1992            .unindent(),
1993            false,
1994        );
1995
1996        let mut buffer = Buffer::local(text, cx);
1997        buffer.set_language_registry(language_registry);
1998        buffer.set_language(Some(html_language), cx);
1999        buffer.edit(
2000            ranges.into_iter().map(|range| (range, "\na")),
2001            Some(AutoindentMode::EachLine),
2002            cx,
2003        );
2004        assert_eq!(
2005            buffer.text(),
2006            "
2007                <div>
2008                  a
2009                </div>
2010                <script>
2011                    init({
2012                            a
2013                    })
2014                </script>
2015                <span>
2016                  a
2017                </span>
2018            "
2019            .unindent()
2020        );
2021        buffer
2022    });
2023}
2024
2025#[gpui::test]
2026fn test_autoindent_query_with_outdent_captures(cx: &mut App) {
2027    init_settings(cx, |settings| {
2028        settings.defaults.tab_size = Some(2.try_into().unwrap());
2029    });
2030
2031    cx.new(|cx| {
2032        let mut buffer = Buffer::local("", cx).with_language(Arc::new(ruby_lang()), cx);
2033
2034        let text = r#"
2035            class C
2036            def a(b, c)
2037            puts b
2038            puts c
2039            rescue
2040            puts "errored"
2041            exit 1
2042            end
2043            end
2044        "#
2045        .unindent();
2046
2047        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
2048
2049        assert_eq!(
2050            buffer.text(),
2051            r#"
2052                class C
2053                  def a(b, c)
2054                    puts b
2055                    puts c
2056                  rescue
2057                    puts "errored"
2058                    exit 1
2059                  end
2060                end
2061            "#
2062            .unindent()
2063        );
2064
2065        buffer
2066    });
2067}
2068
2069#[gpui::test]
2070async fn test_async_autoindents_preserve_preview(cx: &mut TestAppContext) {
2071    cx.update(|cx| init_settings(cx, |_| {}));
2072
2073    // First we insert some newlines to request an auto-indent (asynchronously).
2074    // Then we request that a preview tab be preserved for the new version, even though it's edited.
2075    let buffer = cx.new(|cx| {
2076        let text = "fn a() {}";
2077        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
2078
2079        // This causes autoindent to be async.
2080        buffer.set_sync_parse_timeout(Duration::ZERO);
2081
2082        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
2083        buffer.refresh_preview();
2084
2085        // Synchronously, we haven't auto-indented and we're still preserving the preview.
2086        assert_eq!(buffer.text(), "fn a() {\n\n}");
2087        assert!(buffer.preserve_preview());
2088        buffer
2089    });
2090
2091    // Now let the autoindent finish
2092    cx.executor().run_until_parked();
2093
2094    // The auto-indent applied, but didn't dismiss our preview
2095    buffer.update(cx, |buffer, cx| {
2096        assert_eq!(buffer.text(), "fn a() {\n    \n}");
2097        assert!(buffer.preserve_preview());
2098
2099        // Edit inserting another line. It will autoindent async.
2100        // Then refresh the preview version.
2101        buffer.edit(
2102            [(Point::new(1, 4)..Point::new(1, 4), "\n")],
2103            Some(AutoindentMode::EachLine),
2104            cx,
2105        );
2106        buffer.refresh_preview();
2107        assert_eq!(buffer.text(), "fn a() {\n    \n\n}");
2108        assert!(buffer.preserve_preview());
2109
2110        // Then perform another edit, this time without refreshing the preview version.
2111        buffer.edit([(Point::new(1, 4)..Point::new(1, 4), "x")], None, cx);
2112        // This causes the preview to not be preserved.
2113        assert!(!buffer.preserve_preview());
2114    });
2115
2116    // Let the async autoindent from the first edit finish.
2117    cx.executor().run_until_parked();
2118
2119    // The autoindent applies, but it shouldn't restore the preview status because we had an edit in the meantime.
2120    buffer.update(cx, |buffer, _| {
2121        assert_eq!(buffer.text(), "fn a() {\n    x\n    \n}");
2122        assert!(!buffer.preserve_preview());
2123    });
2124}
2125
2126#[gpui::test]
2127fn test_insert_empty_line(cx: &mut App) {
2128    init_settings(cx, |_| {});
2129
2130    // Insert empty line at the beginning, requesting an empty line above
2131    cx.new(|cx| {
2132        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2133        let point = buffer.insert_empty_line(Point::new(0, 0), true, false, cx);
2134        assert_eq!(buffer.text(), "\nabc\ndef\nghi");
2135        assert_eq!(point, Point::new(0, 0));
2136        buffer
2137    });
2138
2139    // Insert empty line at the beginning, requesting an empty line above and below
2140    cx.new(|cx| {
2141        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2142        let point = buffer.insert_empty_line(Point::new(0, 0), true, true, cx);
2143        assert_eq!(buffer.text(), "\n\nabc\ndef\nghi");
2144        assert_eq!(point, Point::new(0, 0));
2145        buffer
2146    });
2147
2148    // Insert empty line at the start of a line, requesting empty lines above and below
2149    cx.new(|cx| {
2150        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2151        let point = buffer.insert_empty_line(Point::new(2, 0), true, true, cx);
2152        assert_eq!(buffer.text(), "abc\ndef\n\n\n\nghi");
2153        assert_eq!(point, Point::new(3, 0));
2154        buffer
2155    });
2156
2157    // Insert empty line in the middle of a line, requesting empty lines above and below
2158    cx.new(|cx| {
2159        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2160        let point = buffer.insert_empty_line(Point::new(1, 3), true, true, cx);
2161        assert_eq!(buffer.text(), "abc\ndef\n\n\n\nghi\njkl");
2162        assert_eq!(point, Point::new(3, 0));
2163        buffer
2164    });
2165
2166    // Insert empty line in the middle of a line, requesting empty line above only
2167    cx.new(|cx| {
2168        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2169        let point = buffer.insert_empty_line(Point::new(1, 3), true, false, cx);
2170        assert_eq!(buffer.text(), "abc\ndef\n\n\nghi\njkl");
2171        assert_eq!(point, Point::new(3, 0));
2172        buffer
2173    });
2174
2175    // Insert empty line in the middle of a line, requesting empty line below only
2176    cx.new(|cx| {
2177        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2178        let point = buffer.insert_empty_line(Point::new(1, 3), false, true, cx);
2179        assert_eq!(buffer.text(), "abc\ndef\n\n\nghi\njkl");
2180        assert_eq!(point, Point::new(2, 0));
2181        buffer
2182    });
2183
2184    // Insert empty line at the end, requesting empty lines above and below
2185    cx.new(|cx| {
2186        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2187        let point = buffer.insert_empty_line(Point::new(2, 3), true, true, cx);
2188        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n\n");
2189        assert_eq!(point, Point::new(4, 0));
2190        buffer
2191    });
2192
2193    // Insert empty line at the end, requesting empty line above only
2194    cx.new(|cx| {
2195        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2196        let point = buffer.insert_empty_line(Point::new(2, 3), true, false, cx);
2197        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n");
2198        assert_eq!(point, Point::new(4, 0));
2199        buffer
2200    });
2201
2202    // Insert empty line at the end, requesting empty line below only
2203    cx.new(|cx| {
2204        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2205        let point = buffer.insert_empty_line(Point::new(2, 3), false, true, cx);
2206        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n");
2207        assert_eq!(point, Point::new(3, 0));
2208        buffer
2209    });
2210}
2211
2212#[gpui::test]
2213fn test_language_scope_at_with_javascript(cx: &mut App) {
2214    init_settings(cx, |_| {});
2215
2216    cx.new(|cx| {
2217        let language = Language::new(
2218            LanguageConfig {
2219                name: "JavaScript".into(),
2220                line_comments: vec!["// ".into()],
2221                brackets: BracketPairConfig {
2222                    pairs: vec![
2223                        BracketPair {
2224                            start: "{".into(),
2225                            end: "}".into(),
2226                            close: true,
2227                            surround: true,
2228                            newline: false,
2229                        },
2230                        BracketPair {
2231                            start: "'".into(),
2232                            end: "'".into(),
2233                            close: true,
2234                            surround: true,
2235                            newline: false,
2236                        },
2237                    ],
2238                    disabled_scopes_by_bracket_ix: vec![
2239                        Vec::new(),                              //
2240                        vec!["string".into(), "comment".into()], // single quotes disabled
2241                    ],
2242                },
2243                overrides: [(
2244                    "element".into(),
2245                    LanguageConfigOverride {
2246                        line_comments: Override::Remove { remove: true },
2247                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
2248                        ..Default::default()
2249                    },
2250                )]
2251                .into_iter()
2252                .collect(),
2253                ..Default::default()
2254            },
2255            Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
2256        )
2257        .with_override_query(
2258            r#"
2259                (jsx_element) @element
2260                (string) @string
2261                (comment) @comment.inclusive
2262                [
2263                    (jsx_opening_element)
2264                    (jsx_closing_element)
2265                    (jsx_expression)
2266                ] @default
2267            "#,
2268        )
2269        .unwrap();
2270
2271        let text = r#"
2272            a["b"] = <C d="e">
2273                <F></F>
2274                { g() }
2275            </C>; // a comment
2276        "#
2277        .unindent();
2278
2279        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
2280        let snapshot = buffer.snapshot();
2281
2282        let config = snapshot.language_scope_at(0).unwrap();
2283        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
2284        // Both bracket pairs are enabled
2285        assert_eq!(
2286            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2287            &[true, true]
2288        );
2289
2290        let comment_config = snapshot
2291            .language_scope_at(text.find("comment").unwrap() + "comment".len())
2292            .unwrap();
2293        assert_eq!(
2294            comment_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2295            &[true, false]
2296        );
2297
2298        let string_config = snapshot
2299            .language_scope_at(text.find("b\"").unwrap())
2300            .unwrap();
2301        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
2302        // Second bracket pair is disabled
2303        assert_eq!(
2304            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2305            &[true, false]
2306        );
2307
2308        // In between JSX tags: use the `element` override.
2309        let element_config = snapshot
2310            .language_scope_at(text.find("<F>").unwrap())
2311            .unwrap();
2312        // TODO nested blocks after newlines are captured with all whitespaces
2313        // https://github.com/tree-sitter/tree-sitter-typescript/issues/306
2314        // assert_eq!(element_config.line_comment_prefixes(), &[]);
2315        // assert_eq!(
2316        //     element_config.block_comment_delimiters(),
2317        //     Some((&"{/*".into(), &"*/}".into()))
2318        // );
2319        assert_eq!(
2320            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2321            &[true, true]
2322        );
2323
2324        // Within a JSX tag: use the default config.
2325        let tag_config = snapshot
2326            .language_scope_at(text.find(" d=").unwrap() + 1)
2327            .unwrap();
2328        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
2329        assert_eq!(
2330            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2331            &[true, true]
2332        );
2333
2334        // In a JSX expression: use the default config.
2335        let expression_in_element_config = snapshot
2336            .language_scope_at(text.find('{').unwrap() + 1)
2337            .unwrap();
2338        assert_eq!(
2339            expression_in_element_config.line_comment_prefixes(),
2340            &[Arc::from("// ")]
2341        );
2342        assert_eq!(
2343            expression_in_element_config
2344                .brackets()
2345                .map(|e| e.1)
2346                .collect::<Vec<_>>(),
2347            &[true, true]
2348        );
2349
2350        buffer
2351    });
2352}
2353
2354#[gpui::test]
2355fn test_language_scope_at_with_rust(cx: &mut App) {
2356    init_settings(cx, |_| {});
2357
2358    cx.new(|cx| {
2359        let language = Language::new(
2360            LanguageConfig {
2361                name: "Rust".into(),
2362                brackets: BracketPairConfig {
2363                    pairs: vec![
2364                        BracketPair {
2365                            start: "{".into(),
2366                            end: "}".into(),
2367                            close: true,
2368                            surround: true,
2369                            newline: false,
2370                        },
2371                        BracketPair {
2372                            start: "'".into(),
2373                            end: "'".into(),
2374                            close: true,
2375                            surround: true,
2376                            newline: false,
2377                        },
2378                    ],
2379                    disabled_scopes_by_bracket_ix: vec![
2380                        Vec::new(), //
2381                        vec!["string".into()],
2382                    ],
2383                },
2384                ..Default::default()
2385            },
2386            Some(tree_sitter_rust::LANGUAGE.into()),
2387        )
2388        .with_override_query(
2389            r#"
2390                (string_literal) @string
2391            "#,
2392        )
2393        .unwrap();
2394
2395        let text = r#"
2396            const S: &'static str = "hello";
2397        "#
2398        .unindent();
2399
2400        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
2401        let snapshot = buffer.snapshot();
2402
2403        // By default, all brackets are enabled
2404        let config = snapshot.language_scope_at(0).unwrap();
2405        assert_eq!(
2406            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2407            &[true, true]
2408        );
2409
2410        // Within a string, the quotation brackets are disabled.
2411        let string_config = snapshot
2412            .language_scope_at(text.find("ello").unwrap())
2413            .unwrap();
2414        assert_eq!(
2415            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2416            &[true, false]
2417        );
2418
2419        buffer
2420    });
2421}
2422
2423#[gpui::test]
2424fn test_language_scope_at_with_combined_injections(cx: &mut App) {
2425    init_settings(cx, |_| {});
2426
2427    cx.new(|cx| {
2428        let text = r#"
2429            <ol>
2430            <% people.each do |person| %>
2431                <li>
2432                    <%= person.name %>
2433                </li>
2434            <% end %>
2435            </ol>
2436        "#
2437        .unindent();
2438
2439        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2440        language_registry.add(Arc::new(ruby_lang()));
2441        language_registry.add(Arc::new(html_lang()));
2442        language_registry.add(Arc::new(erb_lang()));
2443
2444        let mut buffer = Buffer::local(text, cx);
2445        buffer.set_language_registry(language_registry.clone());
2446        buffer.set_language(
2447            language_registry
2448                .language_for_name("ERB")
2449                .now_or_never()
2450                .unwrap()
2451                .ok(),
2452            cx,
2453        );
2454
2455        let snapshot = buffer.snapshot();
2456        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2457        assert_eq!(html_config.line_comment_prefixes(), &[]);
2458        assert_eq!(
2459            html_config.block_comment_delimiters(),
2460            Some((&"<!--".into(), &"-->".into()))
2461        );
2462
2463        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2464        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2465        assert_eq!(ruby_config.block_comment_delimiters(), None);
2466
2467        buffer
2468    });
2469}
2470
2471#[gpui::test]
2472fn test_language_at_with_hidden_languages(cx: &mut App) {
2473    init_settings(cx, |_| {});
2474
2475    cx.new(|cx| {
2476        let text = r#"
2477            this is an *emphasized* word.
2478        "#
2479        .unindent();
2480
2481        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2482        language_registry.add(Arc::new(markdown_lang()));
2483        language_registry.add(Arc::new(markdown_inline_lang()));
2484
2485        let mut buffer = Buffer::local(text, cx);
2486        buffer.set_language_registry(language_registry.clone());
2487        buffer.set_language(
2488            language_registry
2489                .language_for_name("Markdown")
2490                .now_or_never()
2491                .unwrap()
2492                .ok(),
2493            cx,
2494        );
2495
2496        let snapshot = buffer.snapshot();
2497
2498        for point in [Point::new(0, 4), Point::new(0, 16)] {
2499            let config = snapshot.language_scope_at(point).unwrap();
2500            assert_eq!(config.language_name(), "Markdown".into());
2501
2502            let language = snapshot.language_at(point).unwrap();
2503            assert_eq!(language.name().as_ref(), "Markdown");
2504        }
2505
2506        buffer
2507    });
2508}
2509
2510#[gpui::test]
2511fn test_language_at_for_markdown_code_block(cx: &mut App) {
2512    init_settings(cx, |_| {});
2513
2514    cx.new(|cx| {
2515        let text = r#"
2516            ```rs
2517            let a = 2;
2518            // let b = 3;
2519            ```
2520        "#
2521        .unindent();
2522
2523        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2524        language_registry.add(Arc::new(markdown_lang()));
2525        language_registry.add(Arc::new(markdown_inline_lang()));
2526        language_registry.add(Arc::new(rust_lang()));
2527
2528        let mut buffer = Buffer::local(text, cx);
2529        buffer.set_language_registry(language_registry.clone());
2530        buffer.set_language(
2531            language_registry
2532                .language_for_name("Markdown")
2533                .now_or_never()
2534                .unwrap()
2535                .ok(),
2536            cx,
2537        );
2538
2539        let snapshot = buffer.snapshot();
2540
2541        // Test points in the code line
2542        for point in [Point::new(1, 4), Point::new(1, 6)] {
2543            let config = snapshot.language_scope_at(point).unwrap();
2544            assert_eq!(config.language_name(), "Rust".into());
2545
2546            let language = snapshot.language_at(point).unwrap();
2547            assert_eq!(language.name().as_ref(), "Rust");
2548        }
2549
2550        // Test points in the comment line to verify it's still detected as Rust
2551        for point in [Point::new(2, 4), Point::new(2, 6)] {
2552            let config = snapshot.language_scope_at(point).unwrap();
2553            assert_eq!(config.language_name(), "Rust".into());
2554
2555            let language = snapshot.language_at(point).unwrap();
2556            assert_eq!(language.name().as_ref(), "Rust");
2557        }
2558
2559        buffer
2560    });
2561}
2562
2563#[gpui::test]
2564fn test_serialization(cx: &mut gpui::App) {
2565    let mut now = Instant::now();
2566
2567    let buffer1 = cx.new(|cx| {
2568        let mut buffer = Buffer::local("abc", cx);
2569        buffer.edit([(3..3, "D")], None, cx);
2570
2571        now += Duration::from_secs(1);
2572        buffer.start_transaction_at(now);
2573        buffer.edit([(4..4, "E")], None, cx);
2574        buffer.end_transaction_at(now, cx);
2575        assert_eq!(buffer.text(), "abcDE");
2576
2577        buffer.undo(cx);
2578        assert_eq!(buffer.text(), "abcD");
2579
2580        buffer.edit([(4..4, "F")], None, cx);
2581        assert_eq!(buffer.text(), "abcDF");
2582        buffer
2583    });
2584    assert_eq!(buffer1.read(cx).text(), "abcDF");
2585
2586    let state = buffer1.read(cx).to_proto(cx);
2587    let ops = cx
2588        .background_executor()
2589        .block(buffer1.read(cx).serialize_ops(None, cx));
2590    let buffer2 = cx.new(|cx| {
2591        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2592        buffer.apply_ops(
2593            ops.into_iter()
2594                .map(|op| proto::deserialize_operation(op).unwrap()),
2595            cx,
2596        );
2597        buffer
2598    });
2599    assert_eq!(buffer2.read(cx).text(), "abcDF");
2600}
2601
2602#[gpui::test]
2603fn test_branch_and_merge(cx: &mut TestAppContext) {
2604    cx.update(|cx| init_settings(cx, |_| {}));
2605
2606    let base = cx.new(|cx| Buffer::local("one\ntwo\nthree\n", cx));
2607
2608    // Create a remote replica of the base buffer.
2609    let base_replica = cx.new(|cx| {
2610        Buffer::from_proto(1, Capability::ReadWrite, base.read(cx).to_proto(cx), None).unwrap()
2611    });
2612    base.update(cx, |_buffer, cx| {
2613        cx.subscribe(&base_replica, |this, _, event, cx| {
2614            if let BufferEvent::Operation {
2615                operation,
2616                is_local: true,
2617            } = event
2618            {
2619                this.apply_ops([operation.clone()], cx);
2620            }
2621        })
2622        .detach();
2623    });
2624
2625    // Create a branch, which initially has the same state as the base buffer.
2626    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2627    branch.read_with(cx, |buffer, _| {
2628        assert_eq!(buffer.text(), "one\ntwo\nthree\n");
2629    });
2630
2631    // Edits to the branch are not applied to the base.
2632    branch.update(cx, |buffer, cx| {
2633        buffer.edit(
2634            [
2635                (Point::new(1, 0)..Point::new(1, 0), "1.5\n"),
2636                (Point::new(2, 0)..Point::new(2, 5), "THREE"),
2637            ],
2638            None,
2639            cx,
2640        )
2641    });
2642    branch.read_with(cx, |buffer, cx| {
2643        assert_eq!(base.read(cx).text(), "one\ntwo\nthree\n");
2644        assert_eq!(buffer.text(), "one\n1.5\ntwo\nTHREE\n");
2645    });
2646
2647    // Convert from branch buffer ranges to the corresponding ranges in the
2648    // base buffer.
2649    branch.read_with(cx, |buffer, cx| {
2650        assert_eq!(
2651            buffer.range_to_version(4..7, &base.read(cx).version()),
2652            4..4
2653        );
2654        assert_eq!(
2655            buffer.range_to_version(2..9, &base.read(cx).version()),
2656            2..5
2657        );
2658    });
2659
2660    // Edits to the base are applied to the branch.
2661    base.update(cx, |buffer, cx| {
2662        buffer.edit([(Point::new(0, 0)..Point::new(0, 0), "ZERO\n")], None, cx)
2663    });
2664    branch.read_with(cx, |buffer, cx| {
2665        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\nthree\n");
2666        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\nTHREE\n");
2667    });
2668
2669    // Edits to any replica of the base are applied to the branch.
2670    base_replica.update(cx, |buffer, cx| {
2671        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "2.5\n")], None, cx)
2672    });
2673    branch.read_with(cx, |buffer, cx| {
2674        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\n2.5\nthree\n");
2675        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2676    });
2677
2678    // Merging the branch applies all of its changes to the base.
2679    branch.update(cx, |buffer, cx| {
2680        buffer.merge_into_base(Vec::new(), cx);
2681    });
2682
2683    branch.update(cx, |buffer, cx| {
2684        assert_eq!(base.read(cx).text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2685        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2686    });
2687}
2688
2689#[gpui::test]
2690fn test_merge_into_base(cx: &mut TestAppContext) {
2691    cx.update(|cx| init_settings(cx, |_| {}));
2692
2693    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2694    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2695
2696    // Make 3 edits, merge one into the base.
2697    branch.update(cx, |branch, cx| {
2698        branch.edit([(0..3, "ABC"), (7..9, "HI"), (11..11, "LMN")], None, cx);
2699        branch.merge_into_base(vec![5..8], cx);
2700    });
2701
2702    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjkLMN"));
2703    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2704
2705    // Undo the one already-merged edit. Merge that into the base.
2706    branch.update(cx, |branch, cx| {
2707        branch.edit([(7..9, "hi")], None, cx);
2708        branch.merge_into_base(vec![5..8], cx);
2709    });
2710    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2711
2712    // Merge an insertion into the base.
2713    branch.update(cx, |branch, cx| {
2714        branch.merge_into_base(vec![11..11], cx);
2715    });
2716
2717    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefghijkLMN"));
2718    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijkLMN"));
2719
2720    // Deleted the inserted text and merge that into the base.
2721    branch.update(cx, |branch, cx| {
2722        branch.edit([(11..14, "")], None, cx);
2723        branch.merge_into_base(vec![10..11], cx);
2724    });
2725
2726    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2727}
2728
2729#[gpui::test]
2730fn test_undo_after_merge_into_base(cx: &mut TestAppContext) {
2731    cx.update(|cx| init_settings(cx, |_| {}));
2732
2733    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2734    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2735
2736    // Make 2 edits, merge one into the base.
2737    branch.update(cx, |branch, cx| {
2738        branch.edit([(0..3, "ABC"), (7..9, "HI")], None, cx);
2739        branch.merge_into_base(vec![7..7], cx);
2740    });
2741    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2742    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2743
2744    // Undo the merge in the base buffer.
2745    base.update(cx, |base, cx| {
2746        base.undo(cx);
2747    });
2748    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2749    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2750
2751    // Merge that operation into the base again.
2752    branch.update(cx, |branch, cx| {
2753        branch.merge_into_base(vec![7..7], cx);
2754    });
2755    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2756    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2757}
2758
2759#[gpui::test]
2760async fn test_preview_edits(cx: &mut TestAppContext) {
2761    cx.update(|cx| {
2762        init_settings(cx, |_| {});
2763        theme::init(theme::LoadThemes::JustBase, cx);
2764    });
2765
2766    let insertion_style = HighlightStyle {
2767        background_color: Some(cx.read(|cx| cx.theme().status().created_background)),
2768        ..Default::default()
2769    };
2770    let deletion_style = HighlightStyle {
2771        background_color: Some(cx.read(|cx| cx.theme().status().deleted_background)),
2772        ..Default::default()
2773    };
2774
2775    // no edits
2776    assert_preview_edits(
2777        indoc! {"
2778        fn test_empty() -> bool {
2779            false
2780        }"
2781        },
2782        vec![],
2783        true,
2784        cx,
2785        |hl| {
2786            assert!(hl.text.is_empty());
2787            assert!(hl.highlights.is_empty());
2788        },
2789    )
2790    .await;
2791
2792    // only insertions
2793    assert_preview_edits(
2794        indoc! {"
2795        fn calculate_area(: f64) -> f64 {
2796            std::f64::consts::PI * .powi(2)
2797        }"
2798        },
2799        vec![
2800            (Point::new(0, 18)..Point::new(0, 18), "radius"),
2801            (Point::new(1, 27)..Point::new(1, 27), "radius"),
2802        ],
2803        true,
2804        cx,
2805        |hl| {
2806            assert_eq!(
2807                hl.text,
2808                indoc! {"
2809                fn calculate_area(radius: f64) -> f64 {
2810                    std::f64::consts::PI * radius.powi(2)"
2811                }
2812            );
2813
2814            assert_eq!(hl.highlights.len(), 2);
2815            assert_eq!(hl.highlights[0], ((18..24), insertion_style));
2816            assert_eq!(hl.highlights[1], ((67..73), insertion_style));
2817        },
2818    )
2819    .await;
2820
2821    // insertions & deletions
2822    assert_preview_edits(
2823        indoc! {"
2824        struct Person {
2825            first_name: String,
2826        }
2827
2828        impl Person {
2829            fn first_name(&self) -> &String {
2830                &self.first_name
2831            }
2832        }"
2833        },
2834        vec![
2835            (Point::new(1, 4)..Point::new(1, 9), "last"),
2836            (Point::new(5, 7)..Point::new(5, 12), "last"),
2837            (Point::new(6, 14)..Point::new(6, 19), "last"),
2838        ],
2839        true,
2840        cx,
2841        |hl| {
2842            assert_eq!(
2843                hl.text,
2844                indoc! {"
2845                        firstlast_name: String,
2846                    }
2847
2848                    impl Person {
2849                        fn firstlast_name(&self) -> &String {
2850                            &self.firstlast_name"
2851                }
2852            );
2853
2854            assert_eq!(hl.highlights.len(), 6);
2855            assert_eq!(hl.highlights[0], ((4..9), deletion_style));
2856            assert_eq!(hl.highlights[1], ((9..13), insertion_style));
2857            assert_eq!(hl.highlights[2], ((52..57), deletion_style));
2858            assert_eq!(hl.highlights[3], ((57..61), insertion_style));
2859            assert_eq!(hl.highlights[4], ((101..106), deletion_style));
2860            assert_eq!(hl.highlights[5], ((106..110), insertion_style));
2861        },
2862    )
2863    .await;
2864
2865    async fn assert_preview_edits(
2866        text: &str,
2867        edits: Vec<(Range<Point>, &str)>,
2868        include_deletions: bool,
2869        cx: &mut TestAppContext,
2870        assert_fn: impl Fn(HighlightedText),
2871    ) {
2872        let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
2873        let edits = buffer.read_with(cx, |buffer, _| {
2874            edits
2875                .into_iter()
2876                .map(|(range, text)| {
2877                    (
2878                        buffer.anchor_before(range.start)..buffer.anchor_after(range.end),
2879                        text.to_string(),
2880                    )
2881                })
2882                .collect::<Vec<_>>()
2883        });
2884        let edit_preview = buffer
2885            .read_with(cx, |buffer, cx| {
2886                buffer.preview_edits(edits.clone().into(), cx)
2887            })
2888            .await;
2889        let highlighted_edits = cx.read(|cx| {
2890            edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, include_deletions, cx)
2891        });
2892        assert_fn(highlighted_edits);
2893    }
2894}
2895
2896#[gpui::test(iterations = 100)]
2897fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
2898    let min_peers = env::var("MIN_PEERS")
2899        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2900        .unwrap_or(1);
2901    let max_peers = env::var("MAX_PEERS")
2902        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2903        .unwrap_or(5);
2904    let operations = env::var("OPERATIONS")
2905        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2906        .unwrap_or(10);
2907
2908    let base_text_len = rng.gen_range(0..10);
2909    let base_text = RandomCharIter::new(&mut rng)
2910        .take(base_text_len)
2911        .collect::<String>();
2912    let mut replica_ids = Vec::new();
2913    let mut buffers = Vec::new();
2914    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2915    let base_buffer = cx.new(|cx| Buffer::local(base_text.as_str(), cx));
2916
2917    for i in 0..rng.gen_range(min_peers..=max_peers) {
2918        let buffer = cx.new(|cx| {
2919            let state = base_buffer.read(cx).to_proto(cx);
2920            let ops = cx
2921                .background_executor()
2922                .block(base_buffer.read(cx).serialize_ops(None, cx));
2923            let mut buffer =
2924                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2925            buffer.apply_ops(
2926                ops.into_iter()
2927                    .map(|op| proto::deserialize_operation(op).unwrap()),
2928                cx,
2929            );
2930            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2931            let network = network.clone();
2932            cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
2933                if let BufferEvent::Operation {
2934                    operation,
2935                    is_local: true,
2936                } = event
2937                {
2938                    network.lock().broadcast(
2939                        buffer.replica_id(),
2940                        vec![proto::serialize_operation(operation)],
2941                    );
2942                }
2943            })
2944            .detach();
2945            buffer
2946        });
2947
2948        buffers.push(buffer);
2949        replica_ids.push(i as ReplicaId);
2950        network.lock().add_peer(i as ReplicaId);
2951        log::info!("Adding initial peer with replica id {}", i);
2952    }
2953
2954    log::info!("initial text: {:?}", base_text);
2955
2956    let mut now = Instant::now();
2957    let mut mutation_count = operations;
2958    let mut next_diagnostic_id = 0;
2959    let mut active_selections = BTreeMap::default();
2960    loop {
2961        let replica_index = rng.gen_range(0..replica_ids.len());
2962        let replica_id = replica_ids[replica_index];
2963        let buffer = &mut buffers[replica_index];
2964        let mut new_buffer = None;
2965        match rng.gen_range(0..100) {
2966            0..=29 if mutation_count != 0 => {
2967                buffer.update(cx, |buffer, cx| {
2968                    buffer.start_transaction_at(now);
2969                    buffer.randomly_edit(&mut rng, 5, cx);
2970                    buffer.end_transaction_at(now, cx);
2971                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2972                });
2973                mutation_count -= 1;
2974            }
2975            30..=39 if mutation_count != 0 => {
2976                buffer.update(cx, |buffer, cx| {
2977                    if rng.gen_bool(0.2) {
2978                        log::info!("peer {} clearing active selections", replica_id);
2979                        active_selections.remove(&replica_id);
2980                        buffer.remove_active_selections(cx);
2981                    } else {
2982                        let mut selections = Vec::new();
2983                        for id in 0..rng.gen_range(1..=5) {
2984                            let range = buffer.random_byte_range(0, &mut rng);
2985                            selections.push(Selection {
2986                                id,
2987                                start: buffer.anchor_before(range.start),
2988                                end: buffer.anchor_before(range.end),
2989                                reversed: false,
2990                                goal: SelectionGoal::None,
2991                            });
2992                        }
2993                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2994                        log::info!(
2995                            "peer {} setting active selections: {:?}",
2996                            replica_id,
2997                            selections
2998                        );
2999                        active_selections.insert(replica_id, selections.clone());
3000                        buffer.set_active_selections(selections, false, Default::default(), cx);
3001                    }
3002                });
3003                mutation_count -= 1;
3004            }
3005            40..=49 if mutation_count != 0 && replica_id == 0 => {
3006                let entry_count = rng.gen_range(1..=5);
3007                buffer.update(cx, |buffer, cx| {
3008                    let diagnostics = DiagnosticSet::new(
3009                        (0..entry_count).map(|_| {
3010                            let range = buffer.random_byte_range(0, &mut rng);
3011                            let range = range.to_point_utf16(buffer);
3012                            let range = range.start..range.end;
3013                            DiagnosticEntry {
3014                                range,
3015                                diagnostic: Diagnostic {
3016                                    message: post_inc(&mut next_diagnostic_id).to_string(),
3017                                    ..Default::default()
3018                                },
3019                            }
3020                        }),
3021                        buffer,
3022                    );
3023                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
3024                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
3025                });
3026                mutation_count -= 1;
3027            }
3028            50..=59 if replica_ids.len() < max_peers => {
3029                let old_buffer_state = buffer.read(cx).to_proto(cx);
3030                let old_buffer_ops = cx
3031                    .background_executor()
3032                    .block(buffer.read(cx).serialize_ops(None, cx));
3033                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
3034                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
3035                    .choose(&mut rng)
3036                    .unwrap();
3037                log::info!(
3038                    "Adding new replica {} (replicating from {})",
3039                    new_replica_id,
3040                    replica_id
3041                );
3042                new_buffer = Some(cx.new(|cx| {
3043                    let mut new_buffer = Buffer::from_proto(
3044                        new_replica_id,
3045                        Capability::ReadWrite,
3046                        old_buffer_state,
3047                        None,
3048                    )
3049                    .unwrap();
3050                    new_buffer.apply_ops(
3051                        old_buffer_ops
3052                            .into_iter()
3053                            .map(|op| deserialize_operation(op).unwrap()),
3054                        cx,
3055                    );
3056                    log::info!(
3057                        "New replica {} text: {:?}",
3058                        new_buffer.replica_id(),
3059                        new_buffer.text()
3060                    );
3061                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
3062                    let network = network.clone();
3063                    cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
3064                        if let BufferEvent::Operation {
3065                            operation,
3066                            is_local: true,
3067                        } = event
3068                        {
3069                            network.lock().broadcast(
3070                                buffer.replica_id(),
3071                                vec![proto::serialize_operation(operation)],
3072                            );
3073                        }
3074                    })
3075                    .detach();
3076                    new_buffer
3077                }));
3078                network.lock().replicate(replica_id, new_replica_id);
3079
3080                if new_replica_id as usize == replica_ids.len() {
3081                    replica_ids.push(new_replica_id);
3082                } else {
3083                    let new_buffer = new_buffer.take().unwrap();
3084                    while network.lock().has_unreceived(new_replica_id) {
3085                        let ops = network
3086                            .lock()
3087                            .receive(new_replica_id)
3088                            .into_iter()
3089                            .map(|op| proto::deserialize_operation(op).unwrap());
3090                        if ops.len() > 0 {
3091                            log::info!(
3092                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3093                                new_replica_id,
3094                                buffer.read(cx).version(),
3095                                ops.len(),
3096                                ops
3097                            );
3098                            new_buffer.update(cx, |new_buffer, cx| {
3099                                new_buffer.apply_ops(ops, cx);
3100                            });
3101                        }
3102                    }
3103                    buffers[new_replica_id as usize] = new_buffer;
3104                }
3105            }
3106            60..=69 if mutation_count != 0 => {
3107                buffer.update(cx, |buffer, cx| {
3108                    buffer.randomly_undo_redo(&mut rng, cx);
3109                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
3110                });
3111                mutation_count -= 1;
3112            }
3113            _ if network.lock().has_unreceived(replica_id) => {
3114                let ops = network
3115                    .lock()
3116                    .receive(replica_id)
3117                    .into_iter()
3118                    .map(|op| proto::deserialize_operation(op).unwrap());
3119                if ops.len() > 0 {
3120                    log::info!(
3121                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3122                        replica_id,
3123                        buffer.read(cx).version(),
3124                        ops.len(),
3125                        ops
3126                    );
3127                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx));
3128                }
3129            }
3130            _ => {}
3131        }
3132
3133        now += Duration::from_millis(rng.gen_range(0..=200));
3134        buffers.extend(new_buffer);
3135
3136        for buffer in &buffers {
3137            buffer.read(cx).check_invariants();
3138        }
3139
3140        if mutation_count == 0 && network.lock().is_idle() {
3141            break;
3142        }
3143    }
3144
3145    let first_buffer = buffers[0].read(cx).snapshot();
3146    for buffer in &buffers[1..] {
3147        let buffer = buffer.read(cx).snapshot();
3148        assert_eq!(
3149            buffer.version(),
3150            first_buffer.version(),
3151            "Replica {} version != Replica 0 version",
3152            buffer.replica_id()
3153        );
3154        assert_eq!(
3155            buffer.text(),
3156            first_buffer.text(),
3157            "Replica {} text != Replica 0 text",
3158            buffer.replica_id()
3159        );
3160        assert_eq!(
3161            buffer
3162                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
3163                .collect::<Vec<_>>(),
3164            first_buffer
3165                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
3166                .collect::<Vec<_>>(),
3167            "Replica {} diagnostics != Replica 0 diagnostics",
3168            buffer.replica_id()
3169        );
3170    }
3171
3172    for buffer in &buffers {
3173        let buffer = buffer.read(cx).snapshot();
3174        let actual_remote_selections = buffer
3175            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
3176            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
3177            .collect::<Vec<_>>();
3178        let expected_remote_selections = active_selections
3179            .iter()
3180            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
3181            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
3182            .collect::<Vec<_>>();
3183        assert_eq!(
3184            actual_remote_selections,
3185            expected_remote_selections,
3186            "Replica {} remote selections != expected selections",
3187            buffer.replica_id()
3188        );
3189    }
3190}
3191
3192#[test]
3193fn test_contiguous_ranges() {
3194    assert_eq!(
3195        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
3196        &[1..4, 5..7, 9..13]
3197    );
3198
3199    // Respects the `max_len` parameter
3200    assert_eq!(
3201        contiguous_ranges(
3202            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
3203            3
3204        )
3205        .collect::<Vec<_>>(),
3206        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
3207    );
3208}
3209
3210#[gpui::test(iterations = 500)]
3211fn test_trailing_whitespace_ranges(mut rng: StdRng) {
3212    // Generate a random multi-line string containing
3213    // some lines with trailing whitespace.
3214    let mut text = String::new();
3215    for _ in 0..rng.gen_range(0..16) {
3216        for _ in 0..rng.gen_range(0..36) {
3217            text.push(match rng.gen_range(0..10) {
3218                0..=1 => ' ',
3219                3 => '\t',
3220                _ => rng.gen_range('a'..='z'),
3221            });
3222        }
3223        text.push('\n');
3224    }
3225
3226    match rng.gen_range(0..10) {
3227        // sometimes remove the last newline
3228        0..=1 => drop(text.pop()), //
3229
3230        // sometimes add extra newlines
3231        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
3232        _ => {}
3233    }
3234
3235    let rope = Rope::from(text.as_str());
3236    let actual_ranges = trailing_whitespace_ranges(&rope);
3237    let expected_ranges = TRAILING_WHITESPACE_REGEX
3238        .find_iter(&text)
3239        .map(|m| m.range())
3240        .collect::<Vec<_>>();
3241    assert_eq!(
3242        actual_ranges,
3243        expected_ranges,
3244        "wrong ranges for text lines:\n{:?}",
3245        text.split('\n').collect::<Vec<_>>()
3246    );
3247}
3248
3249#[gpui::test]
3250fn test_words_in_range(cx: &mut gpui::App) {
3251    init_settings(cx, |_| {});
3252
3253    // The first line are words excluded from the results with heuristics, we do not expect them in the test assertions.
3254    let contents = r#"
32550_isize 123 3.4 4  
3256let word=öäpple.bar你 Öäpple word2-öÄpPlE-Pizza-word ÖÄPPLE word
3257    "#;
3258
3259    let buffer = cx.new(|cx| {
3260        let buffer = Buffer::local(contents, cx).with_language(Arc::new(rust_lang()), cx);
3261        assert_eq!(buffer.text(), contents);
3262        buffer.check_invariants();
3263        buffer
3264    });
3265
3266    buffer.update(cx, |buffer, _| {
3267        let snapshot = buffer.snapshot();
3268        assert_eq!(
3269            BTreeSet::from_iter(["Pizza".to_string()]),
3270            snapshot
3271                .words_in_range(WordsQuery {
3272                    fuzzy_contents: Some("piz"),
3273                    skip_digits: true,
3274                    range: 0..snapshot.len(),
3275                })
3276                .into_keys()
3277                .collect::<BTreeSet<_>>()
3278        );
3279        assert_eq!(
3280            BTreeSet::from_iter([
3281                "öäpple".to_string(),
3282                "Öäpple".to_string(),
3283                "öÄpPlE".to_string(),
3284                "ÖÄPPLE".to_string(),
3285            ]),
3286            snapshot
3287                .words_in_range(WordsQuery {
3288                    fuzzy_contents: Some("öp"),
3289                    skip_digits: true,
3290                    range: 0..snapshot.len(),
3291                })
3292                .into_keys()
3293                .collect::<BTreeSet<_>>()
3294        );
3295        assert_eq!(
3296            BTreeSet::from_iter([
3297                "öÄpPlE".to_string(),
3298                "Öäpple".to_string(),
3299                "ÖÄPPLE".to_string(),
3300                "öäpple".to_string(),
3301            ]),
3302            snapshot
3303                .words_in_range(WordsQuery {
3304                    fuzzy_contents: Some("öÄ"),
3305                    skip_digits: true,
3306                    range: 0..snapshot.len(),
3307                })
3308                .into_keys()
3309                .collect::<BTreeSet<_>>()
3310        );
3311        assert_eq!(
3312            BTreeSet::default(),
3313            snapshot
3314                .words_in_range(WordsQuery {
3315                    fuzzy_contents: Some("öÄ好"),
3316                    skip_digits: true,
3317                    range: 0..snapshot.len(),
3318                })
3319                .into_keys()
3320                .collect::<BTreeSet<_>>()
3321        );
3322        assert_eq!(
3323            BTreeSet::from_iter(["bar你".to_string(),]),
3324            snapshot
3325                .words_in_range(WordsQuery {
3326                    fuzzy_contents: Some(""),
3327                    skip_digits: true,
3328                    range: 0..snapshot.len(),
3329                })
3330                .into_keys()
3331                .collect::<BTreeSet<_>>()
3332        );
3333        assert_eq!(
3334            BTreeSet::default(),
3335            snapshot
3336                .words_in_range(WordsQuery {
3337                    fuzzy_contents: Some(""),
3338                    skip_digits: true,
3339                    range: 0..snapshot.len(),
3340                },)
3341                .into_keys()
3342                .collect::<BTreeSet<_>>()
3343        );
3344        assert_eq!(
3345            BTreeSet::from_iter([
3346                "bar你".to_string(),
3347                "öÄpPlE".to_string(),
3348                "Öäpple".to_string(),
3349                "ÖÄPPLE".to_string(),
3350                "öäpple".to_string(),
3351                "let".to_string(),
3352                "Pizza".to_string(),
3353                "word".to_string(),
3354                "word2".to_string(),
3355            ]),
3356            snapshot
3357                .words_in_range(WordsQuery {
3358                    fuzzy_contents: None,
3359                    skip_digits: true,
3360                    range: 0..snapshot.len(),
3361                })
3362                .into_keys()
3363                .collect::<BTreeSet<_>>()
3364        );
3365        assert_eq!(
3366            BTreeSet::from_iter([
3367                "0_isize".to_string(),
3368                "123".to_string(),
3369                "3".to_string(),
3370                "4".to_string(),
3371                "bar你".to_string(),
3372                "öÄpPlE".to_string(),
3373                "Öäpple".to_string(),
3374                "ÖÄPPLE".to_string(),
3375                "öäpple".to_string(),
3376                "let".to_string(),
3377                "Pizza".to_string(),
3378                "word".to_string(),
3379                "word2".to_string(),
3380            ]),
3381            snapshot
3382                .words_in_range(WordsQuery {
3383                    fuzzy_contents: None,
3384                    skip_digits: false,
3385                    range: 0..snapshot.len(),
3386                })
3387                .into_keys()
3388                .collect::<BTreeSet<_>>()
3389        );
3390    });
3391}
3392
3393fn ruby_lang() -> Language {
3394    Language::new(
3395        LanguageConfig {
3396            name: "Ruby".into(),
3397            matcher: LanguageMatcher {
3398                path_suffixes: vec!["rb".to_string()],
3399                ..Default::default()
3400            },
3401            line_comments: vec!["# ".into()],
3402            ..Default::default()
3403        },
3404        Some(tree_sitter_ruby::LANGUAGE.into()),
3405    )
3406    .with_indents_query(
3407        r#"
3408            (class "end" @end) @indent
3409            (method "end" @end) @indent
3410            (rescue) @outdent
3411            (then) @indent
3412        "#,
3413    )
3414    .unwrap()
3415}
3416
3417fn html_lang() -> Language {
3418    Language::new(
3419        LanguageConfig {
3420            name: LanguageName::new("HTML"),
3421            block_comment: Some(("<!--".into(), "-->".into())),
3422            ..Default::default()
3423        },
3424        Some(tree_sitter_html::LANGUAGE.into()),
3425    )
3426    .with_indents_query(
3427        "
3428        (element
3429          (start_tag) @start
3430          (end_tag)? @end) @indent
3431        ",
3432    )
3433    .unwrap()
3434    .with_injection_query(
3435        r#"
3436        (script_element
3437            (raw_text) @injection.content
3438            (#set! injection.language "javascript"))
3439        "#,
3440    )
3441    .unwrap()
3442}
3443
3444fn erb_lang() -> Language {
3445    Language::new(
3446        LanguageConfig {
3447            name: "ERB".into(),
3448            matcher: LanguageMatcher {
3449                path_suffixes: vec!["erb".to_string()],
3450                ..Default::default()
3451            },
3452            block_comment: Some(("<%#".into(), "%>".into())),
3453            ..Default::default()
3454        },
3455        Some(tree_sitter_embedded_template::LANGUAGE.into()),
3456    )
3457    .with_injection_query(
3458        r#"
3459            (
3460                (code) @injection.content
3461                (#set! injection.language "ruby")
3462                (#set! injection.combined)
3463            )
3464
3465            (
3466                (content) @injection.content
3467                (#set! injection.language "html")
3468                (#set! injection.combined)
3469            )
3470        "#,
3471    )
3472    .unwrap()
3473}
3474
3475fn rust_lang() -> Language {
3476    Language::new(
3477        LanguageConfig {
3478            name: "Rust".into(),
3479            matcher: LanguageMatcher {
3480                path_suffixes: vec!["rs".to_string()],
3481                ..Default::default()
3482            },
3483            ..Default::default()
3484        },
3485        Some(tree_sitter_rust::LANGUAGE.into()),
3486    )
3487    .with_indents_query(
3488        r#"
3489        (call_expression) @indent
3490        (field_expression) @indent
3491        (_ "(" ")" @end) @indent
3492        (_ "{" "}" @end) @indent
3493        "#,
3494    )
3495    .unwrap()
3496    .with_brackets_query(
3497        r#"
3498        ("{" @open "}" @close)
3499        "#,
3500    )
3501    .unwrap()
3502    .with_text_object_query(
3503        r#"
3504        (function_item
3505            body: (_
3506                "{"
3507                (_)* @function.inside
3508                "}" )) @function.around
3509
3510        (line_comment)+ @comment.around
3511
3512        (block_comment) @comment.around
3513        "#,
3514    )
3515    .unwrap()
3516    .with_outline_query(
3517        r#"
3518        (line_comment) @annotation
3519
3520        (struct_item
3521            "struct" @context
3522            name: (_) @name) @item
3523        (enum_item
3524            "enum" @context
3525            name: (_) @name) @item
3526        (enum_variant
3527            name: (_) @name) @item
3528        (field_declaration
3529            name: (_) @name) @item
3530        (impl_item
3531            "impl" @context
3532            trait: (_)? @name
3533            "for"? @context
3534            type: (_) @name
3535            body: (_ "{" (_)* "}")) @item
3536        (function_item
3537            "fn" @context
3538            name: (_) @name) @item
3539        (mod_item
3540            "mod" @context
3541            name: (_) @name) @item
3542        "#,
3543    )
3544    .unwrap()
3545}
3546
3547fn json_lang() -> Language {
3548    Language::new(
3549        LanguageConfig {
3550            name: "Json".into(),
3551            matcher: LanguageMatcher {
3552                path_suffixes: vec!["js".to_string()],
3553                ..Default::default()
3554            },
3555            ..Default::default()
3556        },
3557        Some(tree_sitter_json::LANGUAGE.into()),
3558    )
3559}
3560
3561fn javascript_lang() -> Language {
3562    Language::new(
3563        LanguageConfig {
3564            name: "JavaScript".into(),
3565            ..Default::default()
3566        },
3567        Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
3568    )
3569    .with_brackets_query(
3570        r#"
3571        ("{" @open "}" @close)
3572        ("(" @open ")" @close)
3573        "#,
3574    )
3575    .unwrap()
3576    .with_indents_query(
3577        r#"
3578        (object "}" @end) @indent
3579        "#,
3580    )
3581    .unwrap()
3582}
3583
3584pub fn markdown_lang() -> Language {
3585    Language::new(
3586        LanguageConfig {
3587            name: "Markdown".into(),
3588            matcher: LanguageMatcher {
3589                path_suffixes: vec!["md".into()],
3590                ..Default::default()
3591            },
3592            ..Default::default()
3593        },
3594        Some(tree_sitter_md::LANGUAGE.into()),
3595    )
3596    .with_injection_query(
3597        r#"
3598            (fenced_code_block
3599                (info_string
3600                    (language) @injection.language)
3601                (code_fence_content) @injection.content)
3602
3603                ((inline) @injection.content
3604                (#set! injection.language "markdown-inline"))
3605        "#,
3606    )
3607    .unwrap()
3608}
3609
3610pub fn markdown_inline_lang() -> Language {
3611    Language::new(
3612        LanguageConfig {
3613            name: "Markdown-Inline".into(),
3614            hidden: true,
3615            ..LanguageConfig::default()
3616        },
3617        Some(tree_sitter_md::INLINE_LANGUAGE.into()),
3618    )
3619    .with_highlights_query("(emphasis) @emphasis")
3620    .unwrap()
3621}
3622
3623fn get_tree_sexp(buffer: &Entity<Buffer>, cx: &mut gpui::TestAppContext) -> String {
3624    buffer.update(cx, |buffer, _| {
3625        let snapshot = buffer.snapshot();
3626        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
3627        layers[0].node().to_sexp()
3628    })
3629}
3630
3631// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
3632fn assert_bracket_pairs(
3633    selection_text: &'static str,
3634    bracket_pair_texts: Vec<&'static str>,
3635    language: Language,
3636    cx: &mut App,
3637) {
3638    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
3639    let buffer =
3640        cx.new(|cx| Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx));
3641    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
3642
3643    let selection_range = selection_ranges[0].clone();
3644
3645    let bracket_pairs = bracket_pair_texts
3646        .into_iter()
3647        .map(|pair_text| {
3648            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
3649            assert_eq!(bracket_text, expected_text);
3650            (ranges[0].clone(), ranges[1].clone())
3651        })
3652        .collect::<Vec<_>>();
3653
3654    assert_set_eq!(
3655        buffer
3656            .bracket_ranges(selection_range)
3657            .map(|pair| (pair.open_range, pair.close_range))
3658            .collect::<Vec<_>>(),
3659        bracket_pairs
3660    );
3661}
3662
3663fn init_settings(cx: &mut App, f: fn(&mut AllLanguageSettingsContent)) {
3664    let settings_store = SettingsStore::test(cx);
3665    cx.set_global(settings_store);
3666    crate::init(cx);
3667    cx.update_global::<SettingsStore, _>(|settings, cx| {
3668        settings.update_user_settings::<AllLanguageSettings>(cx, f);
3669    });
3670}