buffer_tests.rs

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