buffer_tests.rs

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