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