buffer_tests.rs

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