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    let (text, offsets) = marked_text_offsets(
1057        &"
1058        // ˇ😅 //
1059        fn test() {
1060        }
1061    "
1062        .unindent(),
1063    );
1064    let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
1065    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
1066
1067    // note, it would be nice to actually return the method test in this
1068    // case, but primarily asserting we don't crash because of the multibyte character.
1069    assert_eq!(snapshot.symbols_containing(offsets[0], None), vec![]);
1070}
1071
1072#[gpui::test]
1073fn test_text_objects(cx: &mut App) {
1074    let (text, ranges) = marked_text_ranges(
1075        indoc! {r#"
1076            impl Hello {
1077                fn say() -> u8 { return /* ˇhi */ 1 }
1078            }"#
1079        },
1080        false,
1081    );
1082
1083    let buffer =
1084        cx.new(|cx| Buffer::local(text.clone(), cx).with_language(Arc::new(rust_lang()), cx));
1085    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
1086
1087    let matches = snapshot
1088        .text_object_ranges(ranges[0].clone(), TreeSitterOptions::default())
1089        .map(|(range, text_object)| (&text[range], text_object))
1090        .collect::<Vec<_>>();
1091
1092    assert_eq!(
1093        matches,
1094        &[
1095            ("/* hi */", TextObject::AroundComment),
1096            ("return /* hi */ 1", TextObject::InsideFunction),
1097            (
1098                "fn say() -> u8 { return /* hi */ 1 }",
1099                TextObject::AroundFunction
1100            ),
1101        ],
1102    )
1103}
1104
1105#[gpui::test]
1106fn test_enclosing_bracket_ranges(cx: &mut App) {
1107    let mut assert = |selection_text, range_markers| {
1108        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
1109    };
1110
1111    assert(
1112        indoc! {"
1113            mod x {
1114                moˇd y {
1115
1116                }
1117            }
1118            let foo = 1;"},
1119        vec![indoc! {"
1120            mod x «{»
1121                mod y {
1122
1123                }
1124            «}»
1125            let foo = 1;"}],
1126    );
1127
1128    assert(
1129        indoc! {"
1130            mod x {
1131                mod y ˇ{
1132
1133                }
1134            }
1135            let foo = 1;"},
1136        vec![
1137            indoc! {"
1138                mod x «{»
1139                    mod y {
1140
1141                    }
1142                «}»
1143                let foo = 1;"},
1144            indoc! {"
1145                mod x {
1146                    mod y «{»
1147
1148                    «}»
1149                }
1150                let foo = 1;"},
1151        ],
1152    );
1153
1154    assert(
1155        indoc! {"
1156            mod x {
1157                mod y {
1158
11591160            }
1161            let foo = 1;"},
1162        vec![
1163            indoc! {"
1164                mod x «{»
1165                    mod y {
1166
1167                    }
1168                «}»
1169                let foo = 1;"},
1170            indoc! {"
1171                mod x {
1172                    mod y «{»
1173
1174                    «}»
1175                }
1176                let foo = 1;"},
1177        ],
1178    );
1179
1180    assert(
1181        indoc! {"
1182            mod x {
1183                mod y {
1184
1185                }
1186            ˇ}
1187            let foo = 1;"},
1188        vec![indoc! {"
1189            mod x «{»
1190                mod y {
1191
1192                }
1193            «}»
1194            let foo = 1;"}],
1195    );
1196
1197    assert(
1198        indoc! {"
1199            mod x {
1200                mod y {
1201
1202                }
1203            }
1204            let fˇoo = 1;"},
1205        vec![],
1206    );
1207
1208    // Regression test: avoid crash when querying at the end of the buffer.
1209    assert(
1210        indoc! {"
1211            mod x {
1212                mod y {
1213
1214                }
1215            }
1216            let foo = 1;ˇ"},
1217        vec![],
1218    );
1219}
1220
1221#[gpui::test]
1222fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut App) {
1223    let mut assert = |selection_text, bracket_pair_texts| {
1224        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
1225    };
1226
1227    assert(
1228        indoc! {"
1229        for (const a in b)ˇ {
1230            // a comment that's longer than the for-loop header
1231        }"},
1232        vec![indoc! {"
1233        for «(»const a in b«)» {
1234            // a comment that's longer than the for-loop header
1235        }"}],
1236    );
1237
1238    // Regression test: even though the parent node of the parentheses (the for loop) does
1239    // intersect the given range, the parentheses themselves do not contain the range, so
1240    // they should not be returned. Only the curly braces contain the range.
1241    assert(
1242        indoc! {"
1243        for (const a in b) {ˇ
1244            // a comment that's longer than the for-loop header
1245        }"},
1246        vec![indoc! {"
1247        for (const a in b) «{»
1248            // a comment that's longer than the for-loop header
1249        «}»"}],
1250    );
1251}
1252
1253#[gpui::test]
1254fn test_range_for_syntax_ancestor(cx: &mut App) {
1255    cx.new(|cx| {
1256        let text = "fn a() { b(|c| {}) }";
1257        let buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1258        let snapshot = buffer.snapshot();
1259
1260        assert_eq!(
1261            snapshot
1262                .syntax_ancestor(empty_range_at(text, "|"))
1263                .unwrap()
1264                .byte_range(),
1265            range_of(text, "|")
1266        );
1267        assert_eq!(
1268            snapshot
1269                .syntax_ancestor(range_of(text, "|"))
1270                .unwrap()
1271                .byte_range(),
1272            range_of(text, "|c|")
1273        );
1274        assert_eq!(
1275            snapshot
1276                .syntax_ancestor(range_of(text, "|c|"))
1277                .unwrap()
1278                .byte_range(),
1279            range_of(text, "|c| {}")
1280        );
1281        assert_eq!(
1282            snapshot
1283                .syntax_ancestor(range_of(text, "|c| {}"))
1284                .unwrap()
1285                .byte_range(),
1286            range_of(text, "(|c| {})")
1287        );
1288
1289        buffer
1290    });
1291
1292    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
1293        let start = text.find(part).unwrap();
1294        start..start
1295    }
1296
1297    fn range_of(text: &str, part: &str) -> Range<usize> {
1298        let start = text.find(part).unwrap();
1299        start..start + part.len()
1300    }
1301}
1302
1303#[gpui::test]
1304fn test_autoindent_with_soft_tabs(cx: &mut App) {
1305    init_settings(cx, |_| {});
1306
1307    cx.new(|cx| {
1308        let text = "fn a() {}";
1309        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1310
1311        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1312        assert_eq!(buffer.text(), "fn a() {\n    \n}");
1313
1314        buffer.edit(
1315            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
1316            Some(AutoindentMode::EachLine),
1317            cx,
1318        );
1319        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
1320
1321        // Create a field expression on a new line, causing that line
1322        // to be indented.
1323        buffer.edit(
1324            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
1325            Some(AutoindentMode::EachLine),
1326            cx,
1327        );
1328        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
1329
1330        // Remove the dot so that the line is no longer a field expression,
1331        // causing the line to be outdented.
1332        buffer.edit(
1333            [(Point::new(2, 8)..Point::new(2, 9), "")],
1334            Some(AutoindentMode::EachLine),
1335            cx,
1336        );
1337        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
1338
1339        buffer
1340    });
1341}
1342
1343#[gpui::test]
1344fn test_autoindent_with_hard_tabs(cx: &mut App) {
1345    init_settings(cx, |settings| {
1346        settings.defaults.hard_tabs = Some(true);
1347    });
1348
1349    cx.new(|cx| {
1350        let text = "fn a() {}";
1351        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1352
1353        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
1354        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
1355
1356        buffer.edit(
1357            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
1358            Some(AutoindentMode::EachLine),
1359            cx,
1360        );
1361        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
1362
1363        // Create a field expression on a new line, causing that line
1364        // to be indented.
1365        buffer.edit(
1366            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
1367            Some(AutoindentMode::EachLine),
1368            cx,
1369        );
1370        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
1371
1372        // Remove the dot so that the line is no longer a field expression,
1373        // causing the line to be outdented.
1374        buffer.edit(
1375            [(Point::new(2, 2)..Point::new(2, 3), "")],
1376            Some(AutoindentMode::EachLine),
1377            cx,
1378        );
1379        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1380
1381        buffer
1382    });
1383}
1384
1385#[gpui::test]
1386fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut App) {
1387    init_settings(cx, |_| {});
1388
1389    cx.new(|cx| {
1390        let mut buffer = Buffer::local(
1391            "
1392            fn a() {
1393            c;
1394            d;
1395            }
1396            "
1397            .unindent(),
1398            cx,
1399        )
1400        .with_language(Arc::new(rust_lang()), cx);
1401
1402        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1403        // their indentation is not adjusted.
1404        buffer.edit_via_marked_text(
1405            &"
1406            fn a() {
1407            c«()»;
1408            d«()»;
1409            }
1410            "
1411            .unindent(),
1412            Some(AutoindentMode::EachLine),
1413            cx,
1414        );
1415        assert_eq!(
1416            buffer.text(),
1417            "
1418            fn a() {
1419            c();
1420            d();
1421            }
1422            "
1423            .unindent()
1424        );
1425
1426        // When appending new content after these lines, the indentation is based on the
1427        // preceding lines' actual indentation.
1428        buffer.edit_via_marked_text(
1429            &"
1430            fn a() {
14311432            .f
1433            .g()»;
14341435            .f
1436            .g()»;
1437            }
1438            "
1439            .unindent(),
1440            Some(AutoindentMode::EachLine),
1441            cx,
1442        );
1443        assert_eq!(
1444            buffer.text(),
1445            "
1446            fn a() {
1447            c
1448                .f
1449                .g();
1450            d
1451                .f
1452                .g();
1453            }
1454            "
1455            .unindent()
1456        );
1457
1458        // Insert a newline after the open brace. It is auto-indented
1459        buffer.edit_via_marked_text(
1460            &"
1461            fn a() {«
1462            »
1463            c
1464                .f
1465                .g();
1466            d
1467                .f
1468                .g();
1469            }
1470            "
1471            .unindent(),
1472            Some(AutoindentMode::EachLine),
1473            cx,
1474        );
1475        assert_eq!(
1476            buffer.text(),
1477            "
1478            fn a() {
1479                ˇ
1480            c
1481                .f
1482                .g();
1483            d
1484                .f
1485                .g();
1486            }
1487            "
1488            .unindent()
1489            .replace("ˇ", "")
1490        );
1491
1492        // Manually outdent the line. It stays outdented.
1493        buffer.edit_via_marked_text(
1494            &"
1495            fn a() {
1496            «»
1497            c
1498                .f
1499                .g();
1500            d
1501                .f
1502                .g();
1503            }
1504            "
1505            .unindent(),
1506            Some(AutoindentMode::EachLine),
1507            cx,
1508        );
1509        assert_eq!(
1510            buffer.text(),
1511            "
1512            fn a() {
1513
1514            c
1515                .f
1516                .g();
1517            d
1518                .f
1519                .g();
1520            }
1521            "
1522            .unindent()
1523        );
1524
1525        buffer
1526    });
1527
1528    cx.new(|cx| {
1529        eprintln!("second buffer: {:?}", cx.entity_id());
1530
1531        let mut buffer = Buffer::local(
1532            "
1533            fn a() {
1534                b();
1535                |
1536            "
1537            .replace('|', "") // marker to preserve trailing whitespace
1538            .unindent(),
1539            cx,
1540        )
1541        .with_language(Arc::new(rust_lang()), cx);
1542
1543        // Insert a closing brace. It is outdented.
1544        buffer.edit_via_marked_text(
1545            &"
1546            fn a() {
1547                b();
1548                «}»
1549            "
1550            .unindent(),
1551            Some(AutoindentMode::EachLine),
1552            cx,
1553        );
1554        assert_eq!(
1555            buffer.text(),
1556            "
1557            fn a() {
1558                b();
1559            }
1560            "
1561            .unindent()
1562        );
1563
1564        // Manually edit the leading whitespace. The edit is preserved.
1565        buffer.edit_via_marked_text(
1566            &"
1567            fn a() {
1568                b();
1569            «    »}
1570            "
1571            .unindent(),
1572            Some(AutoindentMode::EachLine),
1573            cx,
1574        );
1575        assert_eq!(
1576            buffer.text(),
1577            "
1578            fn a() {
1579                b();
1580                }
1581            "
1582            .unindent()
1583        );
1584        buffer
1585    });
1586
1587    eprintln!("DONE");
1588}
1589
1590#[gpui::test]
1591fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut App) {
1592    init_settings(cx, |_| {});
1593
1594    cx.new(|cx| {
1595        let mut buffer = Buffer::local(
1596            "
1597            fn a() {
1598                i
1599            }
1600            "
1601            .unindent(),
1602            cx,
1603        )
1604        .with_language(Arc::new(rust_lang()), cx);
1605
1606        // Regression test: line does not get outdented due to syntax error
1607        buffer.edit_via_marked_text(
1608            &"
1609            fn a() {
1610                i«f let Some(x) = y»
1611            }
1612            "
1613            .unindent(),
1614            Some(AutoindentMode::EachLine),
1615            cx,
1616        );
1617        assert_eq!(
1618            buffer.text(),
1619            "
1620            fn a() {
1621                if let Some(x) = y
1622            }
1623            "
1624            .unindent()
1625        );
1626
1627        buffer.edit_via_marked_text(
1628            &"
1629            fn a() {
1630                if let Some(x) = y« {»
1631            }
1632            "
1633            .unindent(),
1634            Some(AutoindentMode::EachLine),
1635            cx,
1636        );
1637        assert_eq!(
1638            buffer.text(),
1639            "
1640            fn a() {
1641                if let Some(x) = y {
1642            }
1643            "
1644            .unindent()
1645        );
1646
1647        buffer
1648    });
1649}
1650
1651#[gpui::test]
1652fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut App) {
1653    init_settings(cx, |_| {});
1654
1655    cx.new(|cx| {
1656        let mut buffer = Buffer::local(
1657            "
1658            fn a() {}
1659            "
1660            .unindent(),
1661            cx,
1662        )
1663        .with_language(Arc::new(rust_lang()), cx);
1664
1665        buffer.edit_via_marked_text(
1666            &"
1667            fn a(«
1668            b») {}
1669            "
1670            .unindent(),
1671            Some(AutoindentMode::EachLine),
1672            cx,
1673        );
1674        assert_eq!(
1675            buffer.text(),
1676            "
1677            fn a(
1678                b) {}
1679            "
1680            .unindent()
1681        );
1682
1683        // The indentation suggestion changed because `@end` node (a close paren)
1684        // is now at the beginning of the line.
1685        buffer.edit_via_marked_text(
1686            &"
1687            fn a(
1688                ˇ) {}
1689            "
1690            .unindent(),
1691            Some(AutoindentMode::EachLine),
1692            cx,
1693        );
1694        assert_eq!(
1695            buffer.text(),
1696            "
1697                fn a(
1698                ) {}
1699            "
1700            .unindent()
1701        );
1702
1703        buffer
1704    });
1705}
1706
1707#[gpui::test]
1708fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut App) {
1709    init_settings(cx, |_| {});
1710
1711    cx.new(|cx| {
1712        let text = "a\nb";
1713        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1714        buffer.edit(
1715            [(0..1, "\n"), (2..3, "\n")],
1716            Some(AutoindentMode::EachLine),
1717            cx,
1718        );
1719        assert_eq!(buffer.text(), "\n\n\n");
1720        buffer
1721    });
1722}
1723
1724#[gpui::test]
1725fn test_autoindent_multi_line_insertion(cx: &mut App) {
1726    init_settings(cx, |_| {});
1727
1728    cx.new(|cx| {
1729        let text = "
1730            const a: usize = 1;
1731            fn b() {
1732                if c {
1733                    let d = 2;
1734                }
1735            }
1736        "
1737        .unindent();
1738
1739        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1740        buffer.edit(
1741            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1742            Some(AutoindentMode::EachLine),
1743            cx,
1744        );
1745        assert_eq!(
1746            buffer.text(),
1747            "
1748                const a: usize = 1;
1749                fn b() {
1750                    if c {
1751                        e(
1752                            f()
1753                        );
1754                        let d = 2;
1755                    }
1756                }
1757            "
1758            .unindent()
1759        );
1760
1761        buffer
1762    });
1763}
1764
1765#[gpui::test]
1766fn test_autoindent_block_mode(cx: &mut App) {
1767    init_settings(cx, |_| {});
1768
1769    cx.new(|cx| {
1770        let text = r#"
1771            fn a() {
1772                b();
1773            }
1774        "#
1775        .unindent();
1776        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1777
1778        // When this text was copied, both of the quotation marks were at the same
1779        // indent level, but the indentation of the first line was not included in
1780        // the copied text. This information is retained in the
1781        // 'original_indent_columns' vector.
1782        let original_indent_columns = vec![Some(4)];
1783        let inserted_text = r#"
1784            "
1785                  c
1786                    d
1787                      e
1788                "
1789        "#
1790        .unindent();
1791
1792        // Insert the block at column zero. The entire block is indented
1793        // so that the first line matches the previous line's indentation.
1794        buffer.edit(
1795            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1796            Some(AutoindentMode::Block {
1797                original_indent_columns: original_indent_columns.clone(),
1798            }),
1799            cx,
1800        );
1801        assert_eq!(
1802            buffer.text(),
1803            r#"
1804            fn a() {
1805                b();
1806                "
1807                  c
1808                    d
1809                      e
1810                "
1811            }
1812            "#
1813            .unindent()
1814        );
1815
1816        // Grouping is disabled in tests, so we need 2 undos
1817        buffer.undo(cx); // Undo the auto-indent
1818        buffer.undo(cx); // Undo the original edit
1819
1820        // Insert the block at a deeper indent level. The entire block is outdented.
1821        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1822        buffer.edit(
1823            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1824            Some(AutoindentMode::Block {
1825                original_indent_columns,
1826            }),
1827            cx,
1828        );
1829        assert_eq!(
1830            buffer.text(),
1831            r#"
1832            fn a() {
1833                b();
1834                "
1835                  c
1836                    d
1837                      e
1838                "
1839            }
1840            "#
1841            .unindent()
1842        );
1843
1844        buffer
1845    });
1846}
1847
1848#[gpui::test]
1849fn test_autoindent_block_mode_with_newline(cx: &mut App) {
1850    init_settings(cx, |_| {});
1851
1852    cx.new(|cx| {
1853        let text = r#"
1854            fn a() {
1855                b();
1856            }
1857        "#
1858        .unindent();
1859        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1860
1861        // First line contains just '\n', it's indentation is stored in "original_indent_columns"
1862        let original_indent_columns = vec![Some(4)];
1863        let inserted_text = r#"
1864
1865                c();
1866                    d();
1867                        e();
1868        "#
1869        .unindent();
1870        buffer.edit(
1871            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1872            Some(AutoindentMode::Block {
1873                original_indent_columns,
1874            }),
1875            cx,
1876        );
1877
1878        // While making edit, we ignore first line as it only contains '\n'
1879        // hence second line indent is used to calculate delta
1880        assert_eq!(
1881            buffer.text(),
1882            r#"
1883            fn a() {
1884                b();
1885
1886                c();
1887                    d();
1888                        e();
1889            }
1890            "#
1891            .unindent()
1892        );
1893
1894        buffer
1895    });
1896}
1897
1898#[gpui::test]
1899fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut App) {
1900    init_settings(cx, |_| {});
1901
1902    cx.new(|cx| {
1903        let text = r#"
1904            fn a() {
1905                if b() {
1906
1907                }
1908            }
1909        "#
1910        .unindent();
1911        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
1912
1913        // The original indent columns are not known, so this text is
1914        // auto-indented in a block as if the first line was copied in
1915        // its entirety.
1916        let original_indent_columns = Vec::new();
1917        let inserted_text = "    c\n        .d()\n        .e();";
1918
1919        // Insert the block at column zero. The entire block is indented
1920        // so that the first line matches the previous line's indentation.
1921        buffer.edit(
1922            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1923            Some(AutoindentMode::Block {
1924                original_indent_columns,
1925            }),
1926            cx,
1927        );
1928        assert_eq!(
1929            buffer.text(),
1930            r#"
1931            fn a() {
1932                if b() {
1933                    c
1934                        .d()
1935                        .e();
1936                }
1937            }
1938            "#
1939            .unindent()
1940        );
1941
1942        // Grouping is disabled in tests, so we need 2 undos
1943        buffer.undo(cx); // Undo the auto-indent
1944        buffer.undo(cx); // Undo the original edit
1945
1946        // Insert the block at a deeper indent level. The entire block is outdented.
1947        buffer.edit(
1948            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1949            None,
1950            cx,
1951        );
1952        buffer.edit(
1953            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1954            Some(AutoindentMode::Block {
1955                original_indent_columns: Vec::new(),
1956            }),
1957            cx,
1958        );
1959        assert_eq!(
1960            buffer.text(),
1961            r#"
1962            fn a() {
1963                if b() {
1964                    c
1965                        .d()
1966                        .e();
1967                }
1968            }
1969            "#
1970            .unindent()
1971        );
1972
1973        buffer
1974    });
1975}
1976
1977#[gpui::test]
1978fn test_autoindent_block_mode_multiple_adjacent_ranges(cx: &mut App) {
1979    init_settings(cx, |_| {});
1980
1981    cx.new(|cx| {
1982        let (text, ranges_to_replace) = marked_text_ranges(
1983            &"
1984            mod numbers {
1985                «fn one() {
1986                    1
1987                }
1988            »
1989                «fn two() {
1990                    2
1991                }
1992            »
1993                «fn three() {
1994                    3
1995                }
1996            »}
1997            "
1998            .unindent(),
1999            false,
2000        );
2001
2002        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
2003
2004        buffer.edit(
2005            [
2006                (ranges_to_replace[0].clone(), "fn one() {\n    101\n}\n"),
2007                (ranges_to_replace[1].clone(), "fn two() {\n    102\n}\n"),
2008                (ranges_to_replace[2].clone(), "fn three() {\n    103\n}\n"),
2009            ],
2010            Some(AutoindentMode::Block {
2011                original_indent_columns: vec![Some(0), Some(0), Some(0)],
2012            }),
2013            cx,
2014        );
2015
2016        pretty_assertions::assert_eq!(
2017            buffer.text(),
2018            "
2019            mod numbers {
2020                fn one() {
2021                    101
2022                }
2023
2024                fn two() {
2025                    102
2026                }
2027
2028                fn three() {
2029                    103
2030                }
2031            }
2032            "
2033            .unindent()
2034        );
2035
2036        buffer
2037    });
2038}
2039
2040#[gpui::test]
2041fn test_autoindent_language_without_indents_query(cx: &mut App) {
2042    init_settings(cx, |_| {});
2043
2044    cx.new(|cx| {
2045        let text = "
2046            * one
2047                - a
2048                - b
2049            * two
2050        "
2051        .unindent();
2052
2053        let mut buffer = Buffer::local(text, cx).with_language(
2054            Arc::new(Language::new(
2055                LanguageConfig {
2056                    name: "Markdown".into(),
2057                    auto_indent_using_last_non_empty_line: false,
2058                    ..Default::default()
2059                },
2060                Some(tree_sitter_json::LANGUAGE.into()),
2061            )),
2062            cx,
2063        );
2064        buffer.edit(
2065            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
2066            Some(AutoindentMode::EachLine),
2067            cx,
2068        );
2069        assert_eq!(
2070            buffer.text(),
2071            "
2072            * one
2073                - a
2074                - b
2075
2076            * two
2077            "
2078            .unindent()
2079        );
2080        buffer
2081    });
2082}
2083
2084#[gpui::test]
2085fn test_autoindent_with_injected_languages(cx: &mut App) {
2086    init_settings(cx, |settings| {
2087        settings.languages.0.extend([
2088            (
2089                "HTML".into(),
2090                LanguageSettingsContent {
2091                    tab_size: Some(2.try_into().unwrap()),
2092                    ..Default::default()
2093                },
2094            ),
2095            (
2096                "JavaScript".into(),
2097                LanguageSettingsContent {
2098                    tab_size: Some(8.try_into().unwrap()),
2099                    ..Default::default()
2100                },
2101            ),
2102        ])
2103    });
2104
2105    let html_language = Arc::new(html_lang());
2106
2107    let javascript_language = Arc::new(javascript_lang());
2108
2109    let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2110    language_registry.add(html_language.clone());
2111    language_registry.add(javascript_language);
2112
2113    cx.new(|cx| {
2114        let (text, ranges) = marked_text_ranges(
2115            &"
2116                <div>ˇ
2117                </div>
2118                <script>
2119                    init({ˇ
2120                    })
2121                </script>
2122                <span>ˇ
2123                </span>
2124            "
2125            .unindent(),
2126            false,
2127        );
2128
2129        let mut buffer = Buffer::local(text, cx);
2130        buffer.set_language_registry(language_registry);
2131        buffer.set_language(Some(html_language), cx);
2132        buffer.edit(
2133            ranges.into_iter().map(|range| (range, "\na")),
2134            Some(AutoindentMode::EachLine),
2135            cx,
2136        );
2137        assert_eq!(
2138            buffer.text(),
2139            "
2140                <div>
2141                  a
2142                </div>
2143                <script>
2144                    init({
2145                            a
2146                    })
2147                </script>
2148                <span>
2149                  a
2150                </span>
2151            "
2152            .unindent()
2153        );
2154        buffer
2155    });
2156}
2157
2158#[gpui::test]
2159fn test_autoindent_query_with_outdent_captures(cx: &mut App) {
2160    init_settings(cx, |settings| {
2161        settings.defaults.tab_size = Some(2.try_into().unwrap());
2162    });
2163
2164    cx.new(|cx| {
2165        let mut buffer = Buffer::local("", cx).with_language(Arc::new(ruby_lang()), cx);
2166
2167        let text = r#"
2168            class C
2169            def a(b, c)
2170            puts b
2171            puts c
2172            rescue
2173            puts "errored"
2174            exit 1
2175            end
2176            end
2177        "#
2178        .unindent();
2179
2180        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
2181
2182        assert_eq!(
2183            buffer.text(),
2184            r#"
2185                class C
2186                  def a(b, c)
2187                    puts b
2188                    puts c
2189                  rescue
2190                    puts "errored"
2191                    exit 1
2192                  end
2193                end
2194            "#
2195            .unindent()
2196        );
2197
2198        buffer
2199    });
2200}
2201
2202#[gpui::test]
2203async fn test_async_autoindents_preserve_preview(cx: &mut TestAppContext) {
2204    cx.update(|cx| init_settings(cx, |_| {}));
2205
2206    // First we insert some newlines to request an auto-indent (asynchronously).
2207    // Then we request that a preview tab be preserved for the new version, even though it's edited.
2208    let buffer = cx.new(|cx| {
2209        let text = "fn a() {}";
2210        let mut buffer = Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx);
2211
2212        // This causes autoindent to be async.
2213        buffer.set_sync_parse_timeout(Duration::ZERO);
2214
2215        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
2216        buffer.refresh_preview();
2217
2218        // Synchronously, we haven't auto-indented and we're still preserving the preview.
2219        assert_eq!(buffer.text(), "fn a() {\n\n}");
2220        assert!(buffer.preserve_preview());
2221        buffer
2222    });
2223
2224    // Now let the autoindent finish
2225    cx.executor().run_until_parked();
2226
2227    // The auto-indent applied, but didn't dismiss our preview
2228    buffer.update(cx, |buffer, cx| {
2229        assert_eq!(buffer.text(), "fn a() {\n    \n}");
2230        assert!(buffer.preserve_preview());
2231
2232        // Edit inserting another line. It will autoindent async.
2233        // Then refresh the preview version.
2234        buffer.edit(
2235            [(Point::new(1, 4)..Point::new(1, 4), "\n")],
2236            Some(AutoindentMode::EachLine),
2237            cx,
2238        );
2239        buffer.refresh_preview();
2240        assert_eq!(buffer.text(), "fn a() {\n    \n\n}");
2241        assert!(buffer.preserve_preview());
2242
2243        // Then perform another edit, this time without refreshing the preview version.
2244        buffer.edit([(Point::new(1, 4)..Point::new(1, 4), "x")], None, cx);
2245        // This causes the preview to not be preserved.
2246        assert!(!buffer.preserve_preview());
2247    });
2248
2249    // Let the async autoindent from the first edit finish.
2250    cx.executor().run_until_parked();
2251
2252    // The autoindent applies, but it shouldn't restore the preview status because we had an edit in the meantime.
2253    buffer.update(cx, |buffer, _| {
2254        assert_eq!(buffer.text(), "fn a() {\n    x\n    \n}");
2255        assert!(!buffer.preserve_preview());
2256    });
2257}
2258
2259#[gpui::test]
2260fn test_insert_empty_line(cx: &mut App) {
2261    init_settings(cx, |_| {});
2262
2263    // Insert empty line at the beginning, requesting an empty line above
2264    cx.new(|cx| {
2265        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2266        let point = buffer.insert_empty_line(Point::new(0, 0), true, false, cx);
2267        assert_eq!(buffer.text(), "\nabc\ndef\nghi");
2268        assert_eq!(point, Point::new(0, 0));
2269        buffer
2270    });
2271
2272    // Insert empty line at the beginning, requesting an empty line above and below
2273    cx.new(|cx| {
2274        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2275        let point = buffer.insert_empty_line(Point::new(0, 0), true, true, cx);
2276        assert_eq!(buffer.text(), "\n\nabc\ndef\nghi");
2277        assert_eq!(point, Point::new(0, 0));
2278        buffer
2279    });
2280
2281    // Insert empty line at the start of a line, requesting empty lines above and below
2282    cx.new(|cx| {
2283        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2284        let point = buffer.insert_empty_line(Point::new(2, 0), true, true, cx);
2285        assert_eq!(buffer.text(), "abc\ndef\n\n\n\nghi");
2286        assert_eq!(point, Point::new(3, 0));
2287        buffer
2288    });
2289
2290    // Insert empty line in the middle of a line, requesting empty lines above and below
2291    cx.new(|cx| {
2292        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2293        let point = buffer.insert_empty_line(Point::new(1, 3), true, true, cx);
2294        assert_eq!(buffer.text(), "abc\ndef\n\n\n\nghi\njkl");
2295        assert_eq!(point, Point::new(3, 0));
2296        buffer
2297    });
2298
2299    // Insert empty line in the middle of a line, requesting empty line above only
2300    cx.new(|cx| {
2301        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2302        let point = buffer.insert_empty_line(Point::new(1, 3), true, false, cx);
2303        assert_eq!(buffer.text(), "abc\ndef\n\n\nghi\njkl");
2304        assert_eq!(point, Point::new(3, 0));
2305        buffer
2306    });
2307
2308    // Insert empty line in the middle of a line, requesting empty line below only
2309    cx.new(|cx| {
2310        let mut buffer = Buffer::local("abc\ndefghi\njkl", cx);
2311        let point = buffer.insert_empty_line(Point::new(1, 3), false, true, cx);
2312        assert_eq!(buffer.text(), "abc\ndef\n\n\nghi\njkl");
2313        assert_eq!(point, Point::new(2, 0));
2314        buffer
2315    });
2316
2317    // Insert empty line at the end, requesting empty lines above and below
2318    cx.new(|cx| {
2319        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2320        let point = buffer.insert_empty_line(Point::new(2, 3), true, true, cx);
2321        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n\n");
2322        assert_eq!(point, Point::new(4, 0));
2323        buffer
2324    });
2325
2326    // Insert empty line at the end, requesting empty line above only
2327    cx.new(|cx| {
2328        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2329        let point = buffer.insert_empty_line(Point::new(2, 3), true, false, cx);
2330        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n");
2331        assert_eq!(point, Point::new(4, 0));
2332        buffer
2333    });
2334
2335    // Insert empty line at the end, requesting empty line below only
2336    cx.new(|cx| {
2337        let mut buffer = Buffer::local("abc\ndef\nghi", cx);
2338        let point = buffer.insert_empty_line(Point::new(2, 3), false, true, cx);
2339        assert_eq!(buffer.text(), "abc\ndef\nghi\n\n");
2340        assert_eq!(point, Point::new(3, 0));
2341        buffer
2342    });
2343}
2344
2345#[gpui::test]
2346fn test_language_scope_at_with_javascript(cx: &mut App) {
2347    init_settings(cx, |_| {});
2348
2349    cx.new(|cx| {
2350        let language = Language::new(
2351            LanguageConfig {
2352                name: "JavaScript".into(),
2353                line_comments: vec!["// ".into()],
2354                block_comment: Some(BlockCommentConfig {
2355                    start: "/*".into(),
2356                    end: "*/".into(),
2357                    prefix: "* ".into(),
2358                    tab_size: 1,
2359                }),
2360                brackets: BracketPairConfig {
2361                    pairs: vec![
2362                        BracketPair {
2363                            start: "{".into(),
2364                            end: "}".into(),
2365                            close: true,
2366                            surround: true,
2367                            newline: false,
2368                        },
2369                        BracketPair {
2370                            start: "'".into(),
2371                            end: "'".into(),
2372                            close: true,
2373                            surround: true,
2374                            newline: false,
2375                        },
2376                    ],
2377                    disabled_scopes_by_bracket_ix: vec![
2378                        Vec::new(),                              //
2379                        vec!["string".into(), "comment".into()], // single quotes disabled
2380                    ],
2381                },
2382                overrides: [(
2383                    "element".into(),
2384                    LanguageConfigOverride {
2385                        line_comments: Override::Remove { remove: true },
2386                        block_comment: Override::Set(BlockCommentConfig {
2387                            start: "{/*".into(),
2388                            prefix: "".into(),
2389                            end: "*/}".into(),
2390                            tab_size: 0,
2391                        }),
2392                        ..Default::default()
2393                    },
2394                )]
2395                .into_iter()
2396                .collect(),
2397                ..Default::default()
2398            },
2399            Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
2400        )
2401        .with_override_query(
2402            r#"
2403                (jsx_element) @element
2404                (string) @string
2405                (comment) @comment.inclusive
2406                [
2407                    (jsx_opening_element)
2408                    (jsx_closing_element)
2409                    (jsx_expression)
2410                ] @default
2411            "#,
2412        )
2413        .unwrap();
2414
2415        let text = r#"
2416            a["b"] = <C d="e">
2417                <F></F>
2418                { g() }
2419            </C>; // a comment
2420        "#
2421        .unindent();
2422
2423        let buffer = Buffer::local(&text, cx).with_language(Arc::new(language), cx);
2424        let snapshot = buffer.snapshot();
2425
2426        let config = snapshot.language_scope_at(0).unwrap();
2427        assert_eq!(config.line_comment_prefixes(), &[Arc::from("// ")]);
2428        assert_eq!(
2429            config.block_comment(),
2430            Some(&BlockCommentConfig {
2431                start: "/*".into(),
2432                prefix: "* ".into(),
2433                end: "*/".into(),
2434                tab_size: 1,
2435            })
2436        );
2437
2438        // Both bracket pairs are enabled
2439        assert_eq!(
2440            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2441            &[true, true]
2442        );
2443
2444        let comment_config = snapshot
2445            .language_scope_at(text.find("comment").unwrap() + "comment".len())
2446            .unwrap();
2447        assert_eq!(
2448            comment_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2449            &[true, false]
2450        );
2451
2452        let string_config = snapshot
2453            .language_scope_at(text.find("b\"").unwrap())
2454            .unwrap();
2455        assert_eq!(string_config.line_comment_prefixes(), &[Arc::from("// ")]);
2456        assert_eq!(
2457            string_config.block_comment(),
2458            Some(&BlockCommentConfig {
2459                start: "/*".into(),
2460                prefix: "* ".into(),
2461                end: "*/".into(),
2462                tab_size: 1,
2463            })
2464        );
2465        // Second bracket pair is disabled
2466        assert_eq!(
2467            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2468            &[true, false]
2469        );
2470
2471        // In between JSX tags: use the `element` override.
2472        let element_config = snapshot
2473            .language_scope_at(text.find("<F>").unwrap())
2474            .unwrap();
2475        // TODO nested blocks after newlines are captured with all whitespaces
2476        // https://github.com/tree-sitter/tree-sitter-typescript/issues/306
2477        // assert_eq!(element_config.line_comment_prefixes(), &[]);
2478        // assert_eq!(
2479        //     element_config.block_comment_delimiters(),
2480        //     Some((&"{/*".into(), &"*/}".into()))
2481        // );
2482        assert_eq!(
2483            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2484            &[true, true]
2485        );
2486
2487        // Within a JSX tag: use the default config.
2488        let tag_config = snapshot
2489            .language_scope_at(text.find(" d=").unwrap() + 1)
2490            .unwrap();
2491        assert_eq!(tag_config.line_comment_prefixes(), &[Arc::from("// ")]);
2492        assert_eq!(
2493            tag_config.block_comment(),
2494            Some(&BlockCommentConfig {
2495                start: "/*".into(),
2496                prefix: "* ".into(),
2497                end: "*/".into(),
2498                tab_size: 1,
2499            })
2500        );
2501        assert_eq!(
2502            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2503            &[true, true]
2504        );
2505
2506        // In a JSX expression: use the default config.
2507        let expression_in_element_config = snapshot
2508            .language_scope_at(text.find('{').unwrap() + 1)
2509            .unwrap();
2510        assert_eq!(
2511            expression_in_element_config.line_comment_prefixes(),
2512            &[Arc::from("// ")]
2513        );
2514        assert_eq!(
2515            expression_in_element_config.block_comment(),
2516            Some(&BlockCommentConfig {
2517                start: "/*".into(),
2518                prefix: "* ".into(),
2519                end: "*/".into(),
2520                tab_size: 1,
2521            })
2522        );
2523        assert_eq!(
2524            expression_in_element_config
2525                .brackets()
2526                .map(|e| e.1)
2527                .collect::<Vec<_>>(),
2528            &[true, true]
2529        );
2530
2531        buffer
2532    });
2533}
2534
2535#[gpui::test]
2536fn test_language_scope_at_with_rust(cx: &mut App) {
2537    init_settings(cx, |_| {});
2538
2539    cx.new(|cx| {
2540        let language = Language::new(
2541            LanguageConfig {
2542                name: "Rust".into(),
2543                brackets: BracketPairConfig {
2544                    pairs: vec![
2545                        BracketPair {
2546                            start: "{".into(),
2547                            end: "}".into(),
2548                            close: true,
2549                            surround: true,
2550                            newline: false,
2551                        },
2552                        BracketPair {
2553                            start: "'".into(),
2554                            end: "'".into(),
2555                            close: true,
2556                            surround: true,
2557                            newline: false,
2558                        },
2559                    ],
2560                    disabled_scopes_by_bracket_ix: vec![
2561                        Vec::new(), //
2562                        vec!["string".into()],
2563                    ],
2564                },
2565                ..Default::default()
2566            },
2567            Some(tree_sitter_rust::LANGUAGE.into()),
2568        )
2569        .with_override_query(
2570            r#"
2571                (string_literal) @string
2572            "#,
2573        )
2574        .unwrap();
2575
2576        let text = r#"
2577            const S: &'static str = "hello";
2578        "#
2579        .unindent();
2580
2581        let buffer = Buffer::local(text.clone(), cx).with_language(Arc::new(language), cx);
2582        let snapshot = buffer.snapshot();
2583
2584        // By default, all brackets are enabled
2585        let config = snapshot.language_scope_at(0).unwrap();
2586        assert_eq!(
2587            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2588            &[true, true]
2589        );
2590
2591        // Within a string, the quotation brackets are disabled.
2592        let string_config = snapshot
2593            .language_scope_at(text.find("ello").unwrap())
2594            .unwrap();
2595        assert_eq!(
2596            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
2597            &[true, false]
2598        );
2599
2600        buffer
2601    });
2602}
2603
2604#[gpui::test]
2605fn test_language_scope_at_with_combined_injections(cx: &mut App) {
2606    init_settings(cx, |_| {});
2607
2608    cx.new(|cx| {
2609        let text = r#"
2610            <ol>
2611            <% people.each do |person| %>
2612                <li>
2613                    <%= person.name %>
2614                </li>
2615            <% end %>
2616            </ol>
2617        "#
2618        .unindent();
2619
2620        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2621        language_registry.add(Arc::new(ruby_lang()));
2622        language_registry.add(Arc::new(html_lang()));
2623        language_registry.add(Arc::new(erb_lang()));
2624
2625        let mut buffer = Buffer::local(text, cx);
2626        buffer.set_language_registry(language_registry.clone());
2627        buffer.set_language(
2628            language_registry
2629                .language_for_name("ERB")
2630                .now_or_never()
2631                .unwrap()
2632                .ok(),
2633            cx,
2634        );
2635
2636        let snapshot = buffer.snapshot();
2637        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
2638        assert_eq!(html_config.line_comment_prefixes(), &[]);
2639        assert_eq!(
2640            html_config.block_comment(),
2641            Some(&BlockCommentConfig {
2642                start: "<!--".into(),
2643                end: "-->".into(),
2644                prefix: "".into(),
2645                tab_size: 0,
2646            })
2647        );
2648
2649        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
2650        assert_eq!(ruby_config.line_comment_prefixes(), &[Arc::from("# ")]);
2651        assert_eq!(ruby_config.block_comment(), None);
2652
2653        buffer
2654    });
2655}
2656
2657#[gpui::test]
2658fn test_language_at_with_hidden_languages(cx: &mut App) {
2659    init_settings(cx, |_| {});
2660
2661    cx.new(|cx| {
2662        let text = r#"
2663            this is an *emphasized* word.
2664        "#
2665        .unindent();
2666
2667        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2668        language_registry.add(Arc::new(markdown_lang()));
2669        language_registry.add(Arc::new(markdown_inline_lang()));
2670
2671        let mut buffer = Buffer::local(text, cx);
2672        buffer.set_language_registry(language_registry.clone());
2673        buffer.set_language(
2674            language_registry
2675                .language_for_name("Markdown")
2676                .now_or_never()
2677                .unwrap()
2678                .ok(),
2679            cx,
2680        );
2681
2682        let snapshot = buffer.snapshot();
2683
2684        for point in [Point::new(0, 4), Point::new(0, 16)] {
2685            let config = snapshot.language_scope_at(point).unwrap();
2686            assert_eq!(config.language_name(), "Markdown".into());
2687
2688            let language = snapshot.language_at(point).unwrap();
2689            assert_eq!(language.name().as_ref(), "Markdown");
2690        }
2691
2692        buffer
2693    });
2694}
2695
2696#[gpui::test]
2697fn test_language_at_for_markdown_code_block(cx: &mut App) {
2698    init_settings(cx, |_| {});
2699
2700    cx.new(|cx| {
2701        let text = r#"
2702            ```rs
2703            let a = 2;
2704            // let b = 3;
2705            ```
2706        "#
2707        .unindent();
2708
2709        let language_registry = Arc::new(LanguageRegistry::test(cx.background_executor().clone()));
2710        language_registry.add(Arc::new(markdown_lang()));
2711        language_registry.add(Arc::new(markdown_inline_lang()));
2712        language_registry.add(Arc::new(rust_lang()));
2713
2714        let mut buffer = Buffer::local(text, cx);
2715        buffer.set_language_registry(language_registry.clone());
2716        buffer.set_language(
2717            language_registry
2718                .language_for_name("Markdown")
2719                .now_or_never()
2720                .unwrap()
2721                .ok(),
2722            cx,
2723        );
2724
2725        let snapshot = buffer.snapshot();
2726
2727        // Test points in the code line
2728        for point in [Point::new(1, 4), Point::new(1, 6)] {
2729            let config = snapshot.language_scope_at(point).unwrap();
2730            assert_eq!(config.language_name(), "Rust".into());
2731
2732            let language = snapshot.language_at(point).unwrap();
2733            assert_eq!(language.name().as_ref(), "Rust");
2734        }
2735
2736        // Test points in the comment line to verify it's still detected as Rust
2737        for point in [Point::new(2, 4), Point::new(2, 6)] {
2738            let config = snapshot.language_scope_at(point).unwrap();
2739            assert_eq!(config.language_name(), "Rust".into());
2740
2741            let language = snapshot.language_at(point).unwrap();
2742            assert_eq!(language.name().as_ref(), "Rust");
2743        }
2744
2745        buffer
2746    });
2747}
2748
2749#[gpui::test]
2750fn test_serialization(cx: &mut gpui::App) {
2751    let mut now = Instant::now();
2752
2753    let buffer1 = cx.new(|cx| {
2754        let mut buffer = Buffer::local("abc", cx);
2755        buffer.edit([(3..3, "D")], None, cx);
2756
2757        now += Duration::from_secs(1);
2758        buffer.start_transaction_at(now);
2759        buffer.edit([(4..4, "E")], None, cx);
2760        buffer.end_transaction_at(now, cx);
2761        assert_eq!(buffer.text(), "abcDE");
2762
2763        buffer.undo(cx);
2764        assert_eq!(buffer.text(), "abcD");
2765
2766        buffer.edit([(4..4, "F")], None, cx);
2767        assert_eq!(buffer.text(), "abcDF");
2768        buffer
2769    });
2770    assert_eq!(buffer1.read(cx).text(), "abcDF");
2771
2772    let state = buffer1.read(cx).to_proto(cx);
2773    let ops = cx
2774        .background_executor()
2775        .block(buffer1.read(cx).serialize_ops(None, cx));
2776    let buffer2 = cx.new(|cx| {
2777        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
2778        buffer.apply_ops(
2779            ops.into_iter()
2780                .map(|op| proto::deserialize_operation(op).unwrap()),
2781            cx,
2782        );
2783        buffer
2784    });
2785    assert_eq!(buffer2.read(cx).text(), "abcDF");
2786}
2787
2788#[gpui::test]
2789fn test_branch_and_merge(cx: &mut TestAppContext) {
2790    cx.update(|cx| init_settings(cx, |_| {}));
2791
2792    let base = cx.new(|cx| Buffer::local("one\ntwo\nthree\n", cx));
2793
2794    // Create a remote replica of the base buffer.
2795    let base_replica = cx.new(|cx| {
2796        Buffer::from_proto(1, Capability::ReadWrite, base.read(cx).to_proto(cx), None).unwrap()
2797    });
2798    base.update(cx, |_buffer, cx| {
2799        cx.subscribe(&base_replica, |this, _, event, cx| {
2800            if let BufferEvent::Operation {
2801                operation,
2802                is_local: true,
2803            } = event
2804            {
2805                this.apply_ops([operation.clone()], cx);
2806            }
2807        })
2808        .detach();
2809    });
2810
2811    // Create a branch, which initially has the same state as the base buffer.
2812    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2813    branch.read_with(cx, |buffer, _| {
2814        assert_eq!(buffer.text(), "one\ntwo\nthree\n");
2815    });
2816
2817    // Edits to the branch are not applied to the base.
2818    branch.update(cx, |buffer, cx| {
2819        buffer.edit(
2820            [
2821                (Point::new(1, 0)..Point::new(1, 0), "1.5\n"),
2822                (Point::new(2, 0)..Point::new(2, 5), "THREE"),
2823            ],
2824            None,
2825            cx,
2826        )
2827    });
2828    branch.read_with(cx, |buffer, cx| {
2829        assert_eq!(base.read(cx).text(), "one\ntwo\nthree\n");
2830        assert_eq!(buffer.text(), "one\n1.5\ntwo\nTHREE\n");
2831    });
2832
2833    // Convert from branch buffer ranges to the corresponding ranges in the
2834    // base buffer.
2835    branch.read_with(cx, |buffer, cx| {
2836        assert_eq!(
2837            buffer.range_to_version(4..7, &base.read(cx).version()),
2838            4..4
2839        );
2840        assert_eq!(
2841            buffer.range_to_version(2..9, &base.read(cx).version()),
2842            2..5
2843        );
2844    });
2845
2846    // Edits to the base are applied to the branch.
2847    base.update(cx, |buffer, cx| {
2848        buffer.edit([(Point::new(0, 0)..Point::new(0, 0), "ZERO\n")], None, cx)
2849    });
2850    branch.read_with(cx, |buffer, cx| {
2851        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\nthree\n");
2852        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\nTHREE\n");
2853    });
2854
2855    // Edits to any replica of the base are applied to the branch.
2856    base_replica.update(cx, |buffer, cx| {
2857        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "2.5\n")], None, cx)
2858    });
2859    branch.read_with(cx, |buffer, cx| {
2860        assert_eq!(base.read(cx).text(), "ZERO\none\ntwo\n2.5\nthree\n");
2861        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2862    });
2863
2864    // Merging the branch applies all of its changes to the base.
2865    branch.update(cx, |buffer, cx| {
2866        buffer.merge_into_base(Vec::new(), cx);
2867    });
2868
2869    branch.update(cx, |buffer, cx| {
2870        assert_eq!(base.read(cx).text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2871        assert_eq!(buffer.text(), "ZERO\none\n1.5\ntwo\n2.5\nTHREE\n");
2872    });
2873}
2874
2875#[gpui::test]
2876fn test_merge_into_base(cx: &mut TestAppContext) {
2877    cx.update(|cx| init_settings(cx, |_| {}));
2878
2879    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2880    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2881
2882    // Make 3 edits, merge one into the base.
2883    branch.update(cx, |branch, cx| {
2884        branch.edit([(0..3, "ABC"), (7..9, "HI"), (11..11, "LMN")], None, cx);
2885        branch.merge_into_base(vec![5..8], cx);
2886    });
2887
2888    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjkLMN"));
2889    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2890
2891    // Undo the one already-merged edit. Merge that into the base.
2892    branch.update(cx, |branch, cx| {
2893        branch.edit([(7..9, "hi")], None, cx);
2894        branch.merge_into_base(vec![5..8], cx);
2895    });
2896    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2897
2898    // Merge an insertion into the base.
2899    branch.update(cx, |branch, cx| {
2900        branch.merge_into_base(vec![11..11], cx);
2901    });
2902
2903    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefghijkLMN"));
2904    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijkLMN"));
2905
2906    // Deleted the inserted text and merge that into the base.
2907    branch.update(cx, |branch, cx| {
2908        branch.edit([(11..14, "")], None, cx);
2909        branch.merge_into_base(vec![10..11], cx);
2910    });
2911
2912    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2913}
2914
2915#[gpui::test]
2916fn test_undo_after_merge_into_base(cx: &mut TestAppContext) {
2917    cx.update(|cx| init_settings(cx, |_| {}));
2918
2919    let base = cx.new(|cx| Buffer::local("abcdefghijk", cx));
2920    let branch = base.update(cx, |buffer, cx| buffer.branch(cx));
2921
2922    // Make 2 edits, merge one into the base.
2923    branch.update(cx, |branch, cx| {
2924        branch.edit([(0..3, "ABC"), (7..9, "HI")], None, cx);
2925        branch.merge_into_base(vec![7..7], cx);
2926    });
2927    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2928    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2929
2930    // Undo the merge in the base buffer.
2931    base.update(cx, |base, cx| {
2932        base.undo(cx);
2933    });
2934    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefghijk"));
2935    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2936
2937    // Merge that operation into the base again.
2938    branch.update(cx, |branch, cx| {
2939        branch.merge_into_base(vec![7..7], cx);
2940    });
2941    base.read_with(cx, |base, _| assert_eq!(base.text(), "abcdefgHIjk"));
2942    branch.read_with(cx, |branch, _| assert_eq!(branch.text(), "ABCdefgHIjk"));
2943}
2944
2945#[gpui::test]
2946async fn test_preview_edits(cx: &mut TestAppContext) {
2947    cx.update(|cx| {
2948        init_settings(cx, |_| {});
2949        theme::init(theme::LoadThemes::JustBase, cx);
2950    });
2951
2952    let insertion_style = HighlightStyle {
2953        background_color: Some(cx.read(|cx| cx.theme().status().created_background)),
2954        ..Default::default()
2955    };
2956    let deletion_style = HighlightStyle {
2957        background_color: Some(cx.read(|cx| cx.theme().status().deleted_background)),
2958        ..Default::default()
2959    };
2960
2961    // no edits
2962    assert_preview_edits(
2963        indoc! {"
2964        fn test_empty() -> bool {
2965            false
2966        }"
2967        },
2968        vec![],
2969        true,
2970        cx,
2971        |hl| {
2972            assert!(hl.text.is_empty());
2973            assert!(hl.highlights.is_empty());
2974        },
2975    )
2976    .await;
2977
2978    // only insertions
2979    assert_preview_edits(
2980        indoc! {"
2981        fn calculate_area(: f64) -> f64 {
2982            std::f64::consts::PI * .powi(2)
2983        }"
2984        },
2985        vec![
2986            (Point::new(0, 18)..Point::new(0, 18), "radius"),
2987            (Point::new(1, 27)..Point::new(1, 27), "radius"),
2988        ],
2989        true,
2990        cx,
2991        |hl| {
2992            assert_eq!(
2993                hl.text,
2994                indoc! {"
2995                fn calculate_area(radius: f64) -> f64 {
2996                    std::f64::consts::PI * radius.powi(2)"
2997                }
2998            );
2999
3000            assert_eq!(hl.highlights.len(), 2);
3001            assert_eq!(hl.highlights[0], ((18..24), insertion_style));
3002            assert_eq!(hl.highlights[1], ((67..73), insertion_style));
3003        },
3004    )
3005    .await;
3006
3007    // insertions & deletions
3008    assert_preview_edits(
3009        indoc! {"
3010        struct Person {
3011            first_name: String,
3012        }
3013
3014        impl Person {
3015            fn first_name(&self) -> &String {
3016                &self.first_name
3017            }
3018        }"
3019        },
3020        vec![
3021            (Point::new(1, 4)..Point::new(1, 9), "last"),
3022            (Point::new(5, 7)..Point::new(5, 12), "last"),
3023            (Point::new(6, 14)..Point::new(6, 19), "last"),
3024        ],
3025        true,
3026        cx,
3027        |hl| {
3028            assert_eq!(
3029                hl.text,
3030                indoc! {"
3031                        firstlast_name: String,
3032                    }
3033
3034                    impl Person {
3035                        fn firstlast_name(&self) -> &String {
3036                            &self.firstlast_name"
3037                }
3038            );
3039
3040            assert_eq!(hl.highlights.len(), 6);
3041            assert_eq!(hl.highlights[0], ((4..9), deletion_style));
3042            assert_eq!(hl.highlights[1], ((9..13), insertion_style));
3043            assert_eq!(hl.highlights[2], ((52..57), deletion_style));
3044            assert_eq!(hl.highlights[3], ((57..61), insertion_style));
3045            assert_eq!(hl.highlights[4], ((101..106), deletion_style));
3046            assert_eq!(hl.highlights[5], ((106..110), insertion_style));
3047        },
3048    )
3049    .await;
3050
3051    async fn assert_preview_edits(
3052        text: &str,
3053        edits: Vec<(Range<Point>, &str)>,
3054        include_deletions: bool,
3055        cx: &mut TestAppContext,
3056        assert_fn: impl Fn(HighlightedText),
3057    ) {
3058        let buffer = cx.new(|cx| Buffer::local(text, cx).with_language(Arc::new(rust_lang()), cx));
3059        let edits = buffer.read_with(cx, |buffer, _| {
3060            edits
3061                .into_iter()
3062                .map(|(range, text)| {
3063                    (
3064                        buffer.anchor_before(range.start)..buffer.anchor_after(range.end),
3065                        text.to_string(),
3066                    )
3067                })
3068                .collect::<Vec<_>>()
3069        });
3070        let edit_preview = buffer
3071            .read_with(cx, |buffer, cx| {
3072                buffer.preview_edits(edits.clone().into(), cx)
3073            })
3074            .await;
3075        let highlighted_edits = cx.read(|cx| {
3076            edit_preview.highlight_edits(&buffer.read(cx).snapshot(), &edits, include_deletions, cx)
3077        });
3078        assert_fn(highlighted_edits);
3079    }
3080}
3081
3082#[gpui::test(iterations = 100)]
3083fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
3084    let min_peers = env::var("MIN_PEERS")
3085        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
3086        .unwrap_or(1);
3087    let max_peers = env::var("MAX_PEERS")
3088        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
3089        .unwrap_or(5);
3090    let operations = env::var("OPERATIONS")
3091        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
3092        .unwrap_or(10);
3093
3094    let base_text_len = rng.random_range(0..10);
3095    let base_text = RandomCharIter::new(&mut rng)
3096        .take(base_text_len)
3097        .collect::<String>();
3098    let mut replica_ids = Vec::new();
3099    let mut buffers = Vec::new();
3100    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
3101    let base_buffer = cx.new(|cx| Buffer::local(base_text.as_str(), cx));
3102
3103    for i in 0..rng.random_range(min_peers..=max_peers) {
3104        let buffer = cx.new(|cx| {
3105            let state = base_buffer.read(cx).to_proto(cx);
3106            let ops = cx
3107                .background_executor()
3108                .block(base_buffer.read(cx).serialize_ops(None, cx));
3109            let mut buffer =
3110                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
3111            buffer.apply_ops(
3112                ops.into_iter()
3113                    .map(|op| proto::deserialize_operation(op).unwrap()),
3114                cx,
3115            );
3116            buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
3117            let network = network.clone();
3118            cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
3119                if let BufferEvent::Operation {
3120                    operation,
3121                    is_local: true,
3122                } = event
3123                {
3124                    network.lock().broadcast(
3125                        buffer.replica_id(),
3126                        vec![proto::serialize_operation(operation)],
3127                    );
3128                }
3129            })
3130            .detach();
3131            buffer
3132        });
3133
3134        buffers.push(buffer);
3135        replica_ids.push(i as ReplicaId);
3136        network.lock().add_peer(i as ReplicaId);
3137        log::info!("Adding initial peer with replica id {}", i);
3138    }
3139
3140    log::info!("initial text: {:?}", base_text);
3141
3142    let mut now = Instant::now();
3143    let mut mutation_count = operations;
3144    let mut next_diagnostic_id = 0;
3145    let mut active_selections = BTreeMap::default();
3146    loop {
3147        let replica_index = rng.random_range(0..replica_ids.len());
3148        let replica_id = replica_ids[replica_index];
3149        let buffer = &mut buffers[replica_index];
3150        let mut new_buffer = None;
3151        match rng.random_range(0..100) {
3152            0..=29 if mutation_count != 0 => {
3153                buffer.update(cx, |buffer, cx| {
3154                    buffer.start_transaction_at(now);
3155                    buffer.randomly_edit(&mut rng, 5, cx);
3156                    buffer.end_transaction_at(now, cx);
3157                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
3158                });
3159                mutation_count -= 1;
3160            }
3161            30..=39 if mutation_count != 0 => {
3162                buffer.update(cx, |buffer, cx| {
3163                    if rng.random_bool(0.2) {
3164                        log::info!("peer {} clearing active selections", replica_id);
3165                        active_selections.remove(&replica_id);
3166                        buffer.remove_active_selections(cx);
3167                    } else {
3168                        let mut selections = Vec::new();
3169                        for id in 0..rng.random_range(1..=5) {
3170                            let range = buffer.random_byte_range(0, &mut rng);
3171                            selections.push(Selection {
3172                                id,
3173                                start: buffer.anchor_before(range.start),
3174                                end: buffer.anchor_before(range.end),
3175                                reversed: false,
3176                                goal: SelectionGoal::None,
3177                            });
3178                        }
3179                        let selections: Arc<[Selection<Anchor>]> = selections.into();
3180                        log::info!(
3181                            "peer {} setting active selections: {:?}",
3182                            replica_id,
3183                            selections
3184                        );
3185                        active_selections.insert(replica_id, selections.clone());
3186                        buffer.set_active_selections(selections, false, Default::default(), cx);
3187                    }
3188                });
3189                mutation_count -= 1;
3190            }
3191            40..=49 if mutation_count != 0 && replica_id == 0 => {
3192                let entry_count = rng.random_range(1..=5);
3193                buffer.update(cx, |buffer, cx| {
3194                    let diagnostics = DiagnosticSet::new(
3195                        (0..entry_count).map(|_| {
3196                            let range = buffer.random_byte_range(0, &mut rng);
3197                            let range = range.to_point_utf16(buffer);
3198                            let range = range.start..range.end;
3199                            DiagnosticEntry {
3200                                range,
3201                                diagnostic: Diagnostic {
3202                                    message: post_inc(&mut next_diagnostic_id).to_string(),
3203                                    ..Default::default()
3204                                },
3205                            }
3206                        }),
3207                        buffer,
3208                    );
3209                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
3210                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
3211                });
3212                mutation_count -= 1;
3213            }
3214            50..=59 if replica_ids.len() < max_peers => {
3215                let old_buffer_state = buffer.read(cx).to_proto(cx);
3216                let old_buffer_ops = cx
3217                    .background_executor()
3218                    .block(buffer.read(cx).serialize_ops(None, cx));
3219                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
3220                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
3221                    .choose(&mut rng)
3222                    .unwrap();
3223                log::info!(
3224                    "Adding new replica {} (replicating from {})",
3225                    new_replica_id,
3226                    replica_id
3227                );
3228                new_buffer = Some(cx.new(|cx| {
3229                    let mut new_buffer = Buffer::from_proto(
3230                        new_replica_id,
3231                        Capability::ReadWrite,
3232                        old_buffer_state,
3233                        None,
3234                    )
3235                    .unwrap();
3236                    new_buffer.apply_ops(
3237                        old_buffer_ops
3238                            .into_iter()
3239                            .map(|op| deserialize_operation(op).unwrap()),
3240                        cx,
3241                    );
3242                    log::info!(
3243                        "New replica {} text: {:?}",
3244                        new_buffer.replica_id(),
3245                        new_buffer.text()
3246                    );
3247                    new_buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
3248                    let network = network.clone();
3249                    cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
3250                        if let BufferEvent::Operation {
3251                            operation,
3252                            is_local: true,
3253                        } = event
3254                        {
3255                            network.lock().broadcast(
3256                                buffer.replica_id(),
3257                                vec![proto::serialize_operation(operation)],
3258                            );
3259                        }
3260                    })
3261                    .detach();
3262                    new_buffer
3263                }));
3264                network.lock().replicate(replica_id, new_replica_id);
3265
3266                if new_replica_id as usize == replica_ids.len() {
3267                    replica_ids.push(new_replica_id);
3268                } else {
3269                    let new_buffer = new_buffer.take().unwrap();
3270                    while network.lock().has_unreceived(new_replica_id) {
3271                        let ops = network
3272                            .lock()
3273                            .receive(new_replica_id)
3274                            .into_iter()
3275                            .map(|op| proto::deserialize_operation(op).unwrap());
3276                        if ops.len() > 0 {
3277                            log::info!(
3278                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3279                                new_replica_id,
3280                                buffer.read(cx).version(),
3281                                ops.len(),
3282                                ops
3283                            );
3284                            new_buffer.update(cx, |new_buffer, cx| {
3285                                new_buffer.apply_ops(ops, cx);
3286                            });
3287                        }
3288                    }
3289                    buffers[new_replica_id as usize] = new_buffer;
3290                }
3291            }
3292            60..=69 if mutation_count != 0 => {
3293                buffer.update(cx, |buffer, cx| {
3294                    buffer.randomly_undo_redo(&mut rng, cx);
3295                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
3296                });
3297                mutation_count -= 1;
3298            }
3299            _ if network.lock().has_unreceived(replica_id) => {
3300                let ops = network
3301                    .lock()
3302                    .receive(replica_id)
3303                    .into_iter()
3304                    .map(|op| proto::deserialize_operation(op).unwrap());
3305                if ops.len() > 0 {
3306                    log::info!(
3307                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
3308                        replica_id,
3309                        buffer.read(cx).version(),
3310                        ops.len(),
3311                        ops
3312                    );
3313                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx));
3314                }
3315            }
3316            _ => {}
3317        }
3318
3319        now += Duration::from_millis(rng.random_range(0..=200));
3320        buffers.extend(new_buffer);
3321
3322        for buffer in &buffers {
3323            buffer.read(cx).check_invariants();
3324        }
3325
3326        if mutation_count == 0 && network.lock().is_idle() {
3327            break;
3328        }
3329    }
3330
3331    let first_buffer = buffers[0].read(cx).snapshot();
3332    for buffer in &buffers[1..] {
3333        let buffer = buffer.read(cx).snapshot();
3334        assert_eq!(
3335            buffer.version(),
3336            first_buffer.version(),
3337            "Replica {} version != Replica 0 version",
3338            buffer.replica_id()
3339        );
3340        assert_eq!(
3341            buffer.text(),
3342            first_buffer.text(),
3343            "Replica {} text != Replica 0 text",
3344            buffer.replica_id()
3345        );
3346        assert_eq!(
3347            buffer
3348                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
3349                .collect::<Vec<_>>(),
3350            first_buffer
3351                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
3352                .collect::<Vec<_>>(),
3353            "Replica {} diagnostics != Replica 0 diagnostics",
3354            buffer.replica_id()
3355        );
3356    }
3357
3358    for buffer in &buffers {
3359        let buffer = buffer.read(cx).snapshot();
3360        let actual_remote_selections = buffer
3361            .selections_in_range(Anchor::MIN..Anchor::MAX, false)
3362            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
3363            .collect::<Vec<_>>();
3364        let expected_remote_selections = active_selections
3365            .iter()
3366            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
3367            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
3368            .collect::<Vec<_>>();
3369        assert_eq!(
3370            actual_remote_selections,
3371            expected_remote_selections,
3372            "Replica {} remote selections != expected selections",
3373            buffer.replica_id()
3374        );
3375    }
3376}
3377
3378#[test]
3379fn test_contiguous_ranges() {
3380    assert_eq!(
3381        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
3382        &[1..4, 5..7, 9..13]
3383    );
3384
3385    // Respects the `max_len` parameter
3386    assert_eq!(
3387        contiguous_ranges(
3388            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
3389            3
3390        )
3391        .collect::<Vec<_>>(),
3392        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
3393    );
3394}
3395
3396#[gpui::test(iterations = 500)]
3397fn test_trailing_whitespace_ranges(mut rng: StdRng) {
3398    // Generate a random multi-line string containing
3399    // some lines with trailing whitespace.
3400    let mut text = String::new();
3401    for _ in 0..rng.random_range(0..16) {
3402        for _ in 0..rng.random_range(0..36) {
3403            text.push(match rng.random_range(0..10) {
3404                0..=1 => ' ',
3405                3 => '\t',
3406                _ => rng.random_range('a'..='z'),
3407            });
3408        }
3409        text.push('\n');
3410    }
3411
3412    match rng.random_range(0..10) {
3413        // sometimes remove the last newline
3414        0..=1 => drop(text.pop()), //
3415
3416        // sometimes add extra newlines
3417        2..=3 => text.push_str(&"\n".repeat(rng.random_range(1..5))),
3418        _ => {}
3419    }
3420
3421    let rope = Rope::from(text.as_str());
3422    let actual_ranges = trailing_whitespace_ranges(&rope);
3423    let expected_ranges = TRAILING_WHITESPACE_REGEX
3424        .find_iter(&text)
3425        .map(|m| m.range())
3426        .collect::<Vec<_>>();
3427    assert_eq!(
3428        actual_ranges,
3429        expected_ranges,
3430        "wrong ranges for text lines:\n{:?}",
3431        text.split('\n').collect::<Vec<_>>()
3432    );
3433}
3434
3435#[gpui::test]
3436fn test_words_in_range(cx: &mut gpui::App) {
3437    init_settings(cx, |_| {});
3438
3439    // The first line are words excluded from the results with heuristics, we do not expect them in the test assertions.
3440    let contents = r#"
34410_isize 123 3.4 4  
3442let word=öäpple.bar你 Öäpple word2-öÄpPlE-Pizza-word ÖÄPPLE word
3443    "#;
3444
3445    let buffer = cx.new(|cx| {
3446        let buffer = Buffer::local(contents, cx).with_language(Arc::new(rust_lang()), cx);
3447        assert_eq!(buffer.text(), contents);
3448        buffer.check_invariants();
3449        buffer
3450    });
3451
3452    buffer.update(cx, |buffer, _| {
3453        let snapshot = buffer.snapshot();
3454        assert_eq!(
3455            BTreeSet::from_iter(["Pizza".to_string()]),
3456            snapshot
3457                .words_in_range(WordsQuery {
3458                    fuzzy_contents: Some("piz"),
3459                    skip_digits: true,
3460                    range: 0..snapshot.len(),
3461                })
3462                .into_keys()
3463                .collect::<BTreeSet<_>>()
3464        );
3465        assert_eq!(
3466            BTreeSet::from_iter([
3467                "öäpple".to_string(),
3468                "Öäpple".to_string(),
3469                "öÄpPlE".to_string(),
3470                "ÖÄPPLE".to_string(),
3471            ]),
3472            snapshot
3473                .words_in_range(WordsQuery {
3474                    fuzzy_contents: Some("öp"),
3475                    skip_digits: true,
3476                    range: 0..snapshot.len(),
3477                })
3478                .into_keys()
3479                .collect::<BTreeSet<_>>()
3480        );
3481        assert_eq!(
3482            BTreeSet::from_iter([
3483                "öÄpPlE".to_string(),
3484                "Öäpple".to_string(),
3485                "ÖÄPPLE".to_string(),
3486                "öäpple".to_string(),
3487            ]),
3488            snapshot
3489                .words_in_range(WordsQuery {
3490                    fuzzy_contents: Some("öÄ"),
3491                    skip_digits: true,
3492                    range: 0..snapshot.len(),
3493                })
3494                .into_keys()
3495                .collect::<BTreeSet<_>>()
3496        );
3497        assert_eq!(
3498            BTreeSet::default(),
3499            snapshot
3500                .words_in_range(WordsQuery {
3501                    fuzzy_contents: Some("öÄ好"),
3502                    skip_digits: true,
3503                    range: 0..snapshot.len(),
3504                })
3505                .into_keys()
3506                .collect::<BTreeSet<_>>()
3507        );
3508        assert_eq!(
3509            BTreeSet::from_iter(["bar你".to_string(),]),
3510            snapshot
3511                .words_in_range(WordsQuery {
3512                    fuzzy_contents: Some(""),
3513                    skip_digits: true,
3514                    range: 0..snapshot.len(),
3515                })
3516                .into_keys()
3517                .collect::<BTreeSet<_>>()
3518        );
3519        assert_eq!(
3520            BTreeSet::default(),
3521            snapshot
3522                .words_in_range(WordsQuery {
3523                    fuzzy_contents: Some(""),
3524                    skip_digits: true,
3525                    range: 0..snapshot.len(),
3526                },)
3527                .into_keys()
3528                .collect::<BTreeSet<_>>()
3529        );
3530        assert_eq!(
3531            BTreeSet::from_iter([
3532                "bar你".to_string(),
3533                "öÄpPlE".to_string(),
3534                "Öäpple".to_string(),
3535                "ÖÄPPLE".to_string(),
3536                "öäpple".to_string(),
3537                "let".to_string(),
3538                "Pizza".to_string(),
3539                "word".to_string(),
3540                "word2".to_string(),
3541            ]),
3542            snapshot
3543                .words_in_range(WordsQuery {
3544                    fuzzy_contents: None,
3545                    skip_digits: true,
3546                    range: 0..snapshot.len(),
3547                })
3548                .into_keys()
3549                .collect::<BTreeSet<_>>()
3550        );
3551        assert_eq!(
3552            BTreeSet::from_iter([
3553                "0_isize".to_string(),
3554                "123".to_string(),
3555                "3".to_string(),
3556                "4".to_string(),
3557                "bar你".to_string(),
3558                "öÄpPlE".to_string(),
3559                "Öäpple".to_string(),
3560                "ÖÄPPLE".to_string(),
3561                "öäpple".to_string(),
3562                "let".to_string(),
3563                "Pizza".to_string(),
3564                "word".to_string(),
3565                "word2".to_string(),
3566            ]),
3567            snapshot
3568                .words_in_range(WordsQuery {
3569                    fuzzy_contents: None,
3570                    skip_digits: false,
3571                    range: 0..snapshot.len(),
3572                })
3573                .into_keys()
3574                .collect::<BTreeSet<_>>()
3575        );
3576    });
3577}
3578
3579fn ruby_lang() -> Language {
3580    Language::new(
3581        LanguageConfig {
3582            name: "Ruby".into(),
3583            matcher: LanguageMatcher {
3584                path_suffixes: vec!["rb".to_string()],
3585                ..Default::default()
3586            },
3587            line_comments: vec!["# ".into()],
3588            ..Default::default()
3589        },
3590        Some(tree_sitter_ruby::LANGUAGE.into()),
3591    )
3592    .with_indents_query(
3593        r#"
3594            (class "end" @end) @indent
3595            (method "end" @end) @indent
3596            (rescue) @outdent
3597            (then) @indent
3598        "#,
3599    )
3600    .unwrap()
3601}
3602
3603fn html_lang() -> Language {
3604    Language::new(
3605        LanguageConfig {
3606            name: LanguageName::new("HTML"),
3607            block_comment: Some(BlockCommentConfig {
3608                start: "<!--".into(),
3609                prefix: "".into(),
3610                end: "-->".into(),
3611                tab_size: 0,
3612            }),
3613            ..Default::default()
3614        },
3615        Some(tree_sitter_html::LANGUAGE.into()),
3616    )
3617    .with_indents_query(
3618        "
3619        (element
3620          (start_tag) @start
3621          (end_tag)? @end) @indent
3622        ",
3623    )
3624    .unwrap()
3625    .with_injection_query(
3626        r#"
3627        (script_element
3628            (raw_text) @injection.content
3629            (#set! injection.language "javascript"))
3630        "#,
3631    )
3632    .unwrap()
3633}
3634
3635fn erb_lang() -> Language {
3636    Language::new(
3637        LanguageConfig {
3638            name: "ERB".into(),
3639            matcher: LanguageMatcher {
3640                path_suffixes: vec!["erb".to_string()],
3641                ..Default::default()
3642            },
3643            block_comment: Some(BlockCommentConfig {
3644                start: "<%#".into(),
3645                prefix: "".into(),
3646                end: "%>".into(),
3647                tab_size: 0,
3648            }),
3649            ..Default::default()
3650        },
3651        Some(tree_sitter_embedded_template::LANGUAGE.into()),
3652    )
3653    .with_injection_query(
3654        r#"
3655            (
3656                (code) @injection.content
3657                (#set! injection.language "ruby")
3658                (#set! injection.combined)
3659            )
3660
3661            (
3662                (content) @injection.content
3663                (#set! injection.language "html")
3664                (#set! injection.combined)
3665            )
3666        "#,
3667    )
3668    .unwrap()
3669}
3670
3671fn rust_lang() -> Language {
3672    Language::new(
3673        LanguageConfig {
3674            name: "Rust".into(),
3675            matcher: LanguageMatcher {
3676                path_suffixes: vec!["rs".to_string()],
3677                ..Default::default()
3678            },
3679            ..Default::default()
3680        },
3681        Some(tree_sitter_rust::LANGUAGE.into()),
3682    )
3683    .with_indents_query(
3684        r#"
3685        (call_expression) @indent
3686        (field_expression) @indent
3687        (_ "(" ")" @end) @indent
3688        (_ "{" "}" @end) @indent
3689        "#,
3690    )
3691    .unwrap()
3692    .with_brackets_query(
3693        r#"
3694        ("{" @open "}" @close)
3695        "#,
3696    )
3697    .unwrap()
3698    .with_text_object_query(
3699        r#"
3700        (function_item
3701            body: (_
3702                "{"
3703                (_)* @function.inside
3704                "}" )) @function.around
3705
3706        (line_comment)+ @comment.around
3707
3708        (block_comment) @comment.around
3709        "#,
3710    )
3711    .unwrap()
3712    .with_outline_query(
3713        r#"
3714        (line_comment) @annotation
3715
3716        (struct_item
3717            "struct" @context
3718            name: (_) @name) @item
3719        (enum_item
3720            "enum" @context
3721            name: (_) @name) @item
3722        (enum_variant
3723            name: (_) @name) @item
3724        (field_declaration
3725            name: (_) @name) @item
3726        (impl_item
3727            "impl" @context
3728            trait: (_)? @name
3729            "for"? @context
3730            type: (_) @name
3731            body: (_ "{" (_)* "}")) @item
3732        (function_item
3733            "fn" @context
3734            name: (_) @name) @item
3735        (mod_item
3736            "mod" @context
3737            name: (_) @name) @item
3738        "#,
3739    )
3740    .unwrap()
3741}
3742
3743fn json_lang() -> Language {
3744    Language::new(
3745        LanguageConfig {
3746            name: "Json".into(),
3747            matcher: LanguageMatcher {
3748                path_suffixes: vec!["js".to_string()],
3749                ..Default::default()
3750            },
3751            ..Default::default()
3752        },
3753        Some(tree_sitter_json::LANGUAGE.into()),
3754    )
3755}
3756
3757fn javascript_lang() -> Language {
3758    Language::new(
3759        LanguageConfig {
3760            name: "JavaScript".into(),
3761            ..Default::default()
3762        },
3763        Some(tree_sitter_typescript::LANGUAGE_TSX.into()),
3764    )
3765    .with_brackets_query(
3766        r#"
3767        ("{" @open "}" @close)
3768        ("(" @open ")" @close)
3769        "#,
3770    )
3771    .unwrap()
3772    .with_indents_query(
3773        r#"
3774        (object "}" @end) @indent
3775        "#,
3776    )
3777    .unwrap()
3778}
3779
3780pub fn markdown_lang() -> Language {
3781    Language::new(
3782        LanguageConfig {
3783            name: "Markdown".into(),
3784            matcher: LanguageMatcher {
3785                path_suffixes: vec!["md".into()],
3786                ..Default::default()
3787            },
3788            ..Default::default()
3789        },
3790        Some(tree_sitter_md::LANGUAGE.into()),
3791    )
3792    .with_injection_query(
3793        r#"
3794            (fenced_code_block
3795                (info_string
3796                    (language) @injection.language)
3797                (code_fence_content) @injection.content)
3798
3799                ((inline) @injection.content
3800                (#set! injection.language "markdown-inline"))
3801        "#,
3802    )
3803    .unwrap()
3804}
3805
3806pub fn markdown_inline_lang() -> Language {
3807    Language::new(
3808        LanguageConfig {
3809            name: "Markdown-Inline".into(),
3810            hidden: true,
3811            ..LanguageConfig::default()
3812        },
3813        Some(tree_sitter_md::INLINE_LANGUAGE.into()),
3814    )
3815    .with_highlights_query("(emphasis) @emphasis")
3816    .unwrap()
3817}
3818
3819fn get_tree_sexp(buffer: &Entity<Buffer>, cx: &mut gpui::TestAppContext) -> String {
3820    buffer.update(cx, |buffer, _| {
3821        let snapshot = buffer.snapshot();
3822        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
3823        layers[0].node().to_sexp()
3824    })
3825}
3826
3827// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
3828#[track_caller]
3829fn assert_bracket_pairs(
3830    selection_text: &'static str,
3831    bracket_pair_texts: Vec<&'static str>,
3832    language: Language,
3833    cx: &mut App,
3834) {
3835    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
3836    let buffer =
3837        cx.new(|cx| Buffer::local(expected_text.clone(), cx).with_language(Arc::new(language), cx));
3838    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
3839
3840    let selection_range = selection_ranges[0].clone();
3841
3842    let bracket_pairs = bracket_pair_texts
3843        .into_iter()
3844        .map(|pair_text| {
3845            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
3846            assert_eq!(bracket_text, expected_text);
3847            (ranges[0].clone(), ranges[1].clone())
3848        })
3849        .collect::<Vec<_>>();
3850
3851    assert_set_eq!(
3852        buffer
3853            .bracket_ranges(selection_range)
3854            .map(|pair| (pair.open_range, pair.close_range))
3855            .collect::<Vec<_>>(),
3856        bracket_pairs
3857    );
3858}
3859
3860fn init_settings(cx: &mut App, f: fn(&mut AllLanguageSettingsContent)) {
3861    let settings_store = SettingsStore::test(cx);
3862    cx.set_global(settings_store);
3863    crate::init(cx);
3864    cx.update_global::<SettingsStore, _>(|settings, cx| {
3865        settings.update_user_settings(cx, |content| f(&mut content.project.all_languages));
3866    });
3867}
3868
3869#[gpui::test(iterations = 100)]
3870fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
3871    use util::RandomCharIter;
3872
3873    // Generate random text
3874    let len = rng.random_range(0..10000);
3875    let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
3876
3877    let buffer = cx.new(|cx| Buffer::local(text, cx));
3878    let snapshot = buffer.read(cx).snapshot();
3879
3880    // Get all chunks and verify their bitmaps
3881    let chunks = snapshot.chunks(0..snapshot.len(), false);
3882
3883    for chunk in chunks {
3884        let chunk_text = chunk.text;
3885        let chars_bitmap = chunk.chars;
3886        let tabs_bitmap = chunk.tabs;
3887
3888        // Check empty chunks have empty bitmaps
3889        if chunk_text.is_empty() {
3890            assert_eq!(
3891                chars_bitmap, 0,
3892                "Empty chunk should have empty chars bitmap"
3893            );
3894            assert_eq!(tabs_bitmap, 0, "Empty chunk should have empty tabs bitmap");
3895            continue;
3896        }
3897
3898        // Verify that chunk text doesn't exceed 128 bytes
3899        assert!(
3900            chunk_text.len() <= 128,
3901            "Chunk text length {} exceeds 128 bytes",
3902            chunk_text.len()
3903        );
3904
3905        // Verify chars bitmap
3906        let char_indices = chunk_text
3907            .char_indices()
3908            .map(|(i, _)| i)
3909            .collect::<Vec<_>>();
3910
3911        for byte_idx in 0..chunk_text.len() {
3912            let should_have_bit = char_indices.contains(&byte_idx);
3913            let has_bit = chars_bitmap & (1 << byte_idx) != 0;
3914
3915            if has_bit != should_have_bit {
3916                eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
3917                eprintln!("Char indices: {:?}", char_indices);
3918                eprintln!("Chars bitmap: {:#b}", chars_bitmap);
3919            }
3920
3921            assert_eq!(
3922                has_bit, should_have_bit,
3923                "Chars bitmap mismatch at byte index {} in chunk {:?}. Expected bit: {}, Got bit: {}",
3924                byte_idx, chunk_text, should_have_bit, has_bit
3925            );
3926        }
3927
3928        // Verify tabs bitmap
3929        for (byte_idx, byte) in chunk_text.bytes().enumerate() {
3930            let is_tab = byte == b'\t';
3931            let has_bit = tabs_bitmap & (1 << byte_idx) != 0;
3932
3933            if has_bit != is_tab {
3934                eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
3935                eprintln!("Tabs bitmap: {:#b}", tabs_bitmap);
3936                assert_eq!(
3937                    has_bit, is_tab,
3938                    "Tabs bitmap mismatch at byte index {} in chunk {:?}. Byte: {:?}, Expected bit: {}, Got bit: {}",
3939                    byte_idx, chunk_text, byte as char, is_tab, has_bit
3940                );
3941            }
3942        }
3943    }
3944}