buffer_tests.rs

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