buffer_tests.rs

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