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