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: original_indent_columns.clone(),
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.clone())],
1794            Some(AutoindentMode::Block {
1795                original_indent_columns: original_indent_columns.clone(),
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: original_indent_columns.clone(),
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.clone());
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(("/*".into(), "*/".into())),
2277                brackets: BracketPairConfig {
2278                    pairs: vec![
2279                        BracketPair {
2280                            start: "{".into(),
2281                            end: "}".into(),
2282                            close: true,
2283                            surround: true,
2284                            newline: false,
2285                        },
2286                        BracketPair {
2287                            start: "'".into(),
2288                            end: "'".into(),
2289                            close: true,
2290                            surround: true,
2291                            newline: false,
2292                        },
2293                    ],
2294                    disabled_scopes_by_bracket_ix: vec![
2295                        Vec::new(),                              //
2296                        vec!["string".into(), "comment".into()], // single quotes disabled
2297                    ],
2298                },
2299                overrides: [(
2300                    "element".into(),
2301                    LanguageConfigOverride {
2302                        line_comments: Override::Remove { remove: true },
2303                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
2304                        ..Default::default()
2305                    },
2306                )]
2307                .into_iter()
2308                .collect(),
2309                ..Default::default()
2310            },
2311            Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
2312        )
2313        .with_override_query(
2314            r#"
2315                (jsx_element) @element
2316                (string) @string
2317                (comment) @comment.inclusive
2318                [
2319                    (jsx_opening_element)
2320                    (jsx_closing_element)
2321                    (jsx_expression)
2322                ] @default
2323            "#,
2324        )
2325        .unwrap();
2326
2327        let text = r#"
2328            a["b"] = <C d="e">
2329                <F></F>
2330                { g() }
2331            </C>; // a comment
2332        "#
2333        .unindent();
2334
2335        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
2336        let snapshot = buffer.snapshot();
2337
2338        let config = snapshot.language_scope_at(0).unwrap();
2339        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
2340        assert_eq!(
2341            config.block_comment_delimiters(),
2342            Some((&"/*".into(), &"*/".into()))
2343        );
2344        // Both bracket pairs are enabled
2345        assert_eq!(
2346            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2347            &[true, true]
2348        );
2349
2350        let comment_config = snapshot
2351            .language_scope_at(text.find("comment").unwrap() + "comment".len())
2352            .unwrap();
2353        assert_eq!(
2354            comment_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2355            &[true, false]
2356        );
2357
2358        let string_config = snapshot
2359            .language_scope_at(text.find("b\"").unwrap())
2360            .unwrap();
2361        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
2362        assert_eq!(
2363            string_config.block_comment_delimiters(),
2364            Some((&"/*".into(), &"*/".into()))
2365        );
2366        // Second bracket pair is disabled
2367        assert_eq!(
2368            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2369            &[true, false]
2370        );
2371
2372        // In between JSX tags: use the `element` override.
2373        let element_config = snapshot
2374            .language_scope_at(text.find("<F>").unwrap())
2375            .unwrap();
2376        // TODO nested blocks after newlines are captured with all whitespaces
2377        // https://github.com/tree-sitter/tree-sitter-typescript/issues/306
2378        // assert_eq!(element_config.line_comment_prefixes(), &[]);
2379        // assert_eq!(
2380        //     element_config.block_comment_delimiters(),
2381        //     Some((&"{/*".into(), &"*/}".into()))
2382        // );
2383        assert_eq!(
2384            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2385            &[true, true]
2386        );
2387
2388        // Within a JSX tag: use the default config.
2389        let tag_config = snapshot
2390            .language_scope_at(text.find(" d=").unwrap() + 1)
2391            .unwrap();
2392        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
2393        assert_eq!(
2394            tag_config.block_comment_delimiters(),
2395            Some((&"/*".into(), &"*/".into()))
2396        );
2397        assert_eq!(
2398            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2399            &[true, true]
2400        );
2401
2402        // In a JSX expression: use the default config.
2403        let expression_in_element_config = snapshot
2404            .language_scope_at(text.find('{').unwrap() + 1)
2405            .unwrap();
2406        assert_eq!(
2407            expression_in_element_config.line_comment_prefixes(),
2408            &[Arc::from("// ")]
2409        );
2410        assert_eq!(
2411            expression_in_element_config.block_comment_delimiters(),
2412            Some((&"/*".into(), &"*/".into()))
2413        );
2414        assert_eq!(
2415            expression_in_element_config
2416                .brackets()
2417                .map(|e| e.1)
2418                .collect::<Vec<_>>(),
2419            &[true, true]
2420        );
2421
2422        buffer
2423    });
2424}
2425
2426#[gpui::test]
2427fn test_language_scope_at_with_rust(cx: &mut App) {
2428    init_settings(cx, |_| {});
2429
2430    cx.new(|cx| {
2431        let language = Language::new(
2432            LanguageConfig {
2433                name: "Rust".into(),
2434                brackets: BracketPairConfig {
2435                    pairs: vec![
2436                        BracketPair {
2437                            start: "{".into(),
2438                            end: "}".into(),
2439                            close: true,
2440                            surround: true,
2441                            newline: false,
2442                        },
2443                        BracketPair {
2444                            start: "'".into(),
2445                            end: "'".into(),
2446                            close: true,
2447                            surround: true,
2448                            newline: false,
2449                        },
2450                    ],
2451                    disabled_scopes_by_bracket_ix: vec![
2452                        Vec::new(), //
2453                        vec!["string".into()],
2454                    ],
2455                },
2456                ..Default::default()
2457            },
2458            Some(tree_sitter_rust::LANGUAGE.into()),
2459        )
2460        .with_override_query(
2461            r#"
2462                (string_literal) @string
2463            "#,
2464        )
2465        .unwrap();
2466
2467        let text = r#"
2468            const S: &'static str = "hello";
2469        "#
2470        .unindent();
2471
2472        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
2473        let snapshot = buffer.snapshot();
2474
2475        // By default, all brackets are enabled
2476        let config = snapshot.language_scope_at(0).unwrap();
2477        assert_eq!(
2478            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2479            &[true, true]
2480        );
2481
2482        // Within a string, the quotation brackets are disabled.
2483        let string_config = snapshot
2484            .language_scope_at(text.find("ello").unwrap())
2485            .unwrap();
2486        assert_eq!(
2487            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2488            &[true, false]
2489        );
2490
2491        buffer
2492    });
2493}
2494
2495#[gpui::test]
2496fn test_language_scope_at_with_combined_injections(cx: &mut App) {
2497    init_settings(cx, |_| {});
2498
2499    cx.new(|cx| {
2500        let text = r#"
2501            <ol>
2502            <% people.each do |person| %>
2503                <li>
2504                    <%= person.name %>
2505                </li>
2506            <% end %>
2507            </ol>
2508        "#
2509        .unindent();
2510
2511        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2512        language_registry.add(Arc::new(ruby_lang()));
2513        language_registry.add(Arc::new(html_lang()));
2514        language_registry.add(Arc::new(erb_lang()));
2515
2516        let mut buffer = Buffer::local(text, cx);
2517        buffer.set_language_registry(language_registry.clone());
2518        buffer.set_language(
2519            language_registry
2520                .language_for_name("ERB")
2521                .now_or_never()
2522                .unwrap()
2523                .ok(),
2524            cx,
2525        );
2526
2527        let snapshot = buffer.snapshot();
2528        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2529        assert_eq!(html_config.line_comment_prefixes(), &[]);
2530        assert_eq!(
2531            html_config.block_comment_delimiters(),
2532            Some((&"<!--".into(), &"-->".into()))
2533        );
2534
2535        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2536        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2537        assert_eq!(ruby_config.block_comment_delimiters(), None);
2538
2539        buffer
2540    });
2541}
2542
2543#[gpui::test]
2544fn test_language_at_with_hidden_languages(cx: &mut App) {
2545    init_settings(cx, |_| {});
2546
2547    cx.new(|cx| {
2548        let text = r#"
2549            this is an *emphasized* word.
2550        "#
2551        .unindent();
2552
2553        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2554        language_registry.add(Arc::new(markdown_lang()));
2555        language_registry.add(Arc::new(markdown_inline_lang()));
2556
2557        let mut buffer = Buffer::local(text, cx);
2558        buffer.set_language_registry(language_registry.clone());
2559        buffer.set_language(
2560            language_registry
2561                .language_for_name("Markdown")
2562                .now_or_never()
2563                .unwrap()
2564                .ok(),
2565            cx,
2566        );
2567
2568        let snapshot = buffer.snapshot();
2569
2570        for point in [Point::new(0, 4), Point::new(0, 16)] {
2571            let config = snapshot.language_scope_at(point).unwrap();
2572            assert_eq!(config.language_name(), "Markdown".into());
2573
2574            let language = snapshot.language_at(point).unwrap();
2575            assert_eq!(language.name().as_ref(), "Markdown");
2576        }
2577
2578        buffer
2579    });
2580}
2581
2582#[gpui::test]
2583fn test_language_at_for_markdown_code_block(cx: &mut App) {
2584    init_settings(cx, |_| {});
2585
2586    cx.new(|cx| {
2587        let text = r#"
2588            ```rs
2589            let a = 2;
2590            // let b = 3;
2591            ```
2592        "#
2593        .unindent();
2594
2595        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2596        language_registry.add(Arc::new(markdown_lang()));
2597        language_registry.add(Arc::new(markdown_inline_lang()));
2598        language_registry.add(Arc::new(rust_lang()));
2599
2600        let mut buffer = Buffer::local(text, cx);
2601        buffer.set_language_registry(language_registry.clone());
2602        buffer.set_language(
2603            language_registry
2604                .language_for_name("Markdown")
2605                .now_or_never()
2606                .unwrap()
2607                .ok(),
2608            cx,
2609        );
2610
2611        let snapshot = buffer.snapshot();
2612
2613        // Test points in the code line
2614        for point in [Point::new(1, 4), Point::new(1, 6)] {
2615            let config = snapshot.language_scope_at(point).unwrap();
2616            assert_eq!(config.language_name(), "Rust".into());
2617
2618            let language = snapshot.language_at(point).unwrap();
2619            assert_eq!(language.name().as_ref(), "Rust");
2620        }
2621
2622        // Test points in the comment line to verify it's still detected as Rust
2623        for point in [Point::new(2, 4), Point::new(2, 6)] {
2624            let config = snapshot.language_scope_at(point).unwrap();
2625            assert_eq!(config.language_name(), "Rust".into());
2626
2627            let language = snapshot.language_at(point).unwrap();
2628            assert_eq!(language.name().as_ref(), "Rust");
2629        }
2630
2631        buffer
2632    });
2633}
2634
2635#[gpui::test]
2636fn test_serialization(cx: &mut gpui::App) {
2637    let mut now = Instant::now();
2638
2639    let buffer1 = cx.new(|cx| {
2640        let mut buffer = Buffer::local("abc", cx);
2641        buffer.edit([(3..3, "D")], None, cx);
2642
2643        now += Duration::from_secs(1);
2644        buffer.start_transaction_at(now);
2645        buffer.edit([(4..4, "E")], None, cx);
2646        buffer.end_transaction_at(now, cx);
2647        assert_eq!(buffer.text(), "abcDE");
2648
2649        buffer.undo(cx);
2650        assert_eq!(buffer.text(), "abcD");
2651
2652        buffer.edit([(4..4, "F")], None, cx);
2653        assert_eq!(buffer.text(), "abcDF");
2654        buffer
2655    });
2656    assert_eq!(buffer1.read(cx).text(), "abcDF");
2657
2658    let state = buffer1.read(cx).to_proto(cx);
2659    let ops = cx
2660        .background_executor()
2661        .block(buffer1.read(cx).serialize_ops(None, cx));
2662    let buffer2 = cx.new(|cx| {
2663        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2664        buffer.apply_ops(
2665            ops.into_iter()
2666                .map(|op| proto::deserialize_operation(op).unwrap()),
2667            cx,
2668        );
2669        buffer
2670    });
2671    assert_eq!(buffer2.read(cx).text(), "abcDF");
2672}
2673
2674#[gpui::test]
2675fn test_branch_and_merge(cx: &mut TestAppContext) {
2676    cx.update(|cx| init_settings(cx, |_| {}));
2677
2678    let base = cx.new(|cx| Buffer::local("one\ntwo\nthree\n", cx));
2679
2680    // Create a remote replica of the base buffer.
2681    let base_replica = cx.new(|cx| {
2682        Buffer::from_proto(1, Capability::ReadWrite, base.read(cx).to_proto(cx), None).unwrap()
2683    });
2684    base.update(cx, |_buffer, cx| {
2685        cx.subscribe(&base_replica, |this, _, event, cx| {
2686            if let BufferEvent::Operation {
2687                operation,
2688                is_local: true,
2689            } = event
2690            {
2691                this.apply_ops([operation.clone()], cx);
2692            }
2693        })
2694        .detach();
2695    });
2696
2697    // Create a branch, which initially has the same state as the base buffer.
2698    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2699    branch.read_with(cx, |buffer, _| {
2700        assert_eq!(buffer.text(), "one\ntwo\nthree\n");
2701    });
2702
2703    // Edits to the branch are not applied to the base.
2704    branch.update(cx, |buffer, cx| {
2705        buffer.edit(
2706            [
2707                (Point::new(1, 0)..Point::new(1, 0), "1.5\n"),
2708                (Point::new(2, 0)..Point::new(2, 5), "THREE"),
2709            ],
2710            None,
2711            cx,
2712        )
2713    });
2714    branch.read_with(cx, |buffer, cx| {
2715        assert_eq!(base.read(cx).text(), "one\ntwo\nthree\n");
2716        assert_eq!(buffer.text(), "one\n1.5\ntwo\nTHREE\n");
2717    });
2718
2719    // Convert from branch buffer ranges to the corresponding ranges in the
2720    // base buffer.
2721    branch.read_with(cx, |buffer, cx| {
2722        assert_eq!(
2723            buffer.range_to_version(4..7, &base.read(cx).version()),
2724            4..4
2725        );
2726        assert_eq!(
2727            buffer.range_to_version(2..9, &base.read(cx).version()),
2728            2..5
2729        );
2730    });
2731
2732    // Edits to the base are applied to the branch.
2733    base.update(cx, |buffer, cx| {
2734        buffer.edit([(Point::new(0, 0)..Point::new(0, 0), "ZERO\n")], None, cx)
2735    });
2736    branch.read_with(cx, |buffer, cx| {
2737        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\nthree\n");
2738        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\nTHREE\n");
2739    });
2740
2741    // Edits to any replica of the base are applied to the branch.
2742    base_replica.update(cx, |buffer, cx| {
2743        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "2.5\n")], None, cx)
2744    });
2745    branch.read_with(cx, |buffer, cx| {
2746        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\n2.5\nthree\n");
2747        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2748    });
2749
2750    // Merging the branch applies all of its changes to the base.
2751    branch.update(cx, |buffer, cx| {
2752        buffer.merge_into_base(Vec::new(), cx);
2753    });
2754
2755    branch.update(cx, |buffer, cx| {
2756        assert_eq!(base.read(cx).text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2757        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2758    });
2759}
2760
2761#[gpui::test]
2762fn test_merge_into_base(cx: &mut TestAppContext) {
2763    cx.update(|cx| init_settings(cx, |_| {}));
2764
2765    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2766    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2767
2768    // Make 3 edits, merge one into the base.
2769    branch.update(cx, |branch, cx| {
2770        branch.edit([(0..3, "ABC"), (7..9, "HI"), (11..11, "LMN")], None, cx);
2771        branch.merge_into_base(vec![5..8], cx);
2772    });
2773
2774    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjkLMN"));
2775    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2776
2777    // Undo the one already-merged edit. Merge that into the base.
2778    branch.update(cx, |branch, cx| {
2779        branch.edit([(7..9, "hi")], None, cx);
2780        branch.merge_into_base(vec![5..8], cx);
2781    });
2782    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2783
2784    // Merge an insertion into the base.
2785    branch.update(cx, |branch, cx| {
2786        branch.merge_into_base(vec![11..11], cx);
2787    });
2788
2789    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefghijkLMN"));
2790    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijkLMN"));
2791
2792    // Deleted the inserted text and merge that into the base.
2793    branch.update(cx, |branch, cx| {
2794        branch.edit([(11..14, "")], None, cx);
2795        branch.merge_into_base(vec![10..11], cx);
2796    });
2797
2798    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2799}
2800
2801#[gpui::test]
2802fn test_undo_after_merge_into_base(cx: &mut TestAppContext) {
2803    cx.update(|cx| init_settings(cx, |_| {}));
2804
2805    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2806    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2807
2808    // Make 2 edits, merge one into the base.
2809    branch.update(cx, |branch, cx| {
2810        branch.edit([(0..3, "ABC"), (7..9, "HI")], None, cx);
2811        branch.merge_into_base(vec![7..7], cx);
2812    });
2813    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2814    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2815
2816    // Undo the merge in the base buffer.
2817    base.update(cx, |base, cx| {
2818        base.undo(cx);
2819    });
2820    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2821    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2822
2823    // Merge that operation into the base again.
2824    branch.update(cx, |branch, cx| {
2825        branch.merge_into_base(vec![7..7], cx);
2826    });
2827    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2828    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2829}
2830
2831#[gpui::test]
2832async fn test_preview_edits(cx: &mut TestAppContext) {
2833    cx.update(|cx| {
2834        init_settings(cx, |_| {});
2835        theme::init(theme::LoadThemes::JustBase, cx);
2836    });
2837
2838    let insertion_style = HighlightStyle {
2839        background_color: Some(cx.read(|cx| cx.theme().status().created_background)),
2840        ..Default::default()
2841    };
2842    let deletion_style = HighlightStyle {
2843        background_color: Some(cx.read(|cx| cx.theme().status().deleted_background)),
2844        ..Default::default()
2845    };
2846
2847    // no edits
2848    assert_preview_edits(
2849        indoc! {"
2850        fn test_empty() -> bool {
2851            false
2852        }"
2853        },
2854        vec![],
2855        true,
2856        cx,
2857        |hl| {
2858            assert!(hl.text.is_empty());
2859            assert!(hl.highlights.is_empty());
2860        },
2861    )
2862    .await;
2863
2864    // only insertions
2865    assert_preview_edits(
2866        indoc! {"
2867        fn calculate_area(: f64) -> f64 {
2868            std::f64::consts::PI * .powi(2)
2869        }"
2870        },
2871        vec![
2872            (Point::new(0, 18)..Point::new(0, 18), "radius"),
2873            (Point::new(1, 27)..Point::new(1, 27), "radius"),
2874        ],
2875        true,
2876        cx,
2877        |hl| {
2878            assert_eq!(
2879                hl.text,
2880                indoc! {"
2881                fn calculate_area(radius: f64) -> f64 {
2882                    std::f64::consts::PI * radius.powi(2)"
2883                }
2884            );
2885
2886            assert_eq!(hl.highlights.len(), 2);
2887            assert_eq!(hl.highlights[0], ((18..24), insertion_style));
2888            assert_eq!(hl.highlights[1], ((67..73), insertion_style));
2889        },
2890    )
2891    .await;
2892
2893    // insertions & deletions
2894    assert_preview_edits(
2895        indoc! {"
2896        struct Person {
2897            first_name: String,
2898        }
2899
2900        impl Person {
2901            fn first_name(&self) -> &String {
2902                &self.first_name
2903            }
2904        }"
2905        },
2906        vec![
2907            (Point::new(1, 4)..Point::new(1, 9), "last"),
2908            (Point::new(5, 7)..Point::new(5, 12), "last"),
2909            (Point::new(6, 14)..Point::new(6, 19), "last"),
2910        ],
2911        true,
2912        cx,
2913        |hl| {
2914            assert_eq!(
2915                hl.text,
2916                indoc! {"
2917                        firstlast_name: String,
2918                    }
2919
2920                    impl Person {
2921                        fn firstlast_name(&self) -> &String {
2922                            &self.firstlast_name"
2923                }
2924            );
2925
2926            assert_eq!(hl.highlights.len(), 6);
2927            assert_eq!(hl.highlights[0], ((4..9), deletion_style));
2928            assert_eq!(hl.highlights[1], ((9..13), insertion_style));
2929            assert_eq!(hl.highlights[2], ((52..57), deletion_style));
2930            assert_eq!(hl.highlights[3], ((57..61), insertion_style));
2931            assert_eq!(hl.highlights[4], ((101..106), deletion_style));
2932            assert_eq!(hl.highlights[5], ((106..110), insertion_style));
2933        },
2934    )
2935    .await;
2936
2937    async fn assert_preview_edits(
2938        text: &str,
2939        edits: Vec<(Range<Point>, &str)>,
2940        include_deletions: bool,
2941        cx: &mut TestAppContext,
2942        assert_fn: impl Fn(HighlightedText),
2943    ) {
2944        let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
2945        let edits = buffer.read_with(cx, |buffer, _| {
2946            edits
2947                .into_iter()
2948                .map(|(range, text)| {
2949                    (
2950                        buffer.anchor_before(range.start)..buffer.anchor_after(range.end),
2951                        text.to_string(),
2952                    )
2953                })
2954                .collect::<Vec<_>>()
2955        });
2956        let edit_preview = buffer
2957            .read_with(cx, |buffer, cx| {
2958                buffer.preview_edits(edits.clone().into(), cx)
2959            })
2960            .await;
2961        let highlighted_edits = cx.read(|cx| {
2962            edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, include_deletions, cx)
2963        });
2964        assert_fn(highlighted_edits);
2965    }
2966}
2967
2968#[gpui::test(iterations = 100)]
2969fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
2970    let min_peers = env::var("MIN_PEERS")
2971        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
2972        .unwrap_or(1);
2973    let max_peers = env::var("MAX_PEERS")
2974        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
2975        .unwrap_or(5);
2976    let operations = env::var("OPERATIONS")
2977        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
2978        .unwrap_or(10);
2979
2980    let base_text_len = rng.gen_range(0..10);
2981    let base_text = RandomCharIter::new(&mut rng)
2982        .take(base_text_len)
2983        .collect::<String>();
2984    let mut replica_ids = Vec::new();
2985    let mut buffers = Vec::new();
2986    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
2987    let base_buffer = cx.new(|cx| Buffer::local(base_text.as_str(), cx));
2988
2989    for i in 0..rng.gen_range(min_peers..=max_peers) {
2990        let buffer = cx.new(|cx| {
2991            let state = base_buffer.read(cx).to_proto(cx);
2992            let ops = cx
2993                .background_executor()
2994                .block(base_buffer.read(cx).serialize_ops(None, cx));
2995            let mut buffer =
2996                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
2997            buffer.apply_ops(
2998                ops.into_iter()
2999                    .map(|op| proto::deserialize_operation(op).unwrap()),
3000                cx,
3001            );
3002            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
3003            let network = network.clone();
3004            cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
3005                if let BufferEvent::Operation {
3006                    operation,
3007                    is_local: true,
3008                } = event
3009                {
3010                    network.lock().broadcast(
3011                        buffer.replica_id(),
3012                        vec![proto::serialize_operation(operation)],
3013                    );
3014                }
3015            })
3016            .detach();
3017            buffer
3018        });
3019
3020        buffers.push(buffer);
3021        replica_ids.push(i as ReplicaId);
3022        network.lock().add_peer(i as ReplicaId);
3023        log::info!("Adding initial peer with replica id {}", i);
3024    }
3025
3026    log::info!("initial text: {:?}", base_text);
3027
3028    let mut now = Instant::now();
3029    let mut mutation_count = operations;
3030    let mut next_diagnostic_id = 0;
3031    let mut active_selections = BTreeMap::default();
3032    loop {
3033        let replica_index = rng.gen_range(0..replica_ids.len());
3034        let replica_id = replica_ids[replica_index];
3035        let buffer = &mut buffers[replica_index];
3036        let mut new_buffer = None;
3037        match rng.gen_range(0..100) {
3038            0..=29 if mutation_count != 0 => {
3039                buffer.update(cx, |buffer, cx| {
3040                    buffer.start_transaction_at(now);
3041                    buffer.randomly_edit(&mut rng, 5, cx);
3042                    buffer.end_transaction_at(now, cx);
3043                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
3044                });
3045                mutation_count -= 1;
3046            }
3047            30..=39 if mutation_count != 0 => {
3048                buffer.update(cx, |buffer, cx| {
3049                    if rng.gen_bool(0.2) {
3050                        log::info!("peer {} clearing active selections", replica_id);
3051                        active_selections.remove(&replica_id);
3052                        buffer.remove_active_selections(cx);
3053                    } else {
3054                        let mut selections = Vec::new();
3055                        for id in 0..rng.gen_range(1..=5) {
3056                            let range = buffer.random_byte_range(0, &mut rng);
3057                            selections.push(Selection {
3058                                id,
3059                                start: buffer.anchor_before(range.start),
3060                                end: buffer.anchor_before(range.end),
3061                                reversed: false,
3062                                goal: SelectionGoal::None,
3063                            });
3064                        }
3065                        let selections: Arc<[Selection<Anchor>]> = selections.into();
3066                        log::info!(
3067                            "peer {} setting active selections: {:?}",
3068                            replica_id,
3069                            selections
3070                        );
3071                        active_selections.insert(replica_id, selections.clone());
3072                        buffer.set_active_selections(selections, false, Default::default(), cx);
3073                    }
3074                });
3075                mutation_count -= 1;
3076            }
3077            40..=49 if mutation_count != 0 && replica_id == 0 => {
3078                let entry_count = rng.gen_range(1..=5);
3079                buffer.update(cx, |buffer, cx| {
3080                    let diagnostics = DiagnosticSet::new(
3081                        (0..entry_count).map(|_| {
3082                            let range = buffer.random_byte_range(0, &mut rng);
3083                            let range = range.to_point_utf16(buffer);
3084                            let range = range.start..range.end;
3085                            DiagnosticEntry {
3086                                range,
3087                                diagnostic: Diagnostic {
3088                                    message: post_inc(&mut next_diagnostic_id).to_string(),
3089                                    ..Default::default()
3090                                },
3091                            }
3092                        }),
3093                        buffer,
3094                    );
3095                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
3096                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
3097                });
3098                mutation_count -= 1;
3099            }
3100            50..=59 if replica_ids.len() < max_peers => {
3101                let old_buffer_state = buffer.read(cx).to_proto(cx);
3102                let old_buffer_ops = cx
3103                    .background_executor()
3104                    .block(buffer.read(cx).serialize_ops(None, cx));
3105                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
3106                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
3107                    .choose(&mut rng)
3108                    .unwrap();
3109                log::info!(
3110                    "Adding new replica {} (replicating from {})",
3111                    new_replica_id,
3112                    replica_id
3113                );
3114                new_buffer = Some(cx.new(|cx| {
3115                    let mut new_buffer = Buffer::from_proto(
3116                        new_replica_id,
3117                        Capability::ReadWrite,
3118                        old_buffer_state,
3119                        None,
3120                    )
3121                    .unwrap();
3122                    new_buffer.apply_ops(
3123                        old_buffer_ops
3124                            .into_iter()
3125                            .map(|op| deserialize_operation(op).unwrap()),
3126                        cx,
3127                    );
3128                    log::info!(
3129                        "New replica {} text: {:?}",
3130                        new_buffer.replica_id(),
3131                        new_buffer.text()
3132                    );
3133                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
3134                    let network = network.clone();
3135                    cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
3136                        if let BufferEvent::Operation {
3137                            operation,
3138                            is_local: true,
3139                        } = event
3140                        {
3141                            network.lock().broadcast(
3142                                buffer.replica_id(),
3143                                vec![proto::serialize_operation(operation)],
3144                            );
3145                        }
3146                    })
3147                    .detach();
3148                    new_buffer
3149                }));
3150                network.lock().replicate(replica_id, new_replica_id);
3151
3152                if new_replica_id as usize == replica_ids.len() {
3153                    replica_ids.push(new_replica_id);
3154                } else {
3155                    let new_buffer = new_buffer.take().unwrap();
3156                    while network.lock().has_unreceived(new_replica_id) {
3157                        let ops = network
3158                            .lock()
3159                            .receive(new_replica_id)
3160                            .into_iter()
3161                            .map(|op| proto::deserialize_operation(op).unwrap());
3162                        if ops.len() > 0 {
3163                            log::info!(
3164                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3165                                new_replica_id,
3166                                buffer.read(cx).version(),
3167                                ops.len(),
3168                                ops
3169                            );
3170                            new_buffer.update(cx, |new_buffer, cx| {
3171                                new_buffer.apply_ops(ops, cx);
3172                            });
3173                        }
3174                    }
3175                    buffers[new_replica_id as usize] = new_buffer;
3176                }
3177            }
3178            60..=69 if mutation_count != 0 => {
3179                buffer.update(cx, |buffer, cx| {
3180                    buffer.randomly_undo_redo(&mut rng, cx);
3181                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
3182                });
3183                mutation_count -= 1;
3184            }
3185            _ if network.lock().has_unreceived(replica_id) => {
3186                let ops = network
3187                    .lock()
3188                    .receive(replica_id)
3189                    .into_iter()
3190                    .map(|op| proto::deserialize_operation(op).unwrap());
3191                if ops.len() > 0 {
3192                    log::info!(
3193                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3194                        replica_id,
3195                        buffer.read(cx).version(),
3196                        ops.len(),
3197                        ops
3198                    );
3199                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx));
3200                }
3201            }
3202            _ => {}
3203        }
3204
3205        now += Duration::from_millis(rng.gen_range(0..=200));
3206        buffers.extend(new_buffer);
3207
3208        for buffer in &buffers {
3209            buffer.read(cx).check_invariants();
3210        }
3211
3212        if mutation_count == 0 && network.lock().is_idle() {
3213            break;
3214        }
3215    }
3216
3217    let first_buffer = buffers[0].read(cx).snapshot();
3218    for buffer in &buffers[1..] {
3219        let buffer = buffer.read(cx).snapshot();
3220        assert_eq!(
3221            buffer.version(),
3222            first_buffer.version(),
3223            "Replica {} version != Replica 0 version",
3224            buffer.replica_id()
3225        );
3226        assert_eq!(
3227            buffer.text(),
3228            first_buffer.text(),
3229            "Replica {} text != Replica 0 text",
3230            buffer.replica_id()
3231        );
3232        assert_eq!(
3233            buffer
3234                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
3235                .collect::<Vec<_>>(),
3236            first_buffer
3237                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
3238                .collect::<Vec<_>>(),
3239            "Replica {} diagnostics != Replica 0 diagnostics",
3240            buffer.replica_id()
3241        );
3242    }
3243
3244    for buffer in &buffers {
3245        let buffer = buffer.read(cx).snapshot();
3246        let actual_remote_selections = buffer
3247            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
3248            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
3249            .collect::<Vec<_>>();
3250        let expected_remote_selections = active_selections
3251            .iter()
3252            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
3253            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
3254            .collect::<Vec<_>>();
3255        assert_eq!(
3256            actual_remote_selections,
3257            expected_remote_selections,
3258            "Replica {} remote selections != expected selections",
3259            buffer.replica_id()
3260        );
3261    }
3262}
3263
3264#[test]
3265fn test_contiguous_ranges() {
3266    assert_eq!(
3267        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
3268        &[1..4, 5..7, 9..13]
3269    );
3270
3271    // Respects the `max_len` parameter
3272    assert_eq!(
3273        contiguous_ranges(
3274            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
3275            3
3276        )
3277        .collect::<Vec<_>>(),
3278        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
3279    );
3280}
3281
3282#[gpui::test(iterations = 500)]
3283fn test_trailing_whitespace_ranges(mut rng: StdRng) {
3284    // Generate a random multi-line string containing
3285    // some lines with trailing whitespace.
3286    let mut text = String::new();
3287    for _ in 0..rng.gen_range(0..16) {
3288        for _ in 0..rng.gen_range(0..36) {
3289            text.push(match rng.gen_range(0..10) {
3290                0..=1 => ' ',
3291                3 => '\t',
3292                _ => rng.gen_range('a'..='z'),
3293            });
3294        }
3295        text.push('\n');
3296    }
3297
3298    match rng.gen_range(0..10) {
3299        // sometimes remove the last newline
3300        0..=1 => drop(text.pop()), //
3301
3302        // sometimes add extra newlines
3303        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
3304        _ => {}
3305    }
3306
3307    let rope = Rope::from(text.as_str());
3308    let actual_ranges = trailing_whitespace_ranges(&rope);
3309    let expected_ranges = TRAILING_WHITESPACE_REGEX
3310        .find_iter(&text)
3311        .map(|m| m.range())
3312        .collect::<Vec<_>>();
3313    assert_eq!(
3314        actual_ranges,
3315        expected_ranges,
3316        "wrong ranges for text lines:\n{:?}",
3317        text.split('\n').collect::<Vec<_>>()
3318    );
3319}
3320
3321#[gpui::test]
3322fn test_words_in_range(cx: &mut gpui::App) {
3323    init_settings(cx, |_| {});
3324
3325    // The first line are words excluded from the results with heuristics, we do not expect them in the test assertions.
3326    let contents = r#"
33270_isize 123 3.4 4  
3328let word=öäpple.bar你 Öäpple word2-öÄpPlE-Pizza-word ÖÄPPLE word
3329    "#;
3330
3331    let buffer = cx.new(|cx| {
3332        let buffer = Buffer::local(contents, cx).with_language(Arc::new(rust_lang()), cx);
3333        assert_eq!(buffer.text(), contents);
3334        buffer.check_invariants();
3335        buffer
3336    });
3337
3338    buffer.update(cx, |buffer, _| {
3339        let snapshot = buffer.snapshot();
3340        assert_eq!(
3341            BTreeSet::from_iter(["Pizza".to_string()]),
3342            snapshot
3343                .words_in_range(WordsQuery {
3344                    fuzzy_contents: Some("piz"),
3345                    skip_digits: true,
3346                    range: 0..snapshot.len(),
3347                })
3348                .into_keys()
3349                .collect::<BTreeSet<_>>()
3350        );
3351        assert_eq!(
3352            BTreeSet::from_iter([
3353                "öäpple".to_string(),
3354                "Öäpple".to_string(),
3355                "öÄpPlE".to_string(),
3356                "ÖÄPPLE".to_string(),
3357            ]),
3358            snapshot
3359                .words_in_range(WordsQuery {
3360                    fuzzy_contents: Some("öp"),
3361                    skip_digits: true,
3362                    range: 0..snapshot.len(),
3363                })
3364                .into_keys()
3365                .collect::<BTreeSet<_>>()
3366        );
3367        assert_eq!(
3368            BTreeSet::from_iter([
3369                "öÄpPlE".to_string(),
3370                "Öäpple".to_string(),
3371                "ÖÄPPLE".to_string(),
3372                "öäpple".to_string(),
3373            ]),
3374            snapshot
3375                .words_in_range(WordsQuery {
3376                    fuzzy_contents: Some("öÄ"),
3377                    skip_digits: true,
3378                    range: 0..snapshot.len(),
3379                })
3380                .into_keys()
3381                .collect::<BTreeSet<_>>()
3382        );
3383        assert_eq!(
3384            BTreeSet::default(),
3385            snapshot
3386                .words_in_range(WordsQuery {
3387                    fuzzy_contents: Some("öÄ好"),
3388                    skip_digits: true,
3389                    range: 0..snapshot.len(),
3390                })
3391                .into_keys()
3392                .collect::<BTreeSet<_>>()
3393        );
3394        assert_eq!(
3395            BTreeSet::from_iter(["bar你".to_string(),]),
3396            snapshot
3397                .words_in_range(WordsQuery {
3398                    fuzzy_contents: Some(""),
3399                    skip_digits: true,
3400                    range: 0..snapshot.len(),
3401                })
3402                .into_keys()
3403                .collect::<BTreeSet<_>>()
3404        );
3405        assert_eq!(
3406            BTreeSet::default(),
3407            snapshot
3408                .words_in_range(WordsQuery {
3409                    fuzzy_contents: Some(""),
3410                    skip_digits: true,
3411                    range: 0..snapshot.len(),
3412                },)
3413                .into_keys()
3414                .collect::<BTreeSet<_>>()
3415        );
3416        assert_eq!(
3417            BTreeSet::from_iter([
3418                "bar你".to_string(),
3419                "öÄpPlE".to_string(),
3420                "Öäpple".to_string(),
3421                "ÖÄPPLE".to_string(),
3422                "öäpple".to_string(),
3423                "let".to_string(),
3424                "Pizza".to_string(),
3425                "word".to_string(),
3426                "word2".to_string(),
3427            ]),
3428            snapshot
3429                .words_in_range(WordsQuery {
3430                    fuzzy_contents: None,
3431                    skip_digits: true,
3432                    range: 0..snapshot.len(),
3433                })
3434                .into_keys()
3435                .collect::<BTreeSet<_>>()
3436        );
3437        assert_eq!(
3438            BTreeSet::from_iter([
3439                "0_isize".to_string(),
3440                "123".to_string(),
3441                "3".to_string(),
3442                "4".to_string(),
3443                "bar你".to_string(),
3444                "öÄpPlE".to_string(),
3445                "Öäpple".to_string(),
3446                "ÖÄPPLE".to_string(),
3447                "öäpple".to_string(),
3448                "let".to_string(),
3449                "Pizza".to_string(),
3450                "word".to_string(),
3451                "word2".to_string(),
3452            ]),
3453            snapshot
3454                .words_in_range(WordsQuery {
3455                    fuzzy_contents: None,
3456                    skip_digits: false,
3457                    range: 0..snapshot.len(),
3458                })
3459                .into_keys()
3460                .collect::<BTreeSet<_>>()
3461        );
3462    });
3463}
3464
3465fn ruby_lang() -> Language {
3466    Language::new(
3467        LanguageConfig {
3468            name: "Ruby".into(),
3469            matcher: LanguageMatcher {
3470                path_suffixes: vec!["rb".to_string()],
3471                ..Default::default()
3472            },
3473            line_comments: vec!["# ".into()],
3474            ..Default::default()
3475        },
3476        Some(tree_sitter_ruby::LANGUAGE.into()),
3477    )
3478    .with_indents_query(
3479        r#"
3480            (class "end" @end) @indent
3481            (method "end" @end) @indent
3482            (rescue) @outdent
3483            (then) @indent
3484        "#,
3485    )
3486    .unwrap()
3487}
3488
3489fn html_lang() -> Language {
3490    Language::new(
3491        LanguageConfig {
3492            name: LanguageName::new("HTML"),
3493            block_comment: Some(("<!--".into(), "-->".into())),
3494            ..Default::default()
3495        },
3496        Some(tree_sitter_html::LANGUAGE.into()),
3497    )
3498    .with_indents_query(
3499        "
3500        (element
3501          (start_tag) @start
3502          (end_tag)? @end) @indent
3503        ",
3504    )
3505    .unwrap()
3506    .with_injection_query(
3507        r#"
3508        (script_element
3509            (raw_text) @injection.content
3510            (#set! injection.language "javascript"))
3511        "#,
3512    )
3513    .unwrap()
3514}
3515
3516fn erb_lang() -> Language {
3517    Language::new(
3518        LanguageConfig {
3519            name: "ERB".into(),
3520            matcher: LanguageMatcher {
3521                path_suffixes: vec!["erb".to_string()],
3522                ..Default::default()
3523            },
3524            block_comment: Some(("<%#".into(), "%>".into())),
3525            ..Default::default()
3526        },
3527        Some(tree_sitter_embedded_template::LANGUAGE.into()),
3528    )
3529    .with_injection_query(
3530        r#"
3531            (
3532                (code) @injection.content
3533                (#set! injection.language "ruby")
3534                (#set! injection.combined)
3535            )
3536
3537            (
3538                (content) @injection.content
3539                (#set! injection.language "html")
3540                (#set! injection.combined)
3541            )
3542        "#,
3543    )
3544    .unwrap()
3545}
3546
3547fn rust_lang() -> Language {
3548    Language::new(
3549        LanguageConfig {
3550            name: "Rust".into(),
3551            matcher: LanguageMatcher {
3552                path_suffixes: vec!["rs".to_string()],
3553                ..Default::default()
3554            },
3555            ..Default::default()
3556        },
3557        Some(tree_sitter_rust::LANGUAGE.into()),
3558    )
3559    .with_indents_query(
3560        r#"
3561        (call_expression) @indent
3562        (field_expression) @indent
3563        (_ "(" ")" @end) @indent
3564        (_ "{" "}" @end) @indent
3565        "#,
3566    )
3567    .unwrap()
3568    .with_brackets_query(
3569        r#"
3570        ("{" @open "}" @close)
3571        "#,
3572    )
3573    .unwrap()
3574    .with_text_object_query(
3575        r#"
3576        (function_item
3577            body: (_
3578                "{"
3579                (_)* @function.inside
3580                "}" )) @function.around
3581
3582        (line_comment)+ @comment.around
3583
3584        (block_comment) @comment.around
3585        "#,
3586    )
3587    .unwrap()
3588    .with_outline_query(
3589        r#"
3590        (line_comment) @annotation
3591
3592        (struct_item
3593            "struct" @context
3594            name: (_) @name) @item
3595        (enum_item
3596            "enum" @context
3597            name: (_) @name) @item
3598        (enum_variant
3599            name: (_) @name) @item
3600        (field_declaration
3601            name: (_) @name) @item
3602        (impl_item
3603            "impl" @context
3604            trait: (_)? @name
3605            "for"? @context
3606            type: (_) @name
3607            body: (_ "{" (_)* "}")) @item
3608        (function_item
3609            "fn" @context
3610            name: (_) @name) @item
3611        (mod_item
3612            "mod" @context
3613            name: (_) @name) @item
3614        "#,
3615    )
3616    .unwrap()
3617}
3618
3619fn json_lang() -> Language {
3620    Language::new(
3621        LanguageConfig {
3622            name: "Json".into(),
3623            matcher: LanguageMatcher {
3624                path_suffixes: vec!["js".to_string()],
3625                ..Default::default()
3626            },
3627            ..Default::default()
3628        },
3629        Some(tree_sitter_json::LANGUAGE.into()),
3630    )
3631}
3632
3633fn javascript_lang() -> Language {
3634    Language::new(
3635        LanguageConfig {
3636            name: "JavaScript".into(),
3637            ..Default::default()
3638        },
3639        Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
3640    )
3641    .with_brackets_query(
3642        r#"
3643        ("{" @open "}" @close)
3644        ("(" @open ")" @close)
3645        "#,
3646    )
3647    .unwrap()
3648    .with_indents_query(
3649        r#"
3650        (object "}" @end) @indent
3651        "#,
3652    )
3653    .unwrap()
3654}
3655
3656pub fn markdown_lang() -> Language {
3657    Language::new(
3658        LanguageConfig {
3659            name: "Markdown".into(),
3660            matcher: LanguageMatcher {
3661                path_suffixes: vec!["md".into()],
3662                ..Default::default()
3663            },
3664            ..Default::default()
3665        },
3666        Some(tree_sitter_md::LANGUAGE.into()),
3667    )
3668    .with_injection_query(
3669        r#"
3670            (fenced_code_block
3671                (info_string
3672                    (language) @injection.language)
3673                (code_fence_content) @injection.content)
3674
3675                ((inline) @injection.content
3676                (#set! injection.language "markdown-inline"))
3677        "#,
3678    )
3679    .unwrap()
3680}
3681
3682pub fn markdown_inline_lang() -> Language {
3683    Language::new(
3684        LanguageConfig {
3685            name: "Markdown-Inline".into(),
3686            hidden: true,
3687            ..LanguageConfig::default()
3688        },
3689        Some(tree_sitter_md::INLINE_LANGUAGE.into()),
3690    )
3691    .with_highlights_query("(emphasis) @emphasis")
3692    .unwrap()
3693}
3694
3695fn get_tree_sexp(buffer: &Entity<Buffer>, cx: &mut gpui::TestAppContext) -> String {
3696    buffer.update(cx, |buffer, _| {
3697        let snapshot = buffer.snapshot();
3698        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
3699        layers[0].node().to_sexp()
3700    })
3701}
3702
3703// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
3704#[track_caller]
3705fn assert_bracket_pairs(
3706    selection_text: &'static str,
3707    bracket_pair_texts: Vec<&'static str>,
3708    language: Language,
3709    cx: &mut App,
3710) {
3711    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
3712    let buffer =
3713        cx.new(|cx| Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx));
3714    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
3715
3716    let selection_range = selection_ranges[0].clone();
3717
3718    let bracket_pairs = bracket_pair_texts
3719        .into_iter()
3720        .map(|pair_text| {
3721            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
3722            assert_eq!(bracket_text, expected_text);
3723            (ranges[0].clone(), ranges[1].clone())
3724        })
3725        .collect::<Vec<_>>();
3726
3727    assert_set_eq!(
3728        buffer
3729            .bracket_ranges(selection_range)
3730            .map(|pair| (pair.open_range, pair.close_range))
3731            .collect::<Vec<_>>(),
3732        bracket_pairs
3733    );
3734}
3735
3736fn init_settings(cx: &mut App, f: fn(&mut AllLanguageSettingsContent)) {
3737    let settings_store = SettingsStore::test(cx);
3738    cx.set_global(settings_store);
3739    crate::init(cx);
3740    cx.update_global::<SettingsStore, _>(|settings, cx| {
3741        settings.update_user_settings::<AllLanguageSettings>(cx, f);
3742    });
3743}