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