buffer_tests.rs

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