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