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