buffer_tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use fs::LineEnding;
   5use gpui::{AppContext, ModelHandle};
   6use indoc::indoc;
   7use proto::deserialize_operation;
   8use rand::prelude::*;
   9use regex::RegexBuilder;
  10use settings::Settings;
  11use std::{
  12    cell::RefCell,
  13    env,
  14    ops::Range,
  15    rc::Rc,
  16    time::{Duration, Instant},
  17};
  18use text::network::Network;
  19use unindent::Unindent as _;
  20use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  21
  22lazy_static! {
  23    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  24        .multi_line(true)
  25        .build()
  26        .unwrap();
  27}
  28
  29#[cfg(test)]
  30#[ctor::ctor]
  31fn init_logger() {
  32    if std::env::var("RUST_LOG").is_ok() {
  33        env_logger::init();
  34    }
  35}
  36
  37#[gpui::test]
  38fn test_line_endings(cx: &mut gpui::AppContext) {
  39    cx.set_global(Settings::test(cx));
  40    cx.add_model(|cx| {
  41        let mut buffer =
  42            Buffer::new(0, "one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  43        assert_eq!(buffer.text(), "one\ntwo\nthree");
  44        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  45
  46        buffer.check_invariants();
  47        buffer.edit(
  48            [(buffer.len()..buffer.len(), "\r\nfour")],
  49            Some(AutoindentMode::EachLine),
  50            cx,
  51        );
  52        buffer.edit([(0..0, "zero\r\n")], None, cx);
  53        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  54        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  55        buffer.check_invariants();
  56
  57        buffer
  58    });
  59}
  60
  61#[gpui::test]
  62fn test_select_language() {
  63    let registry = Arc::new(LanguageRegistry::test());
  64    registry.add(Arc::new(Language::new(
  65        LanguageConfig {
  66            name: "Rust".into(),
  67            path_suffixes: vec!["rs".to_string()],
  68            ..Default::default()
  69        },
  70        Some(tree_sitter_rust::language()),
  71    )));
  72    registry.add(Arc::new(Language::new(
  73        LanguageConfig {
  74            name: "Make".into(),
  75            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  76            ..Default::default()
  77        },
  78        Some(tree_sitter_rust::language()),
  79    )));
  80
  81    // matching file extension
  82    assert_eq!(
  83        registry
  84            .language_for_file("zed/lib.rs", None)
  85            .now_or_never()
  86            .and_then(|l| Some(l.ok()?.name())),
  87        Some("Rust".into())
  88    );
  89    assert_eq!(
  90        registry
  91            .language_for_file("zed/lib.mk", None)
  92            .now_or_never()
  93            .and_then(|l| Some(l.ok()?.name())),
  94        Some("Make".into())
  95    );
  96
  97    // matching filename
  98    assert_eq!(
  99        registry
 100            .language_for_file("zed/Makefile", None)
 101            .now_or_never()
 102            .and_then(|l| Some(l.ok()?.name())),
 103        Some("Make".into())
 104    );
 105
 106    // matching suffix that is not the full file extension or filename
 107    assert_eq!(
 108        registry
 109            .language_for_file("zed/cars", None)
 110            .now_or_never()
 111            .and_then(|l| Some(l.ok()?.name())),
 112        None
 113    );
 114    assert_eq!(
 115        registry
 116            .language_for_file("zed/a.cars", None)
 117            .now_or_never()
 118            .and_then(|l| Some(l.ok()?.name())),
 119        None
 120    );
 121    assert_eq!(
 122        registry
 123            .language_for_file("zed/sumk", None)
 124            .now_or_never()
 125            .and_then(|l| Some(l.ok()?.name())),
 126        None
 127    );
 128}
 129
 130#[gpui::test]
 131fn test_edit_events(cx: &mut gpui::AppContext) {
 132    let mut now = Instant::now();
 133    let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
 134    let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
 135
 136    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
 137    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
 138    let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
 139    buffer1.update(cx, {
 140        let buffer1_ops = buffer1_ops.clone();
 141        |buffer, cx| {
 142            let buffer_1_events = buffer_1_events.clone();
 143            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 144                Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
 145                event => buffer_1_events.borrow_mut().push(event),
 146            })
 147            .detach();
 148            let buffer_2_events = buffer_2_events.clone();
 149            cx.subscribe(&buffer2, move |_, _, event, _| {
 150                buffer_2_events.borrow_mut().push(event.clone())
 151            })
 152            .detach();
 153
 154            // An edit emits an edited event, followed by a dirty changed event,
 155            // since the buffer was previously in a clean state.
 156            buffer.edit([(2..4, "XYZ")], None, cx);
 157
 158            // An empty transaction does not emit any events.
 159            buffer.start_transaction();
 160            buffer.end_transaction(cx);
 161
 162            // A transaction containing two edits emits one edited event.
 163            now += Duration::from_secs(1);
 164            buffer.start_transaction_at(now);
 165            buffer.edit([(5..5, "u")], None, cx);
 166            buffer.edit([(6..6, "w")], None, cx);
 167            buffer.end_transaction_at(now, cx);
 168
 169            // Undoing a transaction emits one edited event.
 170            buffer.undo(cx);
 171        }
 172    });
 173
 174    // Incorporating a set of remote ops emits a single edited event,
 175    // followed by a dirty changed event.
 176    buffer2.update(cx, |buffer, cx| {
 177        buffer
 178            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 179            .unwrap();
 180    });
 181    assert_eq!(
 182        mem::take(&mut *buffer_1_events.borrow_mut()),
 183        vec![
 184            Event::Edited,
 185            Event::DirtyChanged,
 186            Event::Edited,
 187            Event::Edited,
 188        ]
 189    );
 190    assert_eq!(
 191        mem::take(&mut *buffer_2_events.borrow_mut()),
 192        vec![Event::Edited, Event::DirtyChanged]
 193    );
 194
 195    buffer1.update(cx, |buffer, cx| {
 196        // Undoing the first transaction emits edited event, followed by a
 197        // dirty changed event, since the buffer is again in a clean state.
 198        buffer.undo(cx);
 199    });
 200    // Incorporating the remote ops again emits a single edited event,
 201    // followed by a dirty changed event.
 202    buffer2.update(cx, |buffer, cx| {
 203        buffer
 204            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 205            .unwrap();
 206    });
 207    assert_eq!(
 208        mem::take(&mut *buffer_1_events.borrow_mut()),
 209        vec![Event::Edited, Event::DirtyChanged,]
 210    );
 211    assert_eq!(
 212        mem::take(&mut *buffer_2_events.borrow_mut()),
 213        vec![Event::Edited, Event::DirtyChanged]
 214    );
 215}
 216
 217#[gpui::test]
 218async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
 219    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 220    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 221    let anchor = buffer.read_with(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 222
 223    let text = "a\nccc\ndddd\nffffff\n";
 224    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 225    buffer.update(cx, |buffer, cx| {
 226        buffer.apply_diff(diff, cx).unwrap();
 227        assert_eq!(buffer.text(), text);
 228        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 229    });
 230
 231    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 232    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 233    buffer.update(cx, |buffer, cx| {
 234        buffer.apply_diff(diff, cx).unwrap();
 235        assert_eq!(buffer.text(), text);
 236        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 237    });
 238}
 239
 240#[gpui::test(iterations = 10)]
 241async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 242    let text = [
 243        "zero",     //
 244        "one  ",    // 2 trailing spaces
 245        "two",      //
 246        "three   ", // 3 trailing spaces
 247        "four",     //
 248        "five    ", // 4 trailing spaces
 249    ]
 250    .join("\n");
 251
 252    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 253
 254    // Spawn a task to format the buffer's whitespace.
 255    // Pause so that the foratting task starts running.
 256    let format = buffer.read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 257    smol::future::yield_now().await;
 258
 259    // Edit the buffer while the normalization task is running.
 260    let version_before_edit = buffer.read_with(cx, |buffer, _| buffer.version());
 261    buffer.update(cx, |buffer, cx| {
 262        buffer.edit(
 263            [
 264                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 265                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 266            ],
 267            None,
 268            cx,
 269        );
 270    });
 271
 272    let format_diff = format.await;
 273    buffer.update(cx, |buffer, cx| {
 274        let version_before_format = format_diff.base_version.clone();
 275        buffer.apply_diff(format_diff, cx);
 276
 277        // The outcome depends on the order of concurrent taks.
 278        //
 279        // If the edit occurred while searching for trailing whitespace ranges,
 280        // then the trailing whitespace region touched by the edit is left intact.
 281        if version_before_format == version_before_edit {
 282            assert_eq!(
 283                buffer.text(),
 284                [
 285                    "zEEero",      //
 286                    "one",         //
 287                    "two",         //
 288                    "threeEEE   ", //
 289                    "four",        //
 290                    "five",        //
 291                ]
 292                .join("\n")
 293            );
 294        }
 295        // Otherwise, all trailing whitespace is removed.
 296        else {
 297            assert_eq!(
 298                buffer.text(),
 299                [
 300                    "zEEero",   //
 301                    "one",      //
 302                    "two",      //
 303                    "threeEEE", //
 304                    "four",     //
 305                    "five",     //
 306                ]
 307                .join("\n")
 308            );
 309        }
 310    });
 311}
 312
 313#[gpui::test]
 314async fn test_reparse(cx: &mut gpui::TestAppContext) {
 315    let text = "fn a() {}";
 316    let buffer =
 317        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 318
 319    // Wait for the initial text to parse
 320    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 321    assert_eq!(
 322        get_tree_sexp(&buffer, cx),
 323        concat!(
 324            "(source_file (function_item name: (identifier) ",
 325            "parameters: (parameters) ",
 326            "body: (block)))"
 327        )
 328    );
 329
 330    buffer.update(cx, |buffer, _| {
 331        buffer.set_sync_parse_timeout(Duration::ZERO)
 332    });
 333
 334    // Perform some edits (add parameter and variable reference)
 335    // Parsing doesn't begin until the transaction is complete
 336    buffer.update(cx, |buf, cx| {
 337        buf.start_transaction();
 338
 339        let offset = buf.text().find(')').unwrap();
 340        buf.edit([(offset..offset, "b: C")], None, cx);
 341        assert!(!buf.is_parsing());
 342
 343        let offset = buf.text().find('}').unwrap();
 344        buf.edit([(offset..offset, " d; ")], None, cx);
 345        assert!(!buf.is_parsing());
 346
 347        buf.end_transaction(cx);
 348        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 349        assert!(buf.is_parsing());
 350    });
 351    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 352    assert_eq!(
 353        get_tree_sexp(&buffer, cx),
 354        concat!(
 355            "(source_file (function_item name: (identifier) ",
 356            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 357            "body: (block (expression_statement (identifier)))))"
 358        )
 359    );
 360
 361    // Perform a series of edits without waiting for the current parse to complete:
 362    // * turn identifier into a field expression
 363    // * turn field expression into a method call
 364    // * add a turbofish to the method call
 365    buffer.update(cx, |buf, cx| {
 366        let offset = buf.text().find(';').unwrap();
 367        buf.edit([(offset..offset, ".e")], None, cx);
 368        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 369        assert!(buf.is_parsing());
 370    });
 371    buffer.update(cx, |buf, cx| {
 372        let offset = buf.text().find(';').unwrap();
 373        buf.edit([(offset..offset, "(f)")], None, cx);
 374        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 375        assert!(buf.is_parsing());
 376    });
 377    buffer.update(cx, |buf, cx| {
 378        let offset = buf.text().find("(f)").unwrap();
 379        buf.edit([(offset..offset, "::<G>")], None, cx);
 380        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 381        assert!(buf.is_parsing());
 382    });
 383    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 384    assert_eq!(
 385        get_tree_sexp(&buffer, cx),
 386        concat!(
 387            "(source_file (function_item name: (identifier) ",
 388            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 389            "body: (block (expression_statement (call_expression ",
 390            "function: (generic_function ",
 391            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 392            "type_arguments: (type_arguments (type_identifier))) ",
 393            "arguments: (arguments (identifier)))))))",
 394        )
 395    );
 396
 397    buffer.update(cx, |buf, cx| {
 398        buf.undo(cx);
 399        buf.undo(cx);
 400        buf.undo(cx);
 401        buf.undo(cx);
 402        assert_eq!(buf.text(), "fn a() {}");
 403        assert!(buf.is_parsing());
 404    });
 405    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 406    assert_eq!(
 407        get_tree_sexp(&buffer, cx),
 408        concat!(
 409            "(source_file (function_item name: (identifier) ",
 410            "parameters: (parameters) ",
 411            "body: (block)))"
 412        )
 413    );
 414
 415    buffer.update(cx, |buf, cx| {
 416        buf.redo(cx);
 417        buf.redo(cx);
 418        buf.redo(cx);
 419        buf.redo(cx);
 420        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 421        assert!(buf.is_parsing());
 422    });
 423    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 424    assert_eq!(
 425        get_tree_sexp(&buffer, cx),
 426        concat!(
 427            "(source_file (function_item name: (identifier) ",
 428            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 429            "body: (block (expression_statement (call_expression ",
 430            "function: (generic_function ",
 431            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 432            "type_arguments: (type_arguments (type_identifier))) ",
 433            "arguments: (arguments (identifier)))))))",
 434        )
 435    );
 436}
 437
 438#[gpui::test]
 439async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 440    let buffer = cx.add_model(|cx| {
 441        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 442        buffer.set_sync_parse_timeout(Duration::ZERO);
 443        buffer
 444    });
 445
 446    // Wait for the initial text to parse
 447    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 448    assert_eq!(
 449        get_tree_sexp(&buffer, cx),
 450        "(source_file (expression_statement (block)))"
 451    );
 452
 453    buffer.update(cx, |buffer, cx| {
 454        buffer.set_language(Some(Arc::new(json_lang())), cx)
 455    });
 456    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 457    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 458}
 459
 460#[gpui::test]
 461async fn test_outline(cx: &mut gpui::TestAppContext) {
 462    let text = r#"
 463        struct Person {
 464            name: String,
 465            age: usize,
 466        }
 467
 468        mod module {
 469            enum LoginState {
 470                LoggedOut,
 471                LoggingOn,
 472                LoggedIn {
 473                    person: Person,
 474                    time: Instant,
 475                }
 476            }
 477        }
 478
 479        impl Eq for Person {}
 480
 481        impl Drop for Person {
 482            fn drop(&mut self) {
 483                println!("bye");
 484            }
 485        }
 486    "#
 487    .unindent();
 488
 489    let buffer =
 490        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 491    let outline = buffer
 492        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 493        .unwrap();
 494
 495    assert_eq!(
 496        outline
 497            .items
 498            .iter()
 499            .map(|item| (item.text.as_str(), item.depth))
 500            .collect::<Vec<_>>(),
 501        &[
 502            ("struct Person", 0),
 503            ("name", 1),
 504            ("age", 1),
 505            ("mod module", 0),
 506            ("enum LoginState", 1),
 507            ("LoggedOut", 2),
 508            ("LoggingOn", 2),
 509            ("LoggedIn", 2),
 510            ("person", 3),
 511            ("time", 3),
 512            ("impl Eq for Person", 0),
 513            ("impl Drop for Person", 0),
 514            ("fn drop", 1),
 515        ]
 516    );
 517
 518    // Without space, we only match on names
 519    assert_eq!(
 520        search(&outline, "oon", cx).await,
 521        &[
 522            ("mod module", vec![]),                    // included as the parent of a match
 523            ("enum LoginState", vec![]),               // included as the parent of a match
 524            ("LoggingOn", vec![1, 7, 8]),              // matches
 525            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 526        ]
 527    );
 528
 529    assert_eq!(
 530        search(&outline, "dp p", cx).await,
 531        &[
 532            ("impl Drop for Person", vec![5, 8, 9, 14]),
 533            ("fn drop", vec![]),
 534        ]
 535    );
 536    assert_eq!(
 537        search(&outline, "dpn", cx).await,
 538        &[("impl Drop for Person", vec![5, 14, 19])]
 539    );
 540    assert_eq!(
 541        search(&outline, "impl ", cx).await,
 542        &[
 543            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 544            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 545            ("fn drop", vec![]),
 546        ]
 547    );
 548
 549    async fn search<'a>(
 550        outline: &'a Outline<Anchor>,
 551        query: &'a str,
 552        cx: &'a gpui::TestAppContext,
 553    ) -> Vec<(&'a str, Vec<usize>)> {
 554        let matches = cx
 555            .read(|cx| outline.search(query, cx.background().clone()))
 556            .await;
 557        matches
 558            .into_iter()
 559            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 560            .collect::<Vec<_>>()
 561    }
 562}
 563
 564#[gpui::test]
 565async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 566    let text = r#"
 567        impl A for B<
 568            C
 569        > {
 570        };
 571    "#
 572    .unindent();
 573
 574    let buffer =
 575        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 576    let outline = buffer
 577        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 578        .unwrap();
 579
 580    assert_eq!(
 581        outline
 582            .items
 583            .iter()
 584            .map(|item| (item.text.as_str(), item.depth))
 585            .collect::<Vec<_>>(),
 586        &[("impl A for B<", 0)]
 587    );
 588}
 589
 590#[gpui::test]
 591async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 592    let text = r#"
 593        impl Person {
 594            fn one() {
 595                1
 596            }
 597
 598            fn two() {
 599                2
 600            }fn three() {
 601                3
 602            }
 603        }
 604    "#
 605    .unindent();
 606
 607    let buffer =
 608        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 609    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 610
 611    // point is at the start of an item
 612    assert_eq!(
 613        symbols_containing(Point::new(1, 4), &snapshot),
 614        vec![
 615            (
 616                "impl Person".to_string(),
 617                Point::new(0, 0)..Point::new(10, 1)
 618            ),
 619            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 620        ]
 621    );
 622
 623    // point is in the middle of an item
 624    assert_eq!(
 625        symbols_containing(Point::new(2, 8), &snapshot),
 626        vec![
 627            (
 628                "impl Person".to_string(),
 629                Point::new(0, 0)..Point::new(10, 1)
 630            ),
 631            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 632        ]
 633    );
 634
 635    // point is at the end of an item
 636    assert_eq!(
 637        symbols_containing(Point::new(3, 5), &snapshot),
 638        vec![
 639            (
 640                "impl Person".to_string(),
 641                Point::new(0, 0)..Point::new(10, 1)
 642            ),
 643            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 644        ]
 645    );
 646
 647    // point is in between two adjacent items
 648    assert_eq!(
 649        symbols_containing(Point::new(7, 5), &snapshot),
 650        vec![
 651            (
 652                "impl Person".to_string(),
 653                Point::new(0, 0)..Point::new(10, 1)
 654            ),
 655            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 656        ]
 657    );
 658
 659    fn symbols_containing(
 660        position: Point,
 661        snapshot: &BufferSnapshot,
 662    ) -> Vec<(String, Range<Point>)> {
 663        snapshot
 664            .symbols_containing(position, None)
 665            .unwrap()
 666            .into_iter()
 667            .map(|item| {
 668                (
 669                    item.text,
 670                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 671                )
 672            })
 673            .collect()
 674    }
 675}
 676
 677#[gpui::test]
 678fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 679    let mut assert = |selection_text, range_markers| {
 680        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 681    };
 682
 683    assert(
 684        indoc! {"
 685            mod x {
 686                moˇd y {
 687
 688                }
 689            }
 690            let foo = 1;"},
 691        vec![indoc! {"
 692            mod x «{»
 693                mod y {
 694
 695                }
 696            «}»
 697            let foo = 1;"}],
 698    );
 699
 700    assert(
 701        indoc! {"
 702            mod x {
 703                mod y ˇ{
 704
 705                }
 706            }
 707            let foo = 1;"},
 708        vec![
 709            indoc! {"
 710                mod x «{»
 711                    mod y {
 712
 713                    }
 714                «}»
 715                let foo = 1;"},
 716            indoc! {"
 717                mod x {
 718                    mod y «{»
 719
 720                    «}»
 721                }
 722                let foo = 1;"},
 723        ],
 724    );
 725
 726    assert(
 727        indoc! {"
 728            mod x {
 729                mod y {
 730
 731 732            }
 733            let foo = 1;"},
 734        vec![
 735            indoc! {"
 736                mod x «{»
 737                    mod y {
 738
 739                    }
 740                «}»
 741                let foo = 1;"},
 742            indoc! {"
 743                mod x {
 744                    mod y «{»
 745
 746                    «}»
 747                }
 748                let foo = 1;"},
 749        ],
 750    );
 751
 752    assert(
 753        indoc! {"
 754            mod x {
 755                mod y {
 756
 757                }
 758            ˇ}
 759            let foo = 1;"},
 760        vec![indoc! {"
 761            mod x «{»
 762                mod y {
 763
 764                }
 765            «}»
 766            let foo = 1;"}],
 767    );
 768
 769    assert(
 770        indoc! {"
 771            mod x {
 772                mod y {
 773
 774                }
 775            }
 776            let fˇoo = 1;"},
 777        vec![],
 778    );
 779
 780    // Regression test: avoid crash when querying at the end of the buffer.
 781    assert(
 782        indoc! {"
 783            mod x {
 784                mod y {
 785
 786                }
 787            }
 788            let foo = 1;ˇ"},
 789        vec![],
 790    );
 791}
 792
 793#[gpui::test]
 794fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 795    let mut assert = |selection_text, bracket_pair_texts| {
 796        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 797    };
 798
 799    assert(
 800        indoc! {"
 801        for (const a in b)ˇ {
 802            // a comment that's longer than the for-loop header
 803        }"},
 804        vec![indoc! {"
 805        for «(»const a in b«)» {
 806            // a comment that's longer than the for-loop header
 807        }"}],
 808    );
 809
 810    // Regression test: even though the parent node of the parentheses (the for loop) does
 811    // intersect the given range, the parentheses themselves do not contain the range, so
 812    // they should not be returned. Only the curly braces contain the range.
 813    assert(
 814        indoc! {"
 815        for (const a in b) {ˇ
 816            // a comment that's longer than the for-loop header
 817        }"},
 818        vec![indoc! {"
 819        for (const a in b) «{»
 820            // a comment that's longer than the for-loop header
 821        «}»"}],
 822    );
 823}
 824
 825#[gpui::test]
 826fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
 827    cx.add_model(|cx| {
 828        let text = "fn a() { b(|c| {}) }";
 829        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 830        let snapshot = buffer.snapshot();
 831
 832        assert_eq!(
 833            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 834            Some(range_of(text, "|"))
 835        );
 836        assert_eq!(
 837            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 838            Some(range_of(text, "|c|"))
 839        );
 840        assert_eq!(
 841            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 842            Some(range_of(text, "|c| {}"))
 843        );
 844        assert_eq!(
 845            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 846            Some(range_of(text, "(|c| {})"))
 847        );
 848
 849        buffer
 850    });
 851
 852    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 853        let start = text.find(part).unwrap();
 854        start..start
 855    }
 856
 857    fn range_of(text: &str, part: &str) -> Range<usize> {
 858        let start = text.find(part).unwrap();
 859        start..start + part.len()
 860    }
 861}
 862
 863#[gpui::test]
 864fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
 865    let settings = Settings::test(cx);
 866    cx.set_global(settings);
 867
 868    cx.add_model(|cx| {
 869        let text = "fn a() {}";
 870        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 871
 872        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 873        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 874
 875        buffer.edit(
 876            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 877            Some(AutoindentMode::EachLine),
 878            cx,
 879        );
 880        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 881
 882        // Create a field expression on a new line, causing that line
 883        // to be indented.
 884        buffer.edit(
 885            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 886            Some(AutoindentMode::EachLine),
 887            cx,
 888        );
 889        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 890
 891        // Remove the dot so that the line is no longer a field expression,
 892        // causing the line to be outdented.
 893        buffer.edit(
 894            [(Point::new(2, 8)..Point::new(2, 9), "")],
 895            Some(AutoindentMode::EachLine),
 896            cx,
 897        );
 898        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 899
 900        buffer
 901    });
 902}
 903
 904#[gpui::test]
 905fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
 906    let mut settings = Settings::test(cx);
 907    settings.editor_overrides.hard_tabs = Some(true);
 908    cx.set_global(settings);
 909
 910    cx.add_model(|cx| {
 911        let text = "fn a() {}";
 912        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 913
 914        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 915        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 916
 917        buffer.edit(
 918            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 919            Some(AutoindentMode::EachLine),
 920            cx,
 921        );
 922        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 923
 924        // Create a field expression on a new line, causing that line
 925        // to be indented.
 926        buffer.edit(
 927            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 928            Some(AutoindentMode::EachLine),
 929            cx,
 930        );
 931        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 932
 933        // Remove the dot so that the line is no longer a field expression,
 934        // causing the line to be outdented.
 935        buffer.edit(
 936            [(Point::new(2, 2)..Point::new(2, 3), "")],
 937            Some(AutoindentMode::EachLine),
 938            cx,
 939        );
 940        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 941
 942        buffer
 943    });
 944}
 945
 946#[gpui::test]
 947fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
 948    let settings = Settings::test(cx);
 949    cx.set_global(settings);
 950
 951    cx.add_model(|cx| {
 952        let mut buffer = Buffer::new(
 953            0,
 954            "
 955            fn a() {
 956            c;
 957            d;
 958            }
 959            "
 960            .unindent(),
 961            cx,
 962        )
 963        .with_language(Arc::new(rust_lang()), cx);
 964
 965        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 966        // their indentation is not adjusted.
 967        buffer.edit_via_marked_text(
 968            &"
 969            fn a() {
 970            c«()»;
 971            d«()»;
 972            }
 973            "
 974            .unindent(),
 975            Some(AutoindentMode::EachLine),
 976            cx,
 977        );
 978        assert_eq!(
 979            buffer.text(),
 980            "
 981            fn a() {
 982            c();
 983            d();
 984            }
 985            "
 986            .unindent()
 987        );
 988
 989        // When appending new content after these lines, the indentation is based on the
 990        // preceding lines' actual indentation.
 991        buffer.edit_via_marked_text(
 992            &"
 993            fn a() {
 994 995            .f
 996            .g()»;
 997 998            .f
 999            .g()»;
1000            }
1001            "
1002            .unindent(),
1003            Some(AutoindentMode::EachLine),
1004            cx,
1005        );
1006
1007        assert_eq!(
1008            buffer.text(),
1009            "
1010            fn a() {
1011            c
1012                .f
1013                .g();
1014            d
1015                .f
1016                .g();
1017            }
1018            "
1019            .unindent()
1020        );
1021        buffer
1022    });
1023
1024    cx.add_model(|cx| {
1025        let mut buffer = Buffer::new(
1026            0,
1027            "
1028            fn a() {
1029                b();
1030                |
1031            "
1032            .replace("|", "") // marker to preserve trailing whitespace
1033            .unindent(),
1034            cx,
1035        )
1036        .with_language(Arc::new(rust_lang()), cx);
1037
1038        // Insert a closing brace. It is outdented.
1039        buffer.edit_via_marked_text(
1040            &"
1041            fn a() {
1042                b();
1043                «}»
1044            "
1045            .unindent(),
1046            Some(AutoindentMode::EachLine),
1047            cx,
1048        );
1049        assert_eq!(
1050            buffer.text(),
1051            "
1052            fn a() {
1053                b();
1054            }
1055            "
1056            .unindent()
1057        );
1058
1059        // Manually edit the leading whitespace. The edit is preserved.
1060        buffer.edit_via_marked_text(
1061            &"
1062            fn a() {
1063                b();
1064            «    »}
1065            "
1066            .unindent(),
1067            Some(AutoindentMode::EachLine),
1068            cx,
1069        );
1070        assert_eq!(
1071            buffer.text(),
1072            "
1073            fn a() {
1074                b();
1075                }
1076            "
1077            .unindent()
1078        );
1079        buffer
1080    });
1081}
1082
1083#[gpui::test]
1084fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1085    let settings = Settings::test(cx);
1086    cx.set_global(settings);
1087
1088    cx.add_model(|cx| {
1089        let mut buffer = Buffer::new(
1090            0,
1091            "
1092            fn a() {
1093                i
1094            }
1095            "
1096            .unindent(),
1097            cx,
1098        )
1099        .with_language(Arc::new(rust_lang()), cx);
1100
1101        // Regression test: line does not get outdented due to syntax error
1102        buffer.edit_via_marked_text(
1103            &"
1104            fn a() {
1105                i«f let Some(x) = y»
1106            }
1107            "
1108            .unindent(),
1109            Some(AutoindentMode::EachLine),
1110            cx,
1111        );
1112        assert_eq!(
1113            buffer.text(),
1114            "
1115            fn a() {
1116                if let Some(x) = y
1117            }
1118            "
1119            .unindent()
1120        );
1121
1122        buffer.edit_via_marked_text(
1123            &"
1124            fn a() {
1125                if let Some(x) = y« {»
1126            }
1127            "
1128            .unindent(),
1129            Some(AutoindentMode::EachLine),
1130            cx,
1131        );
1132        assert_eq!(
1133            buffer.text(),
1134            "
1135            fn a() {
1136                if let Some(x) = y {
1137            }
1138            "
1139            .unindent()
1140        );
1141
1142        buffer
1143    });
1144}
1145
1146#[gpui::test]
1147fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1148    cx.set_global(Settings::test(cx));
1149    cx.add_model(|cx| {
1150        let mut buffer = Buffer::new(
1151            0,
1152            "
1153            fn a() {}
1154            "
1155            .unindent(),
1156            cx,
1157        )
1158        .with_language(Arc::new(rust_lang()), cx);
1159
1160        buffer.edit_via_marked_text(
1161            &"
1162            fn a(«
1163            b») {}
1164            "
1165            .unindent(),
1166            Some(AutoindentMode::EachLine),
1167            cx,
1168        );
1169        assert_eq!(
1170            buffer.text(),
1171            "
1172            fn a(
1173                b) {}
1174            "
1175            .unindent()
1176        );
1177
1178        // The indentation suggestion changed because `@end` node (a close paren)
1179        // is now at the beginning of the line.
1180        buffer.edit_via_marked_text(
1181            &"
1182            fn a(
1183                ˇ) {}
1184            "
1185            .unindent(),
1186            Some(AutoindentMode::EachLine),
1187            cx,
1188        );
1189        assert_eq!(
1190            buffer.text(),
1191            "
1192                fn a(
1193                ) {}
1194            "
1195            .unindent()
1196        );
1197
1198        buffer
1199    });
1200}
1201
1202#[gpui::test]
1203fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1204    cx.set_global(Settings::test(cx));
1205    cx.add_model(|cx| {
1206        let text = "a\nb";
1207        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1208        buffer.edit(
1209            [(0..1, "\n"), (2..3, "\n")],
1210            Some(AutoindentMode::EachLine),
1211            cx,
1212        );
1213        assert_eq!(buffer.text(), "\n\n\n");
1214        buffer
1215    });
1216}
1217
1218#[gpui::test]
1219fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1220    cx.set_global(Settings::test(cx));
1221    cx.add_model(|cx| {
1222        let text = "
1223            const a: usize = 1;
1224            fn b() {
1225                if c {
1226                    let d = 2;
1227                }
1228            }
1229        "
1230        .unindent();
1231
1232        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1233        buffer.edit(
1234            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1235            Some(AutoindentMode::EachLine),
1236            cx,
1237        );
1238        assert_eq!(
1239            buffer.text(),
1240            "
1241                const a: usize = 1;
1242                fn b() {
1243                    if c {
1244                        e(
1245                            f()
1246                        );
1247                        let d = 2;
1248                    }
1249                }
1250            "
1251            .unindent()
1252        );
1253
1254        buffer
1255    });
1256}
1257
1258#[gpui::test]
1259fn test_autoindent_block_mode(cx: &mut AppContext) {
1260    cx.set_global(Settings::test(cx));
1261    cx.add_model(|cx| {
1262        let text = r#"
1263            fn a() {
1264                b();
1265            }
1266        "#
1267        .unindent();
1268        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1269
1270        // When this text was copied, both of the quotation marks were at the same
1271        // indent level, but the indentation of the first line was not included in
1272        // the copied text. This information is retained in the
1273        // 'original_indent_columns' vector.
1274        let original_indent_columns = vec![4];
1275        let inserted_text = r#"
1276            "
1277                  c
1278                    d
1279                      e
1280                "
1281        "#
1282        .unindent();
1283
1284        // Insert the block at column zero. The entire block is indented
1285        // so that the first line matches the previous line's indentation.
1286        buffer.edit(
1287            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1288            Some(AutoindentMode::Block {
1289                original_indent_columns: original_indent_columns.clone(),
1290            }),
1291            cx,
1292        );
1293        assert_eq!(
1294            buffer.text(),
1295            r#"
1296            fn a() {
1297                b();
1298                "
1299                  c
1300                    d
1301                      e
1302                "
1303            }
1304            "#
1305            .unindent()
1306        );
1307
1308        // Grouping is disabled in tests, so we need 2 undos
1309        buffer.undo(cx); // Undo the auto-indent
1310        buffer.undo(cx); // Undo the original edit
1311
1312        // Insert the block at a deeper indent level. The entire block is outdented.
1313        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1314        buffer.edit(
1315            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1316            Some(AutoindentMode::Block {
1317                original_indent_columns: original_indent_columns.clone(),
1318            }),
1319            cx,
1320        );
1321        assert_eq!(
1322            buffer.text(),
1323            r#"
1324            fn a() {
1325                b();
1326                "
1327                  c
1328                    d
1329                      e
1330                "
1331            }
1332            "#
1333            .unindent()
1334        );
1335
1336        buffer
1337    });
1338}
1339
1340#[gpui::test]
1341fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1342    cx.set_global(Settings::test(cx));
1343    cx.add_model(|cx| {
1344        let text = r#"
1345            fn a() {
1346                if b() {
1347
1348                }
1349            }
1350        "#
1351        .unindent();
1352        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1353
1354        // The original indent columns are not known, so this text is
1355        // auto-indented in a block as if the first line was copied in
1356        // its entirety.
1357        let original_indent_columns = Vec::new();
1358        let inserted_text = "    c\n        .d()\n        .e();";
1359
1360        // Insert the block at column zero. The entire block is indented
1361        // so that the first line matches the previous line's indentation.
1362        buffer.edit(
1363            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1364            Some(AutoindentMode::Block {
1365                original_indent_columns: original_indent_columns.clone(),
1366            }),
1367            cx,
1368        );
1369        assert_eq!(
1370            buffer.text(),
1371            r#"
1372            fn a() {
1373                if b() {
1374                    c
1375                        .d()
1376                        .e();
1377                }
1378            }
1379            "#
1380            .unindent()
1381        );
1382
1383        // Grouping is disabled in tests, so we need 2 undos
1384        buffer.undo(cx); // Undo the auto-indent
1385        buffer.undo(cx); // Undo the original edit
1386
1387        // Insert the block at a deeper indent level. The entire block is outdented.
1388        buffer.edit(
1389            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1390            None,
1391            cx,
1392        );
1393        buffer.edit(
1394            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1395            Some(AutoindentMode::Block {
1396                original_indent_columns: Vec::new(),
1397            }),
1398            cx,
1399        );
1400        assert_eq!(
1401            buffer.text(),
1402            r#"
1403            fn a() {
1404                if b() {
1405                    c
1406                        .d()
1407                        .e();
1408                }
1409            }
1410            "#
1411            .unindent()
1412        );
1413
1414        buffer
1415    });
1416}
1417
1418#[gpui::test]
1419fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1420    cx.set_global(Settings::test(cx));
1421    cx.add_model(|cx| {
1422        let text = "
1423            * one
1424                - a
1425                - b
1426            * two
1427        "
1428        .unindent();
1429
1430        let mut buffer = Buffer::new(0, text, cx).with_language(
1431            Arc::new(Language::new(
1432                LanguageConfig {
1433                    name: "Markdown".into(),
1434                    auto_indent_using_last_non_empty_line: false,
1435                    ..Default::default()
1436                },
1437                Some(tree_sitter_json::language()),
1438            )),
1439            cx,
1440        );
1441        buffer.edit(
1442            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1443            Some(AutoindentMode::EachLine),
1444            cx,
1445        );
1446        assert_eq!(
1447            buffer.text(),
1448            "
1449            * one
1450                - a
1451                - b
1452
1453            * two
1454            "
1455            .unindent()
1456        );
1457        buffer
1458    });
1459}
1460
1461#[gpui::test]
1462fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1463    cx.set_global({
1464        let mut settings = Settings::test(cx);
1465        settings.language_overrides.extend([
1466            (
1467                "HTML".into(),
1468                settings::EditorSettings {
1469                    tab_size: Some(2.try_into().unwrap()),
1470                    ..Default::default()
1471                },
1472            ),
1473            (
1474                "JavaScript".into(),
1475                settings::EditorSettings {
1476                    tab_size: Some(8.try_into().unwrap()),
1477                    ..Default::default()
1478                },
1479            ),
1480        ]);
1481        settings
1482    });
1483
1484    let html_language = Arc::new(
1485        Language::new(
1486            LanguageConfig {
1487                name: "HTML".into(),
1488                ..Default::default()
1489            },
1490            Some(tree_sitter_html::language()),
1491        )
1492        .with_indents_query(
1493            "
1494            (element
1495              (start_tag) @start
1496              (end_tag)? @end) @indent
1497            ",
1498        )
1499        .unwrap()
1500        .with_injection_query(
1501            r#"
1502            (script_element
1503                (raw_text) @content
1504                (#set! "language" "javascript"))
1505            "#,
1506        )
1507        .unwrap(),
1508    );
1509
1510    let javascript_language = Arc::new(
1511        Language::new(
1512            LanguageConfig {
1513                name: "JavaScript".into(),
1514                ..Default::default()
1515            },
1516            Some(tree_sitter_javascript::language()),
1517        )
1518        .with_indents_query(
1519            r#"
1520            (object "}" @end) @indent
1521            "#,
1522        )
1523        .unwrap(),
1524    );
1525
1526    let language_registry = Arc::new(LanguageRegistry::test());
1527    language_registry.add(html_language.clone());
1528    language_registry.add(javascript_language.clone());
1529
1530    cx.add_model(|cx| {
1531        let (text, ranges) = marked_text_ranges(
1532            &"
1533                <div>ˇ
1534                </div>
1535                <script>
1536                    init({ˇ
1537                    })
1538                </script>
1539                <span>ˇ
1540                </span>
1541            "
1542            .unindent(),
1543            false,
1544        );
1545
1546        let mut buffer = Buffer::new(0, text, cx);
1547        buffer.set_language_registry(language_registry);
1548        buffer.set_language(Some(html_language), cx);
1549        buffer.edit(
1550            ranges.into_iter().map(|range| (range, "\na")),
1551            Some(AutoindentMode::EachLine),
1552            cx,
1553        );
1554        assert_eq!(
1555            buffer.text(),
1556            "
1557                <div>
1558                  a
1559                </div>
1560                <script>
1561                    init({
1562                            a
1563                    })
1564                </script>
1565                <span>
1566                  a
1567                </span>
1568            "
1569            .unindent()
1570        );
1571        buffer
1572    });
1573}
1574
1575#[gpui::test]
1576fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1577    let mut settings = Settings::test(cx);
1578    settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
1579    cx.set_global(settings);
1580    cx.add_model(|cx| {
1581        let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(ruby_lang()), cx);
1582
1583        let text = r#"
1584            class C
1585            def a(b, c)
1586            puts b
1587            puts c
1588            rescue
1589            puts "errored"
1590            exit 1
1591            end
1592            end
1593        "#
1594        .unindent();
1595
1596        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1597
1598        assert_eq!(
1599            buffer.text(),
1600            r#"
1601                class C
1602                  def a(b, c)
1603                    puts b
1604                    puts c
1605                  rescue
1606                    puts "errored"
1607                    exit 1
1608                  end
1609                end
1610            "#
1611            .unindent()
1612        );
1613
1614        buffer
1615    });
1616}
1617
1618#[gpui::test]
1619fn test_language_config_at(cx: &mut AppContext) {
1620    cx.set_global(Settings::test(cx));
1621    cx.add_model(|cx| {
1622        let language = Language::new(
1623            LanguageConfig {
1624                name: "JavaScript".into(),
1625                line_comment: Some("// ".into()),
1626                brackets: BracketPairConfig {
1627                    pairs: vec![
1628                        BracketPair {
1629                            start: "{".into(),
1630                            end: "}".into(),
1631                            close: true,
1632                            newline: false,
1633                        },
1634                        BracketPair {
1635                            start: "'".into(),
1636                            end: "'".into(),
1637                            close: true,
1638                            newline: false,
1639                        },
1640                    ],
1641                    disabled_scopes_by_bracket_ix: vec![
1642                        Vec::new(), //
1643                        vec!["string".into()],
1644                    ],
1645                },
1646                overrides: [(
1647                    "element".into(),
1648                    LanguageConfigOverride {
1649                        line_comment: Override::Remove { remove: true },
1650                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1651                        ..Default::default()
1652                    },
1653                )]
1654                .into_iter()
1655                .collect(),
1656                ..Default::default()
1657            },
1658            Some(tree_sitter_javascript::language()),
1659        )
1660        .with_override_query(
1661            r#"
1662                (jsx_element) @element
1663                (string) @string
1664            "#,
1665        )
1666        .unwrap();
1667
1668        let text = r#"a["b"] = <C d="e"></C>;"#;
1669
1670        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
1671        let snapshot = buffer.snapshot();
1672
1673        let config = snapshot.language_scope_at(0).unwrap();
1674        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1675        // Both bracket pairs are enabled
1676        assert_eq!(
1677            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1678            &[true, true]
1679        );
1680
1681        let string_config = snapshot.language_scope_at(3).unwrap();
1682        assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
1683        // Second bracket pair is disabled
1684        assert_eq!(
1685            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1686            &[true, false]
1687        );
1688
1689        let element_config = snapshot.language_scope_at(10).unwrap();
1690        assert_eq!(element_config.line_comment_prefix(), None);
1691        assert_eq!(
1692            element_config.block_comment_delimiters(),
1693            Some((&"{/*".into(), &"*/}".into()))
1694        );
1695        // Both bracket pairs are enabled
1696        assert_eq!(
1697            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1698            &[true, true]
1699        );
1700
1701        buffer
1702    });
1703}
1704
1705#[gpui::test]
1706fn test_serialization(cx: &mut gpui::AppContext) {
1707    let mut now = Instant::now();
1708
1709    let buffer1 = cx.add_model(|cx| {
1710        let mut buffer = Buffer::new(0, "abc", cx);
1711        buffer.edit([(3..3, "D")], None, cx);
1712
1713        now += Duration::from_secs(1);
1714        buffer.start_transaction_at(now);
1715        buffer.edit([(4..4, "E")], None, cx);
1716        buffer.end_transaction_at(now, cx);
1717        assert_eq!(buffer.text(), "abcDE");
1718
1719        buffer.undo(cx);
1720        assert_eq!(buffer.text(), "abcD");
1721
1722        buffer.edit([(4..4, "F")], None, cx);
1723        assert_eq!(buffer.text(), "abcDF");
1724        buffer
1725    });
1726    assert_eq!(buffer1.read(cx).text(), "abcDF");
1727
1728    let state = buffer1.read(cx).to_proto();
1729    let ops = cx
1730        .background()
1731        .block(buffer1.read(cx).serialize_ops(None, cx));
1732    let buffer2 = cx.add_model(|cx| {
1733        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1734        buffer
1735            .apply_ops(
1736                ops.into_iter()
1737                    .map(|op| proto::deserialize_operation(op).unwrap()),
1738                cx,
1739            )
1740            .unwrap();
1741        buffer
1742    });
1743    assert_eq!(buffer2.read(cx).text(), "abcDF");
1744}
1745
1746#[gpui::test(iterations = 100)]
1747fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1748    let min_peers = env::var("MIN_PEERS")
1749        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1750        .unwrap_or(1);
1751    let max_peers = env::var("MAX_PEERS")
1752        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1753        .unwrap_or(5);
1754    let operations = env::var("OPERATIONS")
1755        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1756        .unwrap_or(10);
1757
1758    let base_text_len = rng.gen_range(0..10);
1759    let base_text = RandomCharIter::new(&mut rng)
1760        .take(base_text_len)
1761        .collect::<String>();
1762    let mut replica_ids = Vec::new();
1763    let mut buffers = Vec::new();
1764    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1765    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1766
1767    for i in 0..rng.gen_range(min_peers..=max_peers) {
1768        let buffer = cx.add_model(|cx| {
1769            let state = base_buffer.read(cx).to_proto();
1770            let ops = cx
1771                .background()
1772                .block(base_buffer.read(cx).serialize_ops(None, cx));
1773            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1774            buffer
1775                .apply_ops(
1776                    ops.into_iter()
1777                        .map(|op| proto::deserialize_operation(op).unwrap()),
1778                    cx,
1779                )
1780                .unwrap();
1781            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1782            let network = network.clone();
1783            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1784                if let Event::Operation(op) = event {
1785                    network
1786                        .borrow_mut()
1787                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1788                }
1789            })
1790            .detach();
1791            buffer
1792        });
1793        buffers.push(buffer);
1794        replica_ids.push(i as ReplicaId);
1795        network.borrow_mut().add_peer(i as ReplicaId);
1796        log::info!("Adding initial peer with replica id {}", i);
1797    }
1798
1799    log::info!("initial text: {:?}", base_text);
1800
1801    let mut now = Instant::now();
1802    let mut mutation_count = operations;
1803    let mut next_diagnostic_id = 0;
1804    let mut active_selections = BTreeMap::default();
1805    loop {
1806        let replica_index = rng.gen_range(0..replica_ids.len());
1807        let replica_id = replica_ids[replica_index];
1808        let buffer = &mut buffers[replica_index];
1809        let mut new_buffer = None;
1810        match rng.gen_range(0..100) {
1811            0..=29 if mutation_count != 0 => {
1812                buffer.update(cx, |buffer, cx| {
1813                    buffer.start_transaction_at(now);
1814                    buffer.randomly_edit(&mut rng, 5, cx);
1815                    buffer.end_transaction_at(now, cx);
1816                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1817                });
1818                mutation_count -= 1;
1819            }
1820            30..=39 if mutation_count != 0 => {
1821                buffer.update(cx, |buffer, cx| {
1822                    if rng.gen_bool(0.2) {
1823                        log::info!("peer {} clearing active selections", replica_id);
1824                        active_selections.remove(&replica_id);
1825                        buffer.remove_active_selections(cx);
1826                    } else {
1827                        let mut selections = Vec::new();
1828                        for id in 0..rng.gen_range(1..=5) {
1829                            let range = buffer.random_byte_range(0, &mut rng);
1830                            selections.push(Selection {
1831                                id,
1832                                start: buffer.anchor_before(range.start),
1833                                end: buffer.anchor_before(range.end),
1834                                reversed: false,
1835                                goal: SelectionGoal::None,
1836                            });
1837                        }
1838                        let selections: Arc<[Selection<Anchor>]> = selections.into();
1839                        log::info!(
1840                            "peer {} setting active selections: {:?}",
1841                            replica_id,
1842                            selections
1843                        );
1844                        active_selections.insert(replica_id, selections.clone());
1845                        buffer.set_active_selections(selections, false, Default::default(), cx);
1846                    }
1847                });
1848                mutation_count -= 1;
1849            }
1850            40..=49 if mutation_count != 0 && replica_id == 0 => {
1851                let entry_count = rng.gen_range(1..=5);
1852                buffer.update(cx, |buffer, cx| {
1853                    let diagnostics = DiagnosticSet::new(
1854                        (0..entry_count).map(|_| {
1855                            let range = buffer.random_byte_range(0, &mut rng);
1856                            let range = range.to_point_utf16(buffer);
1857                            let range = range.start..range.end;
1858                            DiagnosticEntry {
1859                                range,
1860                                diagnostic: Diagnostic {
1861                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1862                                    ..Default::default()
1863                                },
1864                            }
1865                        }),
1866                        buffer,
1867                    );
1868                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1869                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
1870                });
1871                mutation_count -= 1;
1872            }
1873            50..=59 if replica_ids.len() < max_peers => {
1874                let old_buffer_state = buffer.read(cx).to_proto();
1875                let old_buffer_ops = cx
1876                    .background()
1877                    .block(buffer.read(cx).serialize_ops(None, cx));
1878                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1879                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1880                    .choose(&mut rng)
1881                    .unwrap();
1882                log::info!(
1883                    "Adding new replica {} (replicating from {})",
1884                    new_replica_id,
1885                    replica_id
1886                );
1887                new_buffer = Some(cx.add_model(|cx| {
1888                    let mut new_buffer =
1889                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1890                    new_buffer
1891                        .apply_ops(
1892                            old_buffer_ops
1893                                .into_iter()
1894                                .map(|op| deserialize_operation(op).unwrap()),
1895                            cx,
1896                        )
1897                        .unwrap();
1898                    log::info!(
1899                        "New replica {} text: {:?}",
1900                        new_buffer.replica_id(),
1901                        new_buffer.text()
1902                    );
1903                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1904                    let network = network.clone();
1905                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1906                        if let Event::Operation(op) = event {
1907                            network.borrow_mut().broadcast(
1908                                buffer.replica_id(),
1909                                vec![proto::serialize_operation(op)],
1910                            );
1911                        }
1912                    })
1913                    .detach();
1914                    new_buffer
1915                }));
1916                network.borrow_mut().replicate(replica_id, new_replica_id);
1917
1918                if new_replica_id as usize == replica_ids.len() {
1919                    replica_ids.push(new_replica_id);
1920                } else {
1921                    let new_buffer = new_buffer.take().unwrap();
1922                    while network.borrow().has_unreceived(new_replica_id) {
1923                        let ops = network
1924                            .borrow_mut()
1925                            .receive(new_replica_id)
1926                            .into_iter()
1927                            .map(|op| proto::deserialize_operation(op).unwrap());
1928                        if ops.len() > 0 {
1929                            log::info!(
1930                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1931                                new_replica_id,
1932                                buffer.read(cx).version(),
1933                                ops.len(),
1934                                ops
1935                            );
1936                            new_buffer.update(cx, |new_buffer, cx| {
1937                                new_buffer.apply_ops(ops, cx).unwrap();
1938                            });
1939                        }
1940                    }
1941                    buffers[new_replica_id as usize] = new_buffer;
1942                }
1943            }
1944            60..=69 if mutation_count != 0 => {
1945                buffer.update(cx, |buffer, cx| {
1946                    buffer.randomly_undo_redo(&mut rng, cx);
1947                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1948                });
1949                mutation_count -= 1;
1950            }
1951            _ if network.borrow().has_unreceived(replica_id) => {
1952                let ops = network
1953                    .borrow_mut()
1954                    .receive(replica_id)
1955                    .into_iter()
1956                    .map(|op| proto::deserialize_operation(op).unwrap());
1957                if ops.len() > 0 {
1958                    log::info!(
1959                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1960                        replica_id,
1961                        buffer.read(cx).version(),
1962                        ops.len(),
1963                        ops
1964                    );
1965                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1966                }
1967            }
1968            _ => {}
1969        }
1970
1971        now += Duration::from_millis(rng.gen_range(0..=200));
1972        buffers.extend(new_buffer);
1973
1974        for buffer in &buffers {
1975            buffer.read(cx).check_invariants();
1976        }
1977
1978        if mutation_count == 0 && network.borrow().is_idle() {
1979            break;
1980        }
1981    }
1982
1983    let first_buffer = buffers[0].read(cx).snapshot();
1984    for buffer in &buffers[1..] {
1985        let buffer = buffer.read(cx).snapshot();
1986        assert_eq!(
1987            buffer.version(),
1988            first_buffer.version(),
1989            "Replica {} version != Replica 0 version",
1990            buffer.replica_id()
1991        );
1992        assert_eq!(
1993            buffer.text(),
1994            first_buffer.text(),
1995            "Replica {} text != Replica 0 text",
1996            buffer.replica_id()
1997        );
1998        assert_eq!(
1999            buffer
2000                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2001                .collect::<Vec<_>>(),
2002            first_buffer
2003                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2004                .collect::<Vec<_>>(),
2005            "Replica {} diagnostics != Replica 0 diagnostics",
2006            buffer.replica_id()
2007        );
2008    }
2009
2010    for buffer in &buffers {
2011        let buffer = buffer.read(cx).snapshot();
2012        let actual_remote_selections = buffer
2013            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2014            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2015            .collect::<Vec<_>>();
2016        let expected_remote_selections = active_selections
2017            .iter()
2018            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2019            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2020            .collect::<Vec<_>>();
2021        assert_eq!(
2022            actual_remote_selections,
2023            expected_remote_selections,
2024            "Replica {} remote selections != expected selections",
2025            buffer.replica_id()
2026        );
2027    }
2028}
2029
2030#[test]
2031fn test_contiguous_ranges() {
2032    assert_eq!(
2033        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2034        &[1..4, 5..7, 9..13]
2035    );
2036
2037    // Respects the `max_len` parameter
2038    assert_eq!(
2039        contiguous_ranges(
2040            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2041            3
2042        )
2043        .collect::<Vec<_>>(),
2044        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2045    );
2046}
2047
2048#[gpui::test(iterations = 500)]
2049fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2050    // Generate a random multi-line string containing
2051    // some lines with trailing whitespace.
2052    let mut text = String::new();
2053    for _ in 0..rng.gen_range(0..16) {
2054        for _ in 0..rng.gen_range(0..36) {
2055            text.push(match rng.gen_range(0..10) {
2056                0..=1 => ' ',
2057                3 => '\t',
2058                _ => rng.gen_range('a'..'z'),
2059            });
2060        }
2061        text.push('\n');
2062    }
2063
2064    match rng.gen_range(0..10) {
2065        // sometimes remove the last newline
2066        0..=1 => drop(text.pop()), //
2067
2068        // sometimes add extra newlines
2069        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2070        _ => {}
2071    }
2072
2073    let rope = Rope::from(text.as_str());
2074    let actual_ranges = trailing_whitespace_ranges(&rope);
2075    let expected_ranges = TRAILING_WHITESPACE_REGEX
2076        .find_iter(&text)
2077        .map(|m| m.range())
2078        .collect::<Vec<_>>();
2079    assert_eq!(
2080        actual_ranges,
2081        expected_ranges,
2082        "wrong ranges for text lines:\n{:?}",
2083        text.split("\n").collect::<Vec<_>>()
2084    );
2085}
2086
2087fn ruby_lang() -> Language {
2088    Language::new(
2089        LanguageConfig {
2090            name: "Ruby".into(),
2091            path_suffixes: vec!["rb".to_string()],
2092            ..Default::default()
2093        },
2094        Some(tree_sitter_ruby::language()),
2095    )
2096    .with_indents_query(
2097        r#"
2098            (class "end" @end) @indent
2099            (method "end" @end) @indent
2100            (rescue) @outdent
2101            (then) @indent
2102        "#,
2103    )
2104    .unwrap()
2105}
2106
2107fn rust_lang() -> Language {
2108    Language::new(
2109        LanguageConfig {
2110            name: "Rust".into(),
2111            path_suffixes: vec!["rs".to_string()],
2112            ..Default::default()
2113        },
2114        Some(tree_sitter_rust::language()),
2115    )
2116    .with_indents_query(
2117        r#"
2118        (call_expression) @indent
2119        (field_expression) @indent
2120        (_ "(" ")" @end) @indent
2121        (_ "{" "}" @end) @indent
2122        "#,
2123    )
2124    .unwrap()
2125    .with_brackets_query(
2126        r#"
2127        ("{" @open "}" @close)
2128        "#,
2129    )
2130    .unwrap()
2131    .with_outline_query(
2132        r#"
2133        (struct_item
2134            "struct" @context
2135            name: (_) @name) @item
2136        (enum_item
2137            "enum" @context
2138            name: (_) @name) @item
2139        (enum_variant
2140            name: (_) @name) @item
2141        (field_declaration
2142            name: (_) @name) @item
2143        (impl_item
2144            "impl" @context
2145            trait: (_)? @name
2146            "for"? @context
2147            type: (_) @name) @item
2148        (function_item
2149            "fn" @context
2150            name: (_) @name) @item
2151        (mod_item
2152            "mod" @context
2153            name: (_) @name) @item
2154        "#,
2155    )
2156    .unwrap()
2157}
2158
2159fn json_lang() -> Language {
2160    Language::new(
2161        LanguageConfig {
2162            name: "Json".into(),
2163            path_suffixes: vec!["js".to_string()],
2164            ..Default::default()
2165        },
2166        Some(tree_sitter_json::language()),
2167    )
2168}
2169
2170fn javascript_lang() -> Language {
2171    Language::new(
2172        LanguageConfig {
2173            name: "JavaScript".into(),
2174            ..Default::default()
2175        },
2176        Some(tree_sitter_javascript::language()),
2177    )
2178    .with_brackets_query(
2179        r#"
2180        ("{" @open "}" @close)
2181        ("(" @open ")" @close)
2182        "#,
2183    )
2184    .unwrap()
2185}
2186
2187fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2188    buffer.read_with(cx, |buffer, _| {
2189        let snapshot = buffer.snapshot();
2190        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2191        layers[0].node.to_sexp()
2192    })
2193}
2194
2195// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2196fn assert_bracket_pairs(
2197    selection_text: &'static str,
2198    bracket_pair_texts: Vec<&'static str>,
2199    language: Language,
2200    cx: &mut AppContext,
2201) {
2202    cx.set_global(Settings::test(cx));
2203    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2204    let buffer = cx.add_model(|cx| {
2205        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
2206    });
2207    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2208
2209    let selection_range = selection_ranges[0].clone();
2210
2211    let bracket_pairs = bracket_pair_texts
2212        .into_iter()
2213        .map(|pair_text| {
2214            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2215            assert_eq!(bracket_text, expected_text);
2216            (ranges[0].clone(), ranges[1].clone())
2217        })
2218        .collect::<Vec<_>>();
2219
2220    assert_set_eq!(
2221        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2222        bracket_pairs
2223    );
2224}