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::{AppContext, BorrowAppContext, Model};
  10use gpui::{Context, 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    time::{Duration, Instant},
  20};
  21use text::network::Network;
  22use text::{BufferId, LineEnding};
  23use text::{Point, ToPoint};
  24use unindent::Unindent as _;
  25use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  26
  27lazy_static! {
  28    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  29        .multi_line(true)
  30        .build()
  31        .unwrap();
  32}
  33
  34#[cfg(test)]
  35#[ctor::ctor]
  36fn init_logger() {
  37    if std::env::var("RUST_LOG").is_ok() {
  38        env_logger::init();
  39    }
  40}
  41
  42#[gpui::test]
  43fn test_line_endings(cx: &mut gpui::AppContext) {
  44    init_settings(cx, |_| {});
  45
  46    cx.new_model(|cx| {
  47        let mut buffer = Buffer::new(
  48            0,
  49            BufferId::new(cx.entity_id().as_u64()).unwrap(),
  50            "one\r\ntwo\rthree",
  51        )
  52        .with_language(Arc::new(rust_lang()), cx);
  53        assert_eq!(buffer.text(), "one\ntwo\nthree");
  54        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  55
  56        buffer.check_invariants();
  57        buffer.edit(
  58            [(buffer.len()..buffer.len(), "\r\nfour")],
  59            Some(AutoindentMode::EachLine),
  60            cx,
  61        );
  62        buffer.edit([(0..0, "zero\r\n")], None, cx);
  63        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  64        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  65        buffer.check_invariants();
  66
  67        buffer
  68    });
  69}
  70
  71#[gpui::test]
  72fn test_select_language(cx: &mut AppContext) {
  73    init_settings(cx, |_| {});
  74
  75    let registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
  76    registry.add(Arc::new(Language::new(
  77        LanguageConfig {
  78            name: "Rust".into(),
  79            matcher: LanguageMatcher {
  80                path_suffixes: vec!["rs".to_string()],
  81                ..Default::default()
  82            },
  83            ..Default::default()
  84        },
  85        Some(tree_sitter_rust::language()),
  86    )));
  87    registry.add(Arc::new(Language::new(
  88        LanguageConfig {
  89            name: "Make".into(),
  90            matcher: LanguageMatcher {
  91                path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  92                ..Default::default()
  93            },
  94            ..Default::default()
  95        },
  96        Some(tree_sitter_rust::language()),
  97    )));
  98
  99    // matching file extension
 100    assert_eq!(
 101        registry
 102            .language_for_file(&file("src/lib.rs"), None, cx)
 103            .now_or_never()
 104            .and_then(|l| Some(l.ok()?.name())),
 105        Some("Rust".into())
 106    );
 107    assert_eq!(
 108        registry
 109            .language_for_file(&file("src/lib.mk"), None, cx)
 110            .now_or_never()
 111            .and_then(|l| Some(l.ok()?.name())),
 112        Some("Make".into())
 113    );
 114
 115    // matching filename
 116    assert_eq!(
 117        registry
 118            .language_for_file(&file("src/Makefile"), None, cx)
 119            .now_or_never()
 120            .and_then(|l| Some(l.ok()?.name())),
 121        Some("Make".into())
 122    );
 123
 124    // matching suffix that is not the full file extension or filename
 125    assert_eq!(
 126        registry
 127            .language_for_file(&file("zed/cars"), None, cx)
 128            .now_or_never()
 129            .and_then(|l| Some(l.ok()?.name())),
 130        None
 131    );
 132    assert_eq!(
 133        registry
 134            .language_for_file(&file("zed/a.cars"), None, cx)
 135            .now_or_never()
 136            .and_then(|l| Some(l.ok()?.name())),
 137        None
 138    );
 139    assert_eq!(
 140        registry
 141            .language_for_file(&file("zed/sumk"), None, cx)
 142            .now_or_never()
 143            .and_then(|l| Some(l.ok()?.name())),
 144        None
 145    );
 146}
 147
 148#[gpui::test(iterations = 10)]
 149async fn test_first_line_pattern(cx: &mut TestAppContext) {
 150    cx.update(|cx| init_settings(cx, |_| {}));
 151
 152    let languages = LanguageRegistry::test(cx.executor());
 153    let languages = Arc::new(languages);
 154
 155    languages.register_test_language(LanguageConfig {
 156        name: "JavaScript".into(),
 157        matcher: LanguageMatcher {
 158            path_suffixes: vec!["js".into()],
 159            first_line_pattern: Some(Regex::new(r"\bnode\b").unwrap()),
 160        },
 161        ..Default::default()
 162    });
 163
 164    cx.read(|cx| languages.language_for_file(&file("the/script"), None, cx))
 165        .await
 166        .unwrap_err();
 167    cx.read(|cx| languages.language_for_file(&file("the/script"), Some(&"nothing".into()), cx))
 168        .await
 169        .unwrap_err();
 170    assert_eq!(
 171        cx.read(|cx| languages.language_for_file(
 172            &file("the/script"),
 173            Some(&"#!/bin/env node".into()),
 174            cx
 175        ))
 176        .await
 177        .unwrap()
 178        .name()
 179        .as_ref(),
 180        "JavaScript"
 181    );
 182}
 183
 184#[gpui::test]
 185async fn test_language_for_file_with_custom_file_types(cx: &mut TestAppContext) {
 186    cx.update(|cx| {
 187        init_settings(cx, |settings| {
 188            settings.file_types.extend([
 189                ("TypeScript".into(), vec!["js".into()]),
 190                ("C++".into(), vec!["c".into()]),
 191            ]);
 192        })
 193    });
 194
 195    let languages = Arc::new(LanguageRegistry::test(cx.executor()));
 196
 197    for config in [
 198        LanguageConfig {
 199            name: "JavaScript".into(),
 200            matcher: LanguageMatcher {
 201                path_suffixes: vec!["js".to_string()],
 202                ..Default::default()
 203            },
 204            ..Default::default()
 205        },
 206        LanguageConfig {
 207            name: "TypeScript".into(),
 208            matcher: LanguageMatcher {
 209                path_suffixes: vec!["js".to_string()],
 210                ..Default::default()
 211            },
 212            ..Default::default()
 213        },
 214        LanguageConfig {
 215            name: "C++".into(),
 216            matcher: LanguageMatcher {
 217                path_suffixes: vec!["cpp".to_string()],
 218                ..Default::default()
 219            },
 220            ..Default::default()
 221        },
 222        LanguageConfig {
 223            name: "C".into(),
 224            matcher: LanguageMatcher {
 225                path_suffixes: vec!["c".to_string()],
 226                ..Default::default()
 227            },
 228            ..Default::default()
 229        },
 230    ] {
 231        languages.add(Arc::new(Language::new(config, None)));
 232    }
 233
 234    let language = cx
 235        .read(|cx| languages.language_for_file(&file("foo.js"), None, cx))
 236        .await
 237        .unwrap();
 238    assert_eq!(language.name().as_ref(), "TypeScript");
 239    let language = cx
 240        .read(|cx| languages.language_for_file(&file("foo.c"), None, cx))
 241        .await
 242        .unwrap();
 243    assert_eq!(language.name().as_ref(), "C++");
 244}
 245
 246fn file(path: &str) -> Arc<dyn File> {
 247    Arc::new(TestFile {
 248        path: Path::new(path).into(),
 249        root_name: "zed".into(),
 250    })
 251}
 252
 253#[gpui::test]
 254fn test_edit_events(cx: &mut gpui::AppContext) {
 255    let mut now = Instant::now();
 256    let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
 257    let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
 258
 259    let buffer1 = cx
 260        .new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
 261    let buffer2 = cx
 262        .new_model(|cx| Buffer::new(1, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abcdef"));
 263    let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
 264    buffer1.update(cx, {
 265        let buffer1_ops = buffer1_ops.clone();
 266        |buffer, cx| {
 267            let buffer_1_events = buffer_1_events.clone();
 268            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 269                Event::Operation(op) => buffer1_ops.lock().push(op),
 270                event => buffer_1_events.lock().push(event),
 271            })
 272            .detach();
 273            let buffer_2_events = buffer_2_events.clone();
 274            cx.subscribe(&buffer2, move |_, _, event, _| {
 275                buffer_2_events.lock().push(event.clone())
 276            })
 277            .detach();
 278
 279            // An edit emits an edited event, followed by a dirty changed event,
 280            // since the buffer was previously in a clean state.
 281            buffer.edit([(2..4, "XYZ")], None, cx);
 282
 283            // An empty transaction does not emit any events.
 284            buffer.start_transaction();
 285            buffer.end_transaction(cx);
 286
 287            // A transaction containing two edits emits one edited event.
 288            now += Duration::from_secs(1);
 289            buffer.start_transaction_at(now);
 290            buffer.edit([(5..5, "u")], None, cx);
 291            buffer.edit([(6..6, "w")], None, cx);
 292            buffer.end_transaction_at(now, cx);
 293
 294            // Undoing a transaction emits one edited event.
 295            buffer.undo(cx);
 296        }
 297    });
 298
 299    // Incorporating a set of remote ops emits a single edited event,
 300    // followed by a dirty changed event.
 301    buffer2.update(cx, |buffer, cx| {
 302        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 303    });
 304    assert_eq!(
 305        mem::take(&mut *buffer_1_events.lock()),
 306        vec![
 307            Event::Edited,
 308            Event::DirtyChanged,
 309            Event::Edited,
 310            Event::Edited,
 311        ]
 312    );
 313    assert_eq!(
 314        mem::take(&mut *buffer_2_events.lock()),
 315        vec![Event::Edited, Event::DirtyChanged]
 316    );
 317
 318    buffer1.update(cx, |buffer, cx| {
 319        // Undoing the first transaction emits edited event, followed by a
 320        // dirty changed event, since the buffer is again in a clean state.
 321        buffer.undo(cx);
 322    });
 323    // Incorporating the remote ops again emits a single edited event,
 324    // followed by a dirty changed event.
 325    buffer2.update(cx, |buffer, cx| {
 326        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 327    });
 328    assert_eq!(
 329        mem::take(&mut *buffer_1_events.lock()),
 330        vec![Event::Edited, Event::DirtyChanged,]
 331    );
 332    assert_eq!(
 333        mem::take(&mut *buffer_2_events.lock()),
 334        vec![Event::Edited, Event::DirtyChanged]
 335    );
 336}
 337
 338#[gpui::test]
 339async fn test_apply_diff(cx: &mut TestAppContext) {
 340    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 341    let buffer =
 342        cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
 343    let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 344
 345    let text = "a\nccc\ndddd\nffffff\n";
 346    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 347    buffer.update(cx, |buffer, cx| {
 348        buffer.apply_diff(diff, cx).unwrap();
 349        assert_eq!(buffer.text(), text);
 350        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 351    });
 352
 353    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 354    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 355    buffer.update(cx, |buffer, cx| {
 356        buffer.apply_diff(diff, cx).unwrap();
 357        assert_eq!(buffer.text(), text);
 358        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 359    });
 360}
 361
 362#[gpui::test(iterations = 10)]
 363async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 364    let text = [
 365        "zero",     //
 366        "one  ",    // 2 trailing spaces
 367        "two",      //
 368        "three   ", // 3 trailing spaces
 369        "four",     //
 370        "five    ", // 4 trailing spaces
 371    ]
 372    .join("\n");
 373
 374    let buffer =
 375        cx.new_model(|cx| Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text));
 376
 377    // Spawn a task to format the buffer's whitespace.
 378    // Pause so that the foratting task starts running.
 379    let format = buffer.update(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 380    smol::future::yield_now().await;
 381
 382    // Edit the buffer while the normalization task is running.
 383    let version_before_edit = buffer.update(cx, |buffer, _| buffer.version());
 384    buffer.update(cx, |buffer, cx| {
 385        buffer.edit(
 386            [
 387                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 388                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 389            ],
 390            None,
 391            cx,
 392        );
 393    });
 394
 395    let format_diff = format.await;
 396    buffer.update(cx, |buffer, cx| {
 397        let version_before_format = format_diff.base_version.clone();
 398        buffer.apply_diff(format_diff, cx);
 399
 400        // The outcome depends on the order of concurrent tasks.
 401        //
 402        // If the edit occurred while searching for trailing whitespace ranges,
 403        // then the trailing whitespace region touched by the edit is left intact.
 404        if version_before_format == version_before_edit {
 405            assert_eq!(
 406                buffer.text(),
 407                [
 408                    "zEEero",      //
 409                    "one",         //
 410                    "two",         //
 411                    "threeEEE   ", //
 412                    "four",        //
 413                    "five",        //
 414                ]
 415                .join("\n")
 416            );
 417        }
 418        // Otherwise, all trailing whitespace is removed.
 419        else {
 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    });
 434}
 435
 436#[gpui::test]
 437async fn test_reparse(cx: &mut gpui::TestAppContext) {
 438    let text = "fn a() {}";
 439    let buffer = cx.new_model(|cx| {
 440        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 441            .with_language(Arc::new(rust_lang()), cx)
 442    });
 443
 444    // Wait for the initial text to parse
 445    cx.executor().run_until_parked();
 446    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 447    assert_eq!(
 448        get_tree_sexp(&buffer, cx),
 449        concat!(
 450            "(source_file (function_item name: (identifier) ",
 451            "parameters: (parameters) ",
 452            "body: (block)))"
 453        )
 454    );
 455
 456    buffer.update(cx, |buffer, _| {
 457        buffer.set_sync_parse_timeout(Duration::ZERO)
 458    });
 459
 460    // Perform some edits (add parameter and variable reference)
 461    // Parsing doesn't begin until the transaction is complete
 462    buffer.update(cx, |buf, cx| {
 463        buf.start_transaction();
 464
 465        let offset = buf.text().find(')').unwrap();
 466        buf.edit([(offset..offset, "b: C")], None, cx);
 467        assert!(!buf.is_parsing());
 468
 469        let offset = buf.text().find('}').unwrap();
 470        buf.edit([(offset..offset, " d; ")], None, cx);
 471        assert!(!buf.is_parsing());
 472
 473        buf.end_transaction(cx);
 474        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 475        assert!(buf.is_parsing());
 476    });
 477    cx.executor().run_until_parked();
 478    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 479    assert_eq!(
 480        get_tree_sexp(&buffer, cx),
 481        concat!(
 482            "(source_file (function_item name: (identifier) ",
 483            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 484            "body: (block (expression_statement (identifier)))))"
 485        )
 486    );
 487
 488    // Perform a series of edits without waiting for the current parse to complete:
 489    // * turn identifier into a field expression
 490    // * turn field expression into a method call
 491    // * add a turbofish to the method call
 492    buffer.update(cx, |buf, cx| {
 493        let offset = buf.text().find(';').unwrap();
 494        buf.edit([(offset..offset, ".e")], None, cx);
 495        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 496        assert!(buf.is_parsing());
 497    });
 498    buffer.update(cx, |buf, cx| {
 499        let offset = buf.text().find(';').unwrap();
 500        buf.edit([(offset..offset, "(f)")], None, cx);
 501        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 502        assert!(buf.is_parsing());
 503    });
 504    buffer.update(cx, |buf, cx| {
 505        let offset = buf.text().find("(f)").unwrap();
 506        buf.edit([(offset..offset, "::<G>")], None, cx);
 507        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 508        assert!(buf.is_parsing());
 509    });
 510    cx.executor().run_until_parked();
 511    assert_eq!(
 512        get_tree_sexp(&buffer, cx),
 513        concat!(
 514            "(source_file (function_item name: (identifier) ",
 515            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 516            "body: (block (expression_statement (call_expression ",
 517            "function: (generic_function ",
 518            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 519            "type_arguments: (type_arguments (type_identifier))) ",
 520            "arguments: (arguments (identifier)))))))",
 521        )
 522    );
 523
 524    buffer.update(cx, |buf, cx| {
 525        buf.undo(cx);
 526        buf.undo(cx);
 527        buf.undo(cx);
 528        buf.undo(cx);
 529        assert_eq!(buf.text(), "fn a() {}");
 530        assert!(buf.is_parsing());
 531    });
 532
 533    cx.executor().run_until_parked();
 534    assert_eq!(
 535        get_tree_sexp(&buffer, cx),
 536        concat!(
 537            "(source_file (function_item name: (identifier) ",
 538            "parameters: (parameters) ",
 539            "body: (block)))"
 540        )
 541    );
 542
 543    buffer.update(cx, |buf, cx| {
 544        buf.redo(cx);
 545        buf.redo(cx);
 546        buf.redo(cx);
 547        buf.redo(cx);
 548        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 549        assert!(buf.is_parsing());
 550    });
 551    cx.executor().run_until_parked();
 552    assert_eq!(
 553        get_tree_sexp(&buffer, cx),
 554        concat!(
 555            "(source_file (function_item name: (identifier) ",
 556            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 557            "body: (block (expression_statement (call_expression ",
 558            "function: (generic_function ",
 559            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 560            "type_arguments: (type_arguments (type_identifier))) ",
 561            "arguments: (arguments (identifier)))))))",
 562        )
 563    );
 564}
 565
 566#[gpui::test]
 567async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 568    let buffer = cx.new_model(|cx| {
 569        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "{}")
 570            .with_language(Arc::new(rust_lang()), cx);
 571        buffer.set_sync_parse_timeout(Duration::ZERO);
 572        buffer
 573    });
 574
 575    // Wait for the initial text to parse
 576    cx.executor().run_until_parked();
 577    assert_eq!(
 578        get_tree_sexp(&buffer, cx),
 579        "(source_file (expression_statement (block)))"
 580    );
 581
 582    buffer.update(cx, |buffer, cx| {
 583        buffer.set_language(Some(Arc::new(json_lang())), cx)
 584    });
 585    cx.executor().run_until_parked();
 586    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 587}
 588
 589#[gpui::test]
 590async fn test_outline(cx: &mut gpui::TestAppContext) {
 591    let text = r#"
 592        struct Person {
 593            name: String,
 594            age: usize,
 595        }
 596
 597        mod module {
 598            enum LoginState {
 599                LoggedOut,
 600                LoggingOn,
 601                LoggedIn {
 602                    person: Person,
 603                    time: Instant,
 604                }
 605            }
 606        }
 607
 608        impl Eq for Person {}
 609
 610        impl Drop for Person {
 611            fn drop(&mut self) {
 612                println!("bye");
 613            }
 614        }
 615    "#
 616    .unindent();
 617
 618    let buffer = cx.new_model(|cx| {
 619        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 620            .with_language(Arc::new(rust_lang()), cx)
 621    });
 622    let outline = buffer
 623        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 624        .unwrap();
 625
 626    assert_eq!(
 627        outline
 628            .items
 629            .iter()
 630            .map(|item| (item.text.as_str(), item.depth))
 631            .collect::<Vec<_>>(),
 632        &[
 633            ("struct Person", 0),
 634            ("name", 1),
 635            ("age", 1),
 636            ("mod module", 0),
 637            ("enum LoginState", 1),
 638            ("LoggedOut", 2),
 639            ("LoggingOn", 2),
 640            ("LoggedIn", 2),
 641            ("person", 3),
 642            ("time", 3),
 643            ("impl Eq for Person", 0),
 644            ("impl Drop for Person", 0),
 645            ("fn drop", 1),
 646        ]
 647    );
 648
 649    // Without space, we only match on names
 650    assert_eq!(
 651        search(&outline, "oon", cx).await,
 652        &[
 653            ("mod module", vec![]),                    // included as the parent of a match
 654            ("enum LoginState", vec![]),               // included as the parent of a match
 655            ("LoggingOn", vec![1, 7, 8]),              // matches
 656            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 657        ]
 658    );
 659
 660    assert_eq!(
 661        search(&outline, "dp p", cx).await,
 662        &[
 663            ("impl Drop for Person", vec![5, 8, 9, 14]),
 664            ("fn drop", vec![]),
 665        ]
 666    );
 667    assert_eq!(
 668        search(&outline, "dpn", cx).await,
 669        &[("impl Drop for Person", vec![5, 14, 19])]
 670    );
 671    assert_eq!(
 672        search(&outline, "impl ", cx).await,
 673        &[
 674            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 675            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 676            ("fn drop", vec![]),
 677        ]
 678    );
 679
 680    async fn search<'a>(
 681        outline: &'a Outline<Anchor>,
 682        query: &'a str,
 683        cx: &'a gpui::TestAppContext,
 684    ) -> Vec<(&'a str, Vec<usize>)> {
 685        let matches = cx
 686            .update(|cx| outline.search(query, cx.background_executor().clone()))
 687            .await;
 688        matches
 689            .into_iter()
 690            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 691            .collect::<Vec<_>>()
 692    }
 693}
 694
 695#[gpui::test]
 696async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 697    let text = r#"
 698        impl A for B<
 699            C
 700        > {
 701        };
 702    "#
 703    .unindent();
 704
 705    let buffer = cx.new_model(|cx| {
 706        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 707            .with_language(Arc::new(rust_lang()), cx)
 708    });
 709    let outline = buffer
 710        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 711        .unwrap();
 712
 713    assert_eq!(
 714        outline
 715            .items
 716            .iter()
 717            .map(|item| (item.text.as_str(), item.depth))
 718            .collect::<Vec<_>>(),
 719        &[("impl A for B<", 0)]
 720    );
 721}
 722
 723#[gpui::test]
 724async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
 725    let language = javascript_lang()
 726        .with_outline_query(
 727            r#"
 728            (function_declaration
 729                "function" @context
 730                name: (_) @name
 731                parameters: (formal_parameters
 732                    "(" @context.extra
 733                    ")" @context.extra)) @item
 734            "#,
 735        )
 736        .unwrap();
 737
 738    let text = r#"
 739        function a() {}
 740        function b(c) {}
 741    "#
 742    .unindent();
 743
 744    let buffer = cx.new_model(|cx| {
 745        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 746            .with_language(Arc::new(language), cx)
 747    });
 748    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 749
 750    // extra context nodes are included in the outline.
 751    let outline = snapshot.outline(None).unwrap();
 752    assert_eq!(
 753        outline
 754            .items
 755            .iter()
 756            .map(|item| (item.text.as_str(), item.depth))
 757            .collect::<Vec<_>>(),
 758        &[("function a()", 0), ("function b( )", 0),]
 759    );
 760
 761    // extra context nodes do not appear in breadcrumbs.
 762    let symbols = snapshot.symbols_containing(3, None).unwrap();
 763    assert_eq!(
 764        symbols
 765            .iter()
 766            .map(|item| (item.text.as_str(), item.depth))
 767            .collect::<Vec<_>>(),
 768        &[("function a", 0)]
 769    );
 770}
 771
 772#[gpui::test]
 773async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 774    let text = r#"
 775        impl Person {
 776            fn one() {
 777                1
 778            }
 779
 780            fn two() {
 781                2
 782            }fn three() {
 783                3
 784            }
 785        }
 786    "#
 787    .unindent();
 788
 789    let buffer = cx.new_model(|cx| {
 790        Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
 791            .with_language(Arc::new(rust_lang()), cx)
 792    });
 793    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 794
 795    // point is at the start of an item
 796    assert_eq!(
 797        symbols_containing(Point::new(1, 4), &snapshot),
 798        vec![
 799            (
 800                "impl Person".to_string(),
 801                Point::new(0, 0)..Point::new(10, 1)
 802            ),
 803            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 804        ]
 805    );
 806
 807    // point is in the middle of an item
 808    assert_eq!(
 809        symbols_containing(Point::new(2, 8), &snapshot),
 810        vec![
 811            (
 812                "impl Person".to_string(),
 813                Point::new(0, 0)..Point::new(10, 1)
 814            ),
 815            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 816        ]
 817    );
 818
 819    // point is at the end of an item
 820    assert_eq!(
 821        symbols_containing(Point::new(3, 5), &snapshot),
 822        vec![
 823            (
 824                "impl Person".to_string(),
 825                Point::new(0, 0)..Point::new(10, 1)
 826            ),
 827            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 828        ]
 829    );
 830
 831    // point is in between two adjacent items
 832    assert_eq!(
 833        symbols_containing(Point::new(7, 5), &snapshot),
 834        vec![
 835            (
 836                "impl Person".to_string(),
 837                Point::new(0, 0)..Point::new(10, 1)
 838            ),
 839            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 840        ]
 841    );
 842
 843    fn symbols_containing(
 844        position: Point,
 845        snapshot: &BufferSnapshot,
 846    ) -> Vec<(String, Range<Point>)> {
 847        snapshot
 848            .symbols_containing(position, None)
 849            .unwrap()
 850            .into_iter()
 851            .map(|item| {
 852                (
 853                    item.text,
 854                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 855                )
 856            })
 857            .collect()
 858    }
 859}
 860
 861#[gpui::test]
 862fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 863    let mut assert = |selection_text, range_markers| {
 864        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 865    };
 866
 867    assert(
 868        indoc! {"
 869            mod x {
 870                moˇd y {
 871
 872                }
 873            }
 874            let foo = 1;"},
 875        vec![indoc! {"
 876            mod x «{»
 877                mod y {
 878
 879                }
 880            «}»
 881            let foo = 1;"}],
 882    );
 883
 884    assert(
 885        indoc! {"
 886            mod x {
 887                mod y ˇ{
 888
 889                }
 890            }
 891            let foo = 1;"},
 892        vec![
 893            indoc! {"
 894                mod x «{»
 895                    mod y {
 896
 897                    }
 898                «}»
 899                let foo = 1;"},
 900            indoc! {"
 901                mod x {
 902                    mod y «{»
 903
 904                    «}»
 905                }
 906                let foo = 1;"},
 907        ],
 908    );
 909
 910    assert(
 911        indoc! {"
 912            mod x {
 913                mod y {
 914
 915 916            }
 917            let foo = 1;"},
 918        vec![
 919            indoc! {"
 920                mod x «{»
 921                    mod y {
 922
 923                    }
 924                «}»
 925                let foo = 1;"},
 926            indoc! {"
 927                mod x {
 928                    mod y «{»
 929
 930                    «}»
 931                }
 932                let foo = 1;"},
 933        ],
 934    );
 935
 936    assert(
 937        indoc! {"
 938            mod x {
 939                mod y {
 940
 941                }
 942            ˇ}
 943            let foo = 1;"},
 944        vec![indoc! {"
 945            mod x «{»
 946                mod y {
 947
 948                }
 949            «}»
 950            let foo = 1;"}],
 951    );
 952
 953    assert(
 954        indoc! {"
 955            mod x {
 956                mod y {
 957
 958                }
 959            }
 960            let fˇoo = 1;"},
 961        vec![],
 962    );
 963
 964    // Regression test: avoid crash when querying at the end of the buffer.
 965    assert(
 966        indoc! {"
 967            mod x {
 968                mod y {
 969
 970                }
 971            }
 972            let foo = 1;ˇ"},
 973        vec![],
 974    );
 975}
 976
 977#[gpui::test]
 978fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 979    let mut assert = |selection_text, bracket_pair_texts| {
 980        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 981    };
 982
 983    assert(
 984        indoc! {"
 985        for (const a in b)ˇ {
 986            // a comment that's longer than the for-loop header
 987        }"},
 988        vec![indoc! {"
 989        for «(»const a in b«)» {
 990            // a comment that's longer than the for-loop header
 991        }"}],
 992    );
 993
 994    // Regression test: even though the parent node of the parentheses (the for loop) does
 995    // intersect the given range, the parentheses themselves do not contain the range, so
 996    // they should not be returned. Only the curly braces contain the range.
 997    assert(
 998        indoc! {"
 999        for (const a in b) {ˇ
1000            // a comment that's longer than the for-loop header
1001        }"},
1002        vec![indoc! {"
1003        for (const a in b) «{»
1004            // a comment that's longer than the for-loop header
1005        «}»"}],
1006    );
1007}
1008
1009#[gpui::test]
1010fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
1011    cx.new_model(|cx| {
1012        let text = "fn a() { b(|c| {}) }";
1013        let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1014            .with_language(Arc::new(rust_lang()), cx);
1015        let snapshot = buffer.snapshot();
1016
1017        assert_eq!(
1018            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
1019            Some(range_of(text, "|"))
1020        );
1021        assert_eq!(
1022            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
1023            Some(range_of(text, "|c|"))
1024        );
1025        assert_eq!(
1026            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
1027            Some(range_of(text, "|c| {}"))
1028        );
1029        assert_eq!(
1030            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
1031            Some(range_of(text, "(|c| {})"))
1032        );
1033
1034        buffer
1035    });
1036
1037    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
1038        let start = text.find(part).unwrap();
1039        start..start
1040    }
1041
1042    fn range_of(text: &str, part: &str) -> Range<usize> {
1043        let start = text.find(part).unwrap();
1044        start..start + part.len()
1045    }
1046}
1047
1048#[gpui::test]
1049fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
1050    init_settings(cx, |_| {});
1051
1052    cx.new_model(|cx| {
1053        let text = "fn a() {}";
1054        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1055            .with_language(Arc::new(rust_lang()), cx);
1056
1057        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1058        assert_eq!(buffer.text(), "fn a() {\n    \n}");
1059
1060        buffer.edit(
1061            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
1062            Some(AutoindentMode::EachLine),
1063            cx,
1064        );
1065        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
1066
1067        // Create a field expression on a new line, causing that line
1068        // to be indented.
1069        buffer.edit(
1070            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
1071            Some(AutoindentMode::EachLine),
1072            cx,
1073        );
1074        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
1075
1076        // Remove the dot so that the line is no longer a field expression,
1077        // causing the line to be outdented.
1078        buffer.edit(
1079            [(Point::new(2, 8)..Point::new(2, 9), "")],
1080            Some(AutoindentMode::EachLine),
1081            cx,
1082        );
1083        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
1084
1085        buffer
1086    });
1087}
1088
1089#[gpui::test]
1090fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
1091    init_settings(cx, |settings| {
1092        settings.defaults.hard_tabs = Some(true);
1093    });
1094
1095    cx.new_model(|cx| {
1096        let text = "fn a() {}";
1097        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1098            .with_language(Arc::new(rust_lang()), cx);
1099
1100        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1101        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
1102
1103        buffer.edit(
1104            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
1105            Some(AutoindentMode::EachLine),
1106            cx,
1107        );
1108        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1109
1110        // Create a field expression on a new line, causing that line
1111        // to be indented.
1112        buffer.edit(
1113            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1114            Some(AutoindentMode::EachLine),
1115            cx,
1116        );
1117        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1118
1119        // Remove the dot so that the line is no longer a field expression,
1120        // causing the line to be outdented.
1121        buffer.edit(
1122            [(Point::new(2, 2)..Point::new(2, 3), "")],
1123            Some(AutoindentMode::EachLine),
1124            cx,
1125        );
1126        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1127
1128        buffer
1129    });
1130}
1131
1132#[gpui::test]
1133fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1134    init_settings(cx, |_| {});
1135
1136    cx.new_model(|cx| {
1137        let mut buffer = Buffer::new(
1138            0,
1139            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1140            "
1141            fn a() {
1142            c;
1143            d;
1144            }
1145            "
1146            .unindent(),
1147        )
1148        .with_language(Arc::new(rust_lang()), cx);
1149
1150        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1151        // their indentation is not adjusted.
1152        buffer.edit_via_marked_text(
1153            &"
1154            fn a() {
1155            c«()»;
1156            d«()»;
1157            }
1158            "
1159            .unindent(),
1160            Some(AutoindentMode::EachLine),
1161            cx,
1162        );
1163        assert_eq!(
1164            buffer.text(),
1165            "
1166            fn a() {
1167            c();
1168            d();
1169            }
1170            "
1171            .unindent()
1172        );
1173
1174        // When appending new content after these lines, the indentation is based on the
1175        // preceding lines' actual indentation.
1176        buffer.edit_via_marked_text(
1177            &"
1178            fn a() {
11791180            .f
1181            .g()»;
11821183            .f
1184            .g()»;
1185            }
1186            "
1187            .unindent(),
1188            Some(AutoindentMode::EachLine),
1189            cx,
1190        );
1191
1192        assert_eq!(
1193            buffer.text(),
1194            "
1195            fn a() {
1196            c
1197                .f
1198                .g();
1199            d
1200                .f
1201                .g();
1202            }
1203            "
1204            .unindent()
1205        );
1206        buffer
1207    });
1208
1209    cx.new_model(|cx| {
1210        eprintln!("second buffer: {:?}", cx.entity_id());
1211
1212        let mut buffer = Buffer::new(
1213            0,
1214            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1215            "
1216            fn a() {
1217                b();
1218                |
1219            "
1220            .replace('|', "") // marker to preserve trailing whitespace
1221            .unindent(),
1222        )
1223        .with_language(Arc::new(rust_lang()), cx);
1224
1225        // Insert a closing brace. It is outdented.
1226        buffer.edit_via_marked_text(
1227            &"
1228            fn a() {
1229                b();
1230                «}»
1231            "
1232            .unindent(),
1233            Some(AutoindentMode::EachLine),
1234            cx,
1235        );
1236        assert_eq!(
1237            buffer.text(),
1238            "
1239            fn a() {
1240                b();
1241            }
1242            "
1243            .unindent()
1244        );
1245
1246        // Manually edit the leading whitespace. The edit is preserved.
1247        buffer.edit_via_marked_text(
1248            &"
1249            fn a() {
1250                b();
1251            «    »}
1252            "
1253            .unindent(),
1254            Some(AutoindentMode::EachLine),
1255            cx,
1256        );
1257        assert_eq!(
1258            buffer.text(),
1259            "
1260            fn a() {
1261                b();
1262                }
1263            "
1264            .unindent()
1265        );
1266        buffer
1267    });
1268
1269    eprintln!("DONE");
1270}
1271
1272#[gpui::test]
1273fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1274    init_settings(cx, |_| {});
1275
1276    cx.new_model(|cx| {
1277        let mut buffer = Buffer::new(
1278            0,
1279            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1280            "
1281            fn a() {
1282                i
1283            }
1284            "
1285            .unindent(),
1286        )
1287        .with_language(Arc::new(rust_lang()), cx);
1288
1289        // Regression test: line does not get outdented due to syntax error
1290        buffer.edit_via_marked_text(
1291            &"
1292            fn a() {
1293                i«f let Some(x) = y»
1294            }
1295            "
1296            .unindent(),
1297            Some(AutoindentMode::EachLine),
1298            cx,
1299        );
1300        assert_eq!(
1301            buffer.text(),
1302            "
1303            fn a() {
1304                if let Some(x) = y
1305            }
1306            "
1307            .unindent()
1308        );
1309
1310        buffer.edit_via_marked_text(
1311            &"
1312            fn a() {
1313                if let Some(x) = y« {»
1314            }
1315            "
1316            .unindent(),
1317            Some(AutoindentMode::EachLine),
1318            cx,
1319        );
1320        assert_eq!(
1321            buffer.text(),
1322            "
1323            fn a() {
1324                if let Some(x) = y {
1325            }
1326            "
1327            .unindent()
1328        );
1329
1330        buffer
1331    });
1332}
1333
1334#[gpui::test]
1335fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1336    init_settings(cx, |_| {});
1337
1338    cx.new_model(|cx| {
1339        let mut buffer = Buffer::new(
1340            0,
1341            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1342            "
1343            fn a() {}
1344            "
1345            .unindent(),
1346        )
1347        .with_language(Arc::new(rust_lang()), cx);
1348
1349        buffer.edit_via_marked_text(
1350            &"
1351            fn a(«
1352            b») {}
1353            "
1354            .unindent(),
1355            Some(AutoindentMode::EachLine),
1356            cx,
1357        );
1358        assert_eq!(
1359            buffer.text(),
1360            "
1361            fn a(
1362                b) {}
1363            "
1364            .unindent()
1365        );
1366
1367        // The indentation suggestion changed because `@end` node (a close paren)
1368        // is now at the beginning of the line.
1369        buffer.edit_via_marked_text(
1370            &"
1371            fn a(
1372                ˇ) {}
1373            "
1374            .unindent(),
1375            Some(AutoindentMode::EachLine),
1376            cx,
1377        );
1378        assert_eq!(
1379            buffer.text(),
1380            "
1381                fn a(
1382                ) {}
1383            "
1384            .unindent()
1385        );
1386
1387        buffer
1388    });
1389}
1390
1391#[gpui::test]
1392fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1393    init_settings(cx, |_| {});
1394
1395    cx.new_model(|cx| {
1396        let text = "a\nb";
1397        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1398            .with_language(Arc::new(rust_lang()), cx);
1399        buffer.edit(
1400            [(0..1, "\n"), (2..3, "\n")],
1401            Some(AutoindentMode::EachLine),
1402            cx,
1403        );
1404        assert_eq!(buffer.text(), "\n\n\n");
1405        buffer
1406    });
1407}
1408
1409#[gpui::test]
1410fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1411    init_settings(cx, |_| {});
1412
1413    cx.new_model(|cx| {
1414        let text = "
1415            const a: usize = 1;
1416            fn b() {
1417                if c {
1418                    let d = 2;
1419                }
1420            }
1421        "
1422        .unindent();
1423
1424        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1425            .with_language(Arc::new(rust_lang()), cx);
1426        buffer.edit(
1427            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1428            Some(AutoindentMode::EachLine),
1429            cx,
1430        );
1431        assert_eq!(
1432            buffer.text(),
1433            "
1434                const a: usize = 1;
1435                fn b() {
1436                    if c {
1437                        e(
1438                            f()
1439                        );
1440                        let d = 2;
1441                    }
1442                }
1443            "
1444            .unindent()
1445        );
1446
1447        buffer
1448    });
1449}
1450
1451#[gpui::test]
1452fn test_autoindent_block_mode(cx: &mut AppContext) {
1453    init_settings(cx, |_| {});
1454
1455    cx.new_model(|cx| {
1456        let text = r#"
1457            fn a() {
1458                b();
1459            }
1460        "#
1461        .unindent();
1462        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1463            .with_language(Arc::new(rust_lang()), cx);
1464
1465        // When this text was copied, both of the quotation marks were at the same
1466        // indent level, but the indentation of the first line was not included in
1467        // the copied text. This information is retained in the
1468        // 'original_indent_columns' vector.
1469        let original_indent_columns = vec![4];
1470        let inserted_text = r#"
1471            "
1472                  c
1473                    d
1474                      e
1475                "
1476        "#
1477        .unindent();
1478
1479        // Insert the block at column zero. The entire block is indented
1480        // so that the first line matches the previous line's indentation.
1481        buffer.edit(
1482            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1483            Some(AutoindentMode::Block {
1484                original_indent_columns: original_indent_columns.clone(),
1485            }),
1486            cx,
1487        );
1488        assert_eq!(
1489            buffer.text(),
1490            r#"
1491            fn a() {
1492                b();
1493                "
1494                  c
1495                    d
1496                      e
1497                "
1498            }
1499            "#
1500            .unindent()
1501        );
1502
1503        // Grouping is disabled in tests, so we need 2 undos
1504        buffer.undo(cx); // Undo the auto-indent
1505        buffer.undo(cx); // Undo the original edit
1506
1507        // Insert the block at a deeper indent level. The entire block is outdented.
1508        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1509        buffer.edit(
1510            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1511            Some(AutoindentMode::Block {
1512                original_indent_columns: original_indent_columns.clone(),
1513            }),
1514            cx,
1515        );
1516        assert_eq!(
1517            buffer.text(),
1518            r#"
1519            fn a() {
1520                b();
1521                "
1522                  c
1523                    d
1524                      e
1525                "
1526            }
1527            "#
1528            .unindent()
1529        );
1530
1531        buffer
1532    });
1533}
1534
1535#[gpui::test]
1536fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1537    init_settings(cx, |_| {});
1538
1539    cx.new_model(|cx| {
1540        let text = r#"
1541            fn a() {
1542                if b() {
1543
1544                }
1545            }
1546        "#
1547        .unindent();
1548        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1549            .with_language(Arc::new(rust_lang()), cx);
1550
1551        // The original indent columns are not known, so this text is
1552        // auto-indented in a block as if the first line was copied in
1553        // its entirety.
1554        let original_indent_columns = Vec::new();
1555        let inserted_text = "    c\n        .d()\n        .e();";
1556
1557        // Insert the block at column zero. The entire block is indented
1558        // so that the first line matches the previous line's indentation.
1559        buffer.edit(
1560            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1561            Some(AutoindentMode::Block {
1562                original_indent_columns: original_indent_columns.clone(),
1563            }),
1564            cx,
1565        );
1566        assert_eq!(
1567            buffer.text(),
1568            r#"
1569            fn a() {
1570                if b() {
1571                    c
1572                        .d()
1573                        .e();
1574                }
1575            }
1576            "#
1577            .unindent()
1578        );
1579
1580        // Grouping is disabled in tests, so we need 2 undos
1581        buffer.undo(cx); // Undo the auto-indent
1582        buffer.undo(cx); // Undo the original edit
1583
1584        // Insert the block at a deeper indent level. The entire block is outdented.
1585        buffer.edit(
1586            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1587            None,
1588            cx,
1589        );
1590        buffer.edit(
1591            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1592            Some(AutoindentMode::Block {
1593                original_indent_columns: Vec::new(),
1594            }),
1595            cx,
1596        );
1597        assert_eq!(
1598            buffer.text(),
1599            r#"
1600            fn a() {
1601                if b() {
1602                    c
1603                        .d()
1604                        .e();
1605                }
1606            }
1607            "#
1608            .unindent()
1609        );
1610
1611        buffer
1612    });
1613}
1614
1615#[gpui::test]
1616fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1617    init_settings(cx, |_| {});
1618
1619    cx.new_model(|cx| {
1620        let text = "
1621            * one
1622                - a
1623                - b
1624            * two
1625        "
1626        .unindent();
1627
1628        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text)
1629            .with_language(
1630                Arc::new(Language::new(
1631                    LanguageConfig {
1632                        name: "Markdown".into(),
1633                        auto_indent_using_last_non_empty_line: false,
1634                        ..Default::default()
1635                    },
1636                    Some(tree_sitter_json::language()),
1637                )),
1638                cx,
1639            );
1640        buffer.edit(
1641            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1642            Some(AutoindentMode::EachLine),
1643            cx,
1644        );
1645        assert_eq!(
1646            buffer.text(),
1647            "
1648            * one
1649                - a
1650                - b
1651
1652            * two
1653            "
1654            .unindent()
1655        );
1656        buffer
1657    });
1658}
1659
1660#[gpui::test]
1661fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1662    init_settings(cx, |settings| {
1663        settings.languages.extend([
1664            (
1665                "HTML".into(),
1666                LanguageSettingsContent {
1667                    tab_size: Some(2.try_into().unwrap()),
1668                    ..Default::default()
1669                },
1670            ),
1671            (
1672                "JavaScript".into(),
1673                LanguageSettingsContent {
1674                    tab_size: Some(8.try_into().unwrap()),
1675                    ..Default::default()
1676                },
1677            ),
1678        ])
1679    });
1680
1681    let html_language = Arc::new(html_lang());
1682
1683    let javascript_language = Arc::new(javascript_lang());
1684
1685    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
1686    language_registry.add(html_language.clone());
1687    language_registry.add(javascript_language.clone());
1688
1689    cx.new_model(|cx| {
1690        let (text, ranges) = marked_text_ranges(
1691            &"
1692                <div>ˇ
1693                </div>
1694                <script>
1695                    init({ˇ
1696                    })
1697                </script>
1698                <span>ˇ
1699                </span>
1700            "
1701            .unindent(),
1702            false,
1703        );
1704
1705        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
1706        buffer.set_language_registry(language_registry);
1707        buffer.set_language(Some(html_language), cx);
1708        buffer.edit(
1709            ranges.into_iter().map(|range| (range, "\na")),
1710            Some(AutoindentMode::EachLine),
1711            cx,
1712        );
1713        assert_eq!(
1714            buffer.text(),
1715            "
1716                <div>
1717                  a
1718                </div>
1719                <script>
1720                    init({
1721                            a
1722                    })
1723                </script>
1724                <span>
1725                  a
1726                </span>
1727            "
1728            .unindent()
1729        );
1730        buffer
1731    });
1732}
1733
1734#[gpui::test]
1735fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1736    init_settings(cx, |settings| {
1737        settings.defaults.tab_size = Some(2.try_into().unwrap());
1738    });
1739
1740    cx.new_model(|cx| {
1741        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "")
1742            .with_language(Arc::new(ruby_lang()), cx);
1743
1744        let text = r#"
1745            class C
1746            def a(b, c)
1747            puts b
1748            puts c
1749            rescue
1750            puts "errored"
1751            exit 1
1752            end
1753            end
1754        "#
1755        .unindent();
1756
1757        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1758
1759        assert_eq!(
1760            buffer.text(),
1761            r#"
1762                class C
1763                  def a(b, c)
1764                    puts b
1765                    puts c
1766                  rescue
1767                    puts "errored"
1768                    exit 1
1769                  end
1770                end
1771            "#
1772            .unindent()
1773        );
1774
1775        buffer
1776    });
1777}
1778
1779#[gpui::test]
1780fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1781    init_settings(cx, |_| {});
1782
1783    cx.new_model(|cx| {
1784        let language = Language::new(
1785            LanguageConfig {
1786                name: "JavaScript".into(),
1787                line_comments: vec!["// ".into()],
1788                brackets: BracketPairConfig {
1789                    pairs: vec![
1790                        BracketPair {
1791                            start: "{".into(),
1792                            end: "}".into(),
1793                            close: true,
1794                            newline: false,
1795                        },
1796                        BracketPair {
1797                            start: "'".into(),
1798                            end: "'".into(),
1799                            close: true,
1800                            newline: false,
1801                        },
1802                    ],
1803                    disabled_scopes_by_bracket_ix: vec![
1804                        Vec::new(), //
1805                        vec!["string".into()],
1806                    ],
1807                },
1808                overrides: [(
1809                    "element".into(),
1810                    LanguageConfigOverride {
1811                        line_comments: Override::Remove { remove: true },
1812                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1813                        ..Default::default()
1814                    },
1815                )]
1816                .into_iter()
1817                .collect(),
1818                ..Default::default()
1819            },
1820            Some(tree_sitter_typescript::language_tsx()),
1821        )
1822        .with_override_query(
1823            r#"
1824                (jsx_element) @element
1825                (string) @string
1826                [
1827                    (jsx_opening_element)
1828                    (jsx_closing_element)
1829                    (jsx_expression)
1830                ] @default
1831            "#,
1832        )
1833        .unwrap();
1834
1835        let text = r#"
1836            a["b"] = <C d="e">
1837                <F></F>
1838                { g() }
1839            </C>;
1840        "#
1841        .unindent();
1842
1843        let buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), &text)
1844            .with_language(Arc::new(language), cx);
1845        let snapshot = buffer.snapshot();
1846
1847        let config = snapshot.language_scope_at(0).unwrap();
1848        assert_eq!(config.line_comment_prefixes().unwrap(), &[Arc::from("// ")]);
1849        // Both bracket pairs are enabled
1850        assert_eq!(
1851            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1852            &[true, true]
1853        );
1854
1855        let string_config = snapshot
1856            .language_scope_at(text.find("b\"").unwrap())
1857            .unwrap();
1858        assert_eq!(
1859            string_config.line_comment_prefixes().unwrap(),
1860            &[Arc::from("// ")]
1861        );
1862        // Second bracket pair is disabled
1863        assert_eq!(
1864            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1865            &[true, false]
1866        );
1867
1868        // In between JSX tags: use the `element` override.
1869        let element_config = snapshot
1870            .language_scope_at(text.find("<F>").unwrap())
1871            .unwrap();
1872        assert_eq!(element_config.line_comment_prefixes(), None);
1873        assert_eq!(
1874            element_config.block_comment_delimiters(),
1875            Some((&"{/*".into(), &"*/}".into()))
1876        );
1877        assert_eq!(
1878            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1879            &[true, true]
1880        );
1881
1882        // Within a JSX tag: use the default config.
1883        let tag_config = snapshot
1884            .language_scope_at(text.find(" d=").unwrap() + 1)
1885            .unwrap();
1886        assert_eq!(
1887            tag_config.line_comment_prefixes().unwrap(),
1888            &[Arc::from("// ")]
1889        );
1890        assert_eq!(
1891            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1892            &[true, true]
1893        );
1894
1895        // In a JSX expression: use the default config.
1896        let expression_in_element_config = snapshot
1897            .language_scope_at(text.find('{').unwrap() + 1)
1898            .unwrap();
1899        assert_eq!(
1900            expression_in_element_config
1901                .line_comment_prefixes()
1902                .unwrap(),
1903            &[Arc::from("// ")]
1904        );
1905        assert_eq!(
1906            expression_in_element_config
1907                .brackets()
1908                .map(|e| e.1)
1909                .collect::<Vec<_>>(),
1910            &[true, true]
1911        );
1912
1913        buffer
1914    });
1915}
1916
1917#[gpui::test]
1918fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1919    init_settings(cx, |_| {});
1920
1921    cx.new_model(|cx| {
1922        let language = Language::new(
1923            LanguageConfig {
1924                name: "Rust".into(),
1925                brackets: BracketPairConfig {
1926                    pairs: vec![
1927                        BracketPair {
1928                            start: "{".into(),
1929                            end: "}".into(),
1930                            close: true,
1931                            newline: false,
1932                        },
1933                        BracketPair {
1934                            start: "'".into(),
1935                            end: "'".into(),
1936                            close: true,
1937                            newline: false,
1938                        },
1939                    ],
1940                    disabled_scopes_by_bracket_ix: vec![
1941                        Vec::new(), //
1942                        vec!["string".into()],
1943                    ],
1944                },
1945                ..Default::default()
1946            },
1947            Some(tree_sitter_rust::language()),
1948        )
1949        .with_override_query(
1950            r#"
1951                (string_literal) @string
1952            "#,
1953        )
1954        .unwrap();
1955
1956        let text = r#"
1957            const S: &'static str = "hello";
1958        "#
1959        .unindent();
1960
1961        let buffer = Buffer::new(
1962            0,
1963            BufferId::new(cx.entity_id().as_u64()).unwrap(),
1964            text.clone(),
1965        )
1966        .with_language(Arc::new(language), cx);
1967        let snapshot = buffer.snapshot();
1968
1969        // By default, all brackets are enabled
1970        let config = snapshot.language_scope_at(0).unwrap();
1971        assert_eq!(
1972            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1973            &[true, true]
1974        );
1975
1976        // Within a string, the quotation brackets are disabled.
1977        let string_config = snapshot
1978            .language_scope_at(text.find("ello").unwrap())
1979            .unwrap();
1980        assert_eq!(
1981            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1982            &[true, false]
1983        );
1984
1985        buffer
1986    });
1987}
1988
1989#[gpui::test]
1990fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1991    init_settings(cx, |_| {});
1992
1993    cx.new_model(|cx| {
1994        let text = r#"
1995            <ol>
1996            <% people.each do |person| %>
1997                <li>
1998                    <%= person.name %>
1999                </li>
2000            <% end %>
2001            </ol>
2002        "#
2003        .unindent();
2004
2005        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2006        language_registry.add(Arc::new(ruby_lang()));
2007        language_registry.add(Arc::new(html_lang()));
2008        language_registry.add(Arc::new(erb_lang()));
2009
2010        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), text);
2011        buffer.set_language_registry(language_registry.clone());
2012        buffer.set_language(
2013            language_registry
2014                .language_for_name("ERB")
2015                .now_or_never()
2016                .unwrap()
2017                .ok(),
2018            cx,
2019        );
2020
2021        let snapshot = buffer.snapshot();
2022        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2023        assert_eq!(html_config.line_comment_prefixes(), Some(&vec![]));
2024        assert_eq!(
2025            html_config.block_comment_delimiters(),
2026            Some((&"<!--".into(), &"-->".into()))
2027        );
2028
2029        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2030        assert_eq!(
2031            ruby_config.line_comment_prefixes().unwrap(),
2032            &[Arc::from("# ")]
2033        );
2034        assert_eq!(ruby_config.block_comment_delimiters(), None);
2035
2036        buffer
2037    });
2038}
2039
2040#[gpui::test]
2041fn test_serialization(cx: &mut gpui::AppContext) {
2042    let mut now = Instant::now();
2043
2044    let buffer1 = cx.new_model(|cx| {
2045        let mut buffer = Buffer::new(0, BufferId::new(cx.entity_id().as_u64()).unwrap(), "abc");
2046        buffer.edit([(3..3, "D")], None, cx);
2047
2048        now += Duration::from_secs(1);
2049        buffer.start_transaction_at(now);
2050        buffer.edit([(4..4, "E")], None, cx);
2051        buffer.end_transaction_at(now, cx);
2052        assert_eq!(buffer.text(), "abcDE");
2053
2054        buffer.undo(cx);
2055        assert_eq!(buffer.text(), "abcD");
2056
2057        buffer.edit([(4..4, "F")], None, cx);
2058        assert_eq!(buffer.text(), "abcDF");
2059        buffer
2060    });
2061    assert_eq!(buffer1.read(cx).text(), "abcDF");
2062
2063    let state = buffer1.read(cx).to_proto();
2064    let ops = cx
2065        .background_executor()
2066        .block(buffer1.read(cx).serialize_ops(None, cx));
2067    let buffer2 = cx.new_model(|cx| {
2068        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2069        buffer
2070            .apply_ops(
2071                ops.into_iter()
2072                    .map(|op| proto::deserialize_operation(op).unwrap()),
2073                cx,
2074            )
2075            .unwrap();
2076        buffer
2077    });
2078    assert_eq!(buffer2.read(cx).text(), "abcDF");
2079}
2080
2081#[gpui::test(iterations = 100)]
2082fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
2083    let min_peers = env::var("MIN_PEERS")
2084        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2085        .unwrap_or(1);
2086    let max_peers = env::var("MAX_PEERS")
2087        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2088        .unwrap_or(5);
2089    let operations = env::var("OPERATIONS")
2090        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2091        .unwrap_or(10);
2092
2093    let base_text_len = rng.gen_range(0..10);
2094    let base_text = RandomCharIter::new(&mut rng)
2095        .take(base_text_len)
2096        .collect::<String>();
2097    let mut replica_ids = Vec::new();
2098    let mut buffers = Vec::new();
2099    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2100    let base_buffer = cx.new_model(|cx| {
2101        Buffer::new(
2102            0,
2103            BufferId::new(cx.entity_id().as_u64()).unwrap(),
2104            base_text.as_str(),
2105        )
2106    });
2107
2108    for i in 0..rng.gen_range(min_peers..=max_peers) {
2109        let buffer = cx.new_model(|cx| {
2110            let state = base_buffer.read(cx).to_proto();
2111            let ops = cx
2112                .background_executor()
2113                .block(base_buffer.read(cx).serialize_ops(None, cx));
2114            let mut buffer =
2115                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2116            buffer
2117                .apply_ops(
2118                    ops.into_iter()
2119                        .map(|op| proto::deserialize_operation(op).unwrap()),
2120                    cx,
2121                )
2122                .unwrap();
2123            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2124            let network = network.clone();
2125            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2126                if let Event::Operation(op) = event {
2127                    network
2128                        .lock()
2129                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
2130                }
2131            })
2132            .detach();
2133            buffer
2134        });
2135
2136        buffers.push(buffer);
2137        replica_ids.push(i as ReplicaId);
2138        network.lock().add_peer(i as ReplicaId);
2139        log::info!("Adding initial peer with replica id {}", i);
2140    }
2141
2142    log::info!("initial text: {:?}", base_text);
2143
2144    let mut now = Instant::now();
2145    let mut mutation_count = operations;
2146    let mut next_diagnostic_id = 0;
2147    let mut active_selections = BTreeMap::default();
2148    loop {
2149        let replica_index = rng.gen_range(0..replica_ids.len());
2150        let replica_id = replica_ids[replica_index];
2151        let buffer = &mut buffers[replica_index];
2152        let mut new_buffer = None;
2153        match rng.gen_range(0..100) {
2154            0..=29 if mutation_count != 0 => {
2155                buffer.update(cx, |buffer, cx| {
2156                    buffer.start_transaction_at(now);
2157                    buffer.randomly_edit(&mut rng, 5, cx);
2158                    buffer.end_transaction_at(now, cx);
2159                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2160                });
2161                mutation_count -= 1;
2162            }
2163            30..=39 if mutation_count != 0 => {
2164                buffer.update(cx, |buffer, cx| {
2165                    if rng.gen_bool(0.2) {
2166                        log::info!("peer {} clearing active selections", replica_id);
2167                        active_selections.remove(&replica_id);
2168                        buffer.remove_active_selections(cx);
2169                    } else {
2170                        let mut selections = Vec::new();
2171                        for id in 0..rng.gen_range(1..=5) {
2172                            let range = buffer.random_byte_range(0, &mut rng);
2173                            selections.push(Selection {
2174                                id,
2175                                start: buffer.anchor_before(range.start),
2176                                end: buffer.anchor_before(range.end),
2177                                reversed: false,
2178                                goal: SelectionGoal::None,
2179                            });
2180                        }
2181                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2182                        log::info!(
2183                            "peer {} setting active selections: {:?}",
2184                            replica_id,
2185                            selections
2186                        );
2187                        active_selections.insert(replica_id, selections.clone());
2188                        buffer.set_active_selections(selections, false, Default::default(), cx);
2189                    }
2190                });
2191                mutation_count -= 1;
2192            }
2193            40..=49 if mutation_count != 0 && replica_id == 0 => {
2194                let entry_count = rng.gen_range(1..=5);
2195                buffer.update(cx, |buffer, cx| {
2196                    let diagnostics = DiagnosticSet::new(
2197                        (0..entry_count).map(|_| {
2198                            let range = buffer.random_byte_range(0, &mut rng);
2199                            let range = range.to_point_utf16(buffer);
2200                            let range = range.start..range.end;
2201                            DiagnosticEntry {
2202                                range,
2203                                diagnostic: Diagnostic {
2204                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2205                                    ..Default::default()
2206                                },
2207                            }
2208                        }),
2209                        buffer,
2210                    );
2211                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2212                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2213                });
2214                mutation_count -= 1;
2215            }
2216            50..=59 if replica_ids.len() < max_peers => {
2217                let old_buffer_state = buffer.read(cx).to_proto();
2218                let old_buffer_ops = cx
2219                    .background_executor()
2220                    .block(buffer.read(cx).serialize_ops(None, cx));
2221                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2222                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2223                    .choose(&mut rng)
2224                    .unwrap();
2225                log::info!(
2226                    "Adding new replica {} (replicating from {})",
2227                    new_replica_id,
2228                    replica_id
2229                );
2230                new_buffer = Some(cx.new_model(|cx| {
2231                    let mut new_buffer = Buffer::from_proto(
2232                        new_replica_id,
2233                        Capability::ReadWrite,
2234                        old_buffer_state,
2235                        None,
2236                    )
2237                    .unwrap();
2238                    new_buffer
2239                        .apply_ops(
2240                            old_buffer_ops
2241                                .into_iter()
2242                                .map(|op| deserialize_operation(op).unwrap()),
2243                            cx,
2244                        )
2245                        .unwrap();
2246                    log::info!(
2247                        "New replica {} text: {:?}",
2248                        new_buffer.replica_id(),
2249                        new_buffer.text()
2250                    );
2251                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2252                    let network = network.clone();
2253                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2254                        if let Event::Operation(op) = event {
2255                            network.lock().broadcast(
2256                                buffer.replica_id(),
2257                                vec![proto::serialize_operation(op)],
2258                            );
2259                        }
2260                    })
2261                    .detach();
2262                    new_buffer
2263                }));
2264                network.lock().replicate(replica_id, new_replica_id);
2265
2266                if new_replica_id as usize == replica_ids.len() {
2267                    replica_ids.push(new_replica_id);
2268                } else {
2269                    let new_buffer = new_buffer.take().unwrap();
2270                    while network.lock().has_unreceived(new_replica_id) {
2271                        let ops = network
2272                            .lock()
2273                            .receive(new_replica_id)
2274                            .into_iter()
2275                            .map(|op| proto::deserialize_operation(op).unwrap());
2276                        if ops.len() > 0 {
2277                            log::info!(
2278                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2279                                new_replica_id,
2280                                buffer.read(cx).version(),
2281                                ops.len(),
2282                                ops
2283                            );
2284                            new_buffer.update(cx, |new_buffer, cx| {
2285                                new_buffer.apply_ops(ops, cx).unwrap();
2286                            });
2287                        }
2288                    }
2289                    buffers[new_replica_id as usize] = new_buffer;
2290                }
2291            }
2292            60..=69 if mutation_count != 0 => {
2293                buffer.update(cx, |buffer, cx| {
2294                    buffer.randomly_undo_redo(&mut rng, cx);
2295                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2296                });
2297                mutation_count -= 1;
2298            }
2299            _ if network.lock().has_unreceived(replica_id) => {
2300                let ops = network
2301                    .lock()
2302                    .receive(replica_id)
2303                    .into_iter()
2304                    .map(|op| proto::deserialize_operation(op).unwrap());
2305                if ops.len() > 0 {
2306                    log::info!(
2307                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2308                        replica_id,
2309                        buffer.read(cx).version(),
2310                        ops.len(),
2311                        ops
2312                    );
2313                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2314                }
2315            }
2316            _ => {}
2317        }
2318
2319        now += Duration::from_millis(rng.gen_range(0..=200));
2320        buffers.extend(new_buffer);
2321
2322        for buffer in &buffers {
2323            buffer.read(cx).check_invariants();
2324        }
2325
2326        if mutation_count == 0 && network.lock().is_idle() {
2327            break;
2328        }
2329    }
2330
2331    let first_buffer = buffers[0].read(cx).snapshot();
2332    for buffer in &buffers[1..] {
2333        let buffer = buffer.read(cx).snapshot();
2334        assert_eq!(
2335            buffer.version(),
2336            first_buffer.version(),
2337            "Replica {} version != Replica 0 version",
2338            buffer.replica_id()
2339        );
2340        assert_eq!(
2341            buffer.text(),
2342            first_buffer.text(),
2343            "Replica {} text != Replica 0 text",
2344            buffer.replica_id()
2345        );
2346        assert_eq!(
2347            buffer
2348                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2349                .collect::<Vec<_>>(),
2350            first_buffer
2351                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2352                .collect::<Vec<_>>(),
2353            "Replica {} diagnostics != Replica 0 diagnostics",
2354            buffer.replica_id()
2355        );
2356    }
2357
2358    for buffer in &buffers {
2359        let buffer = buffer.read(cx).snapshot();
2360        let actual_remote_selections = buffer
2361            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2362            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2363            .collect::<Vec<_>>();
2364        let expected_remote_selections = active_selections
2365            .iter()
2366            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2367            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2368            .collect::<Vec<_>>();
2369        assert_eq!(
2370            actual_remote_selections,
2371            expected_remote_selections,
2372            "Replica {} remote selections != expected selections",
2373            buffer.replica_id()
2374        );
2375    }
2376}
2377
2378#[test]
2379fn test_contiguous_ranges() {
2380    assert_eq!(
2381        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2382        &[1..4, 5..7, 9..13]
2383    );
2384
2385    // Respects the `max_len` parameter
2386    assert_eq!(
2387        contiguous_ranges(
2388            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2389            3
2390        )
2391        .collect::<Vec<_>>(),
2392        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2393    );
2394}
2395
2396#[gpui::test(iterations = 500)]
2397fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2398    // Generate a random multi-line string containing
2399    // some lines with trailing whitespace.
2400    let mut text = String::new();
2401    for _ in 0..rng.gen_range(0..16) {
2402        for _ in 0..rng.gen_range(0..36) {
2403            text.push(match rng.gen_range(0..10) {
2404                0..=1 => ' ',
2405                3 => '\t',
2406                _ => rng.gen_range('a'..'z'),
2407            });
2408        }
2409        text.push('\n');
2410    }
2411
2412    match rng.gen_range(0..10) {
2413        // sometimes remove the last newline
2414        0..=1 => drop(text.pop()), //
2415
2416        // sometimes add extra newlines
2417        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2418        _ => {}
2419    }
2420
2421    let rope = Rope::from(text.as_str());
2422    let actual_ranges = trailing_whitespace_ranges(&rope);
2423    let expected_ranges = TRAILING_WHITESPACE_REGEX
2424        .find_iter(&text)
2425        .map(|m| m.range())
2426        .collect::<Vec<_>>();
2427    assert_eq!(
2428        actual_ranges,
2429        expected_ranges,
2430        "wrong ranges for text lines:\n{:?}",
2431        text.split('\n').collect::<Vec<_>>()
2432    );
2433}
2434
2435fn ruby_lang() -> Language {
2436    Language::new(
2437        LanguageConfig {
2438            name: "Ruby".into(),
2439            matcher: LanguageMatcher {
2440                path_suffixes: vec!["rb".to_string()],
2441                ..Default::default()
2442            },
2443            line_comments: vec!["# ".into()],
2444            ..Default::default()
2445        },
2446        Some(tree_sitter_ruby::language()),
2447    )
2448    .with_indents_query(
2449        r#"
2450            (class "end" @end) @indent
2451            (method "end" @end) @indent
2452            (rescue) @outdent
2453            (then) @indent
2454        "#,
2455    )
2456    .unwrap()
2457}
2458
2459fn html_lang() -> Language {
2460    Language::new(
2461        LanguageConfig {
2462            name: "HTML".into(),
2463            block_comment: Some(("<!--".into(), "-->".into())),
2464            ..Default::default()
2465        },
2466        Some(tree_sitter_html::language()),
2467    )
2468    .with_indents_query(
2469        "
2470        (element
2471          (start_tag) @start
2472          (end_tag)? @end) @indent
2473        ",
2474    )
2475    .unwrap()
2476    .with_injection_query(
2477        r#"
2478        (script_element
2479            (raw_text) @content
2480            (#set! "language" "javascript"))
2481        "#,
2482    )
2483    .unwrap()
2484}
2485
2486fn erb_lang() -> Language {
2487    Language::new(
2488        LanguageConfig {
2489            name: "ERB".into(),
2490            matcher: LanguageMatcher {
2491                path_suffixes: vec!["erb".to_string()],
2492                ..Default::default()
2493            },
2494            block_comment: Some(("<%#".into(), "%>".into())),
2495            ..Default::default()
2496        },
2497        Some(tree_sitter_embedded_template::language()),
2498    )
2499    .with_injection_query(
2500        r#"
2501            (
2502                (code) @content
2503                (#set! "language" "ruby")
2504                (#set! "combined")
2505            )
2506
2507            (
2508                (content) @content
2509                (#set! "language" "html")
2510                (#set! "combined")
2511            )
2512        "#,
2513    )
2514    .unwrap()
2515}
2516
2517fn rust_lang() -> Language {
2518    Language::new(
2519        LanguageConfig {
2520            name: "Rust".into(),
2521            matcher: LanguageMatcher {
2522                path_suffixes: vec!["rs".to_string()],
2523                ..Default::default()
2524            },
2525            ..Default::default()
2526        },
2527        Some(tree_sitter_rust::language()),
2528    )
2529    .with_indents_query(
2530        r#"
2531        (call_expression) @indent
2532        (field_expression) @indent
2533        (_ "(" ")" @end) @indent
2534        (_ "{" "}" @end) @indent
2535        "#,
2536    )
2537    .unwrap()
2538    .with_brackets_query(
2539        r#"
2540        ("{" @open "}" @close)
2541        "#,
2542    )
2543    .unwrap()
2544    .with_outline_query(
2545        r#"
2546        (struct_item
2547            "struct" @context
2548            name: (_) @name) @item
2549        (enum_item
2550            "enum" @context
2551            name: (_) @name) @item
2552        (enum_variant
2553            name: (_) @name) @item
2554        (field_declaration
2555            name: (_) @name) @item
2556        (impl_item
2557            "impl" @context
2558            trait: (_)? @name
2559            "for"? @context
2560            type: (_) @name) @item
2561        (function_item
2562            "fn" @context
2563            name: (_) @name) @item
2564        (mod_item
2565            "mod" @context
2566            name: (_) @name) @item
2567        "#,
2568    )
2569    .unwrap()
2570}
2571
2572fn json_lang() -> Language {
2573    Language::new(
2574        LanguageConfig {
2575            name: "Json".into(),
2576            matcher: LanguageMatcher {
2577                path_suffixes: vec!["js".to_string()],
2578                ..Default::default()
2579            },
2580            ..Default::default()
2581        },
2582        Some(tree_sitter_json::language()),
2583    )
2584}
2585
2586fn javascript_lang() -> Language {
2587    Language::new(
2588        LanguageConfig {
2589            name: "JavaScript".into(),
2590            ..Default::default()
2591        },
2592        Some(tree_sitter_typescript::language_tsx()),
2593    )
2594    .with_brackets_query(
2595        r#"
2596        ("{" @open "}" @close)
2597        ("(" @open ")" @close)
2598        "#,
2599    )
2600    .unwrap()
2601    .with_indents_query(
2602        r#"
2603        (object "}" @end) @indent
2604        "#,
2605    )
2606    .unwrap()
2607}
2608
2609fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2610    buffer.update(cx, |buffer, _| {
2611        let snapshot = buffer.snapshot();
2612        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2613        layers[0].node().to_sexp()
2614    })
2615}
2616
2617// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2618fn assert_bracket_pairs(
2619    selection_text: &'static str,
2620    bracket_pair_texts: Vec<&'static str>,
2621    language: Language,
2622    cx: &mut AppContext,
2623) {
2624    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2625    let buffer = cx.new_model(|cx| {
2626        Buffer::new(
2627            0,
2628            BufferId::new(cx.entity_id().as_u64()).unwrap(),
2629            expected_text.clone(),
2630        )
2631        .with_language(Arc::new(language), cx)
2632    });
2633    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2634
2635    let selection_range = selection_ranges[0].clone();
2636
2637    let bracket_pairs = bracket_pair_texts
2638        .into_iter()
2639        .map(|pair_text| {
2640            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2641            assert_eq!(bracket_text, expected_text);
2642            (ranges[0].clone(), ranges[1].clone())
2643        })
2644        .collect::<Vec<_>>();
2645
2646    assert_set_eq!(
2647        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2648        bracket_pairs
2649    );
2650}
2651
2652fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2653    let settings_store = SettingsStore::test(cx);
2654    cx.set_global(settings_store);
2655    crate::init(cx);
2656    cx.update_global::<SettingsStore, _>(|settings, cx| {
2657        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2658    });
2659}