buffer_tests.rs

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