buffer_tests.rs

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