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