buffer_tests.rs

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