buffer_tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use fs::LineEnding;
   5use gpui::{ModelHandle, MutableAppContext};
   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::MutableAppContext) {
  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_path("zed/lib.rs")
  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_path("zed/lib.mk")
  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_path("zed/Makefile")
 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_path("zed/cars")
 110            .now_or_never()
 111            .and_then(|l| Some(l.ok()?.name())),
 112        None
 113    );
 114    assert_eq!(
 115        registry
 116            .language_for_path("zed/a.cars")
 117            .now_or_never()
 118            .and_then(|l| Some(l.ok()?.name())),
 119        None
 120    );
 121    assert_eq!(
 122        registry
 123            .language_for_path("zed/sumk")
 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::MutableAppContext) {
 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 MutableAppContext) {
 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(
 795    cx: &mut MutableAppContext,
 796) {
 797    let mut assert = |selection_text, bracket_pair_texts| {
 798        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 799    };
 800
 801    assert(
 802        indoc! {"
 803        for (const a in b)ˇ {
 804            // a comment that's longer than the for-loop header
 805        }"},
 806        vec![indoc! {"
 807        for «(»const a in b«)» {
 808            // a comment that's longer than the for-loop header
 809        }"}],
 810    );
 811
 812    eprintln!("-----------------------");
 813    // Regression test: even though the parent node of the parentheses (the for loop) does
 814    // intersect the given range, the parentheses themselves do not contain the range, so
 815    // they should not be returned. Only the curly braces contain the range.
 816    assert(
 817        indoc! {"
 818        for (const a in b) {ˇ
 819            // a comment that's longer than the for-loop header
 820        }"},
 821        vec![indoc! {"
 822        for (const a in b) «{»
 823            // a comment that's longer than the for-loop header
 824        «}»"}],
 825    );
 826}
 827
 828#[gpui::test]
 829fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 830    cx.add_model(|cx| {
 831        let text = "fn a() { b(|c| {}) }";
 832        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 833        let snapshot = buffer.snapshot();
 834
 835        assert_eq!(
 836            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 837            Some(range_of(text, "|"))
 838        );
 839        assert_eq!(
 840            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 841            Some(range_of(text, "|c|"))
 842        );
 843        assert_eq!(
 844            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 845            Some(range_of(text, "|c| {}"))
 846        );
 847        assert_eq!(
 848            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 849            Some(range_of(text, "(|c| {})"))
 850        );
 851
 852        buffer
 853    });
 854
 855    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 856        let start = text.find(part).unwrap();
 857        start..start
 858    }
 859
 860    fn range_of(text: &str, part: &str) -> Range<usize> {
 861        let start = text.find(part).unwrap();
 862        start..start + part.len()
 863    }
 864}
 865
 866#[gpui::test]
 867fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 868    let settings = Settings::test(cx);
 869    cx.set_global(settings);
 870
 871    cx.add_model(|cx| {
 872        let text = "fn a() {}";
 873        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 874
 875        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 876        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 877
 878        buffer.edit(
 879            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 880            Some(AutoindentMode::EachLine),
 881            cx,
 882        );
 883        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 884
 885        // Create a field expression on a new line, causing that line
 886        // to be indented.
 887        buffer.edit(
 888            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 889            Some(AutoindentMode::EachLine),
 890            cx,
 891        );
 892        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 893
 894        // Remove the dot so that the line is no longer a field expression,
 895        // causing the line to be outdented.
 896        buffer.edit(
 897            [(Point::new(2, 8)..Point::new(2, 9), "")],
 898            Some(AutoindentMode::EachLine),
 899            cx,
 900        );
 901        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 902
 903        buffer
 904    });
 905}
 906
 907#[gpui::test]
 908fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 909    let mut settings = Settings::test(cx);
 910    settings.editor_overrides.hard_tabs = Some(true);
 911    cx.set_global(settings);
 912
 913    cx.add_model(|cx| {
 914        let text = "fn a() {}";
 915        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 916
 917        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 918        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 919
 920        buffer.edit(
 921            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 922            Some(AutoindentMode::EachLine),
 923            cx,
 924        );
 925        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 926
 927        // Create a field expression on a new line, causing that line
 928        // to be indented.
 929        buffer.edit(
 930            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 931            Some(AutoindentMode::EachLine),
 932            cx,
 933        );
 934        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 935
 936        // Remove the dot so that the line is no longer a field expression,
 937        // causing the line to be outdented.
 938        buffer.edit(
 939            [(Point::new(2, 2)..Point::new(2, 3), "")],
 940            Some(AutoindentMode::EachLine),
 941            cx,
 942        );
 943        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 944
 945        buffer
 946    });
 947}
 948
 949#[gpui::test]
 950fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 951    let settings = Settings::test(cx);
 952    cx.set_global(settings);
 953
 954    cx.add_model(|cx| {
 955        let mut buffer = Buffer::new(
 956            0,
 957            "
 958            fn a() {
 959            c;
 960            d;
 961            }
 962            "
 963            .unindent(),
 964            cx,
 965        )
 966        .with_language(Arc::new(rust_lang()), cx);
 967
 968        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 969        // their indentation is not adjusted.
 970        buffer.edit_via_marked_text(
 971            &"
 972            fn a() {
 973            c«()»;
 974            d«()»;
 975            }
 976            "
 977            .unindent(),
 978            Some(AutoindentMode::EachLine),
 979            cx,
 980        );
 981        assert_eq!(
 982            buffer.text(),
 983            "
 984            fn a() {
 985            c();
 986            d();
 987            }
 988            "
 989            .unindent()
 990        );
 991
 992        // When appending new content after these lines, the indentation is based on the
 993        // preceding lines' actual indentation.
 994        buffer.edit_via_marked_text(
 995            &"
 996            fn a() {
 997 998            .f
 999            .g()»;
10001001            .f
1002            .g()»;
1003            }
1004            "
1005            .unindent(),
1006            Some(AutoindentMode::EachLine),
1007            cx,
1008        );
1009
1010        assert_eq!(
1011            buffer.text(),
1012            "
1013            fn a() {
1014            c
1015                .f
1016                .g();
1017            d
1018                .f
1019                .g();
1020            }
1021            "
1022            .unindent()
1023        );
1024        buffer
1025    });
1026
1027    cx.add_model(|cx| {
1028        let mut buffer = Buffer::new(
1029            0,
1030            "
1031            fn a() {
1032                b();
1033                |
1034            "
1035            .replace("|", "") // marker to preserve trailing whitespace
1036            .unindent(),
1037            cx,
1038        )
1039        .with_language(Arc::new(rust_lang()), cx);
1040
1041        // Insert a closing brace. It is outdented.
1042        buffer.edit_via_marked_text(
1043            &"
1044            fn a() {
1045                b();
1046                «}»
1047            "
1048            .unindent(),
1049            Some(AutoindentMode::EachLine),
1050            cx,
1051        );
1052        assert_eq!(
1053            buffer.text(),
1054            "
1055            fn a() {
1056                b();
1057            }
1058            "
1059            .unindent()
1060        );
1061
1062        // Manually edit the leading whitespace. The edit is preserved.
1063        buffer.edit_via_marked_text(
1064            &"
1065            fn a() {
1066                b();
1067            «    »}
1068            "
1069            .unindent(),
1070            Some(AutoindentMode::EachLine),
1071            cx,
1072        );
1073        assert_eq!(
1074            buffer.text(),
1075            "
1076            fn a() {
1077                b();
1078                }
1079            "
1080            .unindent()
1081        );
1082        buffer
1083    });
1084}
1085
1086#[gpui::test]
1087fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut MutableAppContext) {
1088    let settings = Settings::test(cx);
1089    cx.set_global(settings);
1090
1091    cx.add_model(|cx| {
1092        let mut buffer = Buffer::new(
1093            0,
1094            "
1095            fn a() {
1096                i
1097            }
1098            "
1099            .unindent(),
1100            cx,
1101        )
1102        .with_language(Arc::new(rust_lang()), cx);
1103
1104        // Regression test: line does not get outdented due to syntax error
1105        buffer.edit_via_marked_text(
1106            &"
1107            fn a() {
1108                i«f let Some(x) = y»
1109            }
1110            "
1111            .unindent(),
1112            Some(AutoindentMode::EachLine),
1113            cx,
1114        );
1115        assert_eq!(
1116            buffer.text(),
1117            "
1118            fn a() {
1119                if let Some(x) = y
1120            }
1121            "
1122            .unindent()
1123        );
1124
1125        buffer.edit_via_marked_text(
1126            &"
1127            fn a() {
1128                if let Some(x) = y« {»
1129            }
1130            "
1131            .unindent(),
1132            Some(AutoindentMode::EachLine),
1133            cx,
1134        );
1135        assert_eq!(
1136            buffer.text(),
1137            "
1138            fn a() {
1139                if let Some(x) = y {
1140            }
1141            "
1142            .unindent()
1143        );
1144
1145        buffer
1146    });
1147}
1148
1149#[gpui::test]
1150fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
1151    cx.set_global(Settings::test(cx));
1152    cx.add_model(|cx| {
1153        let mut buffer = Buffer::new(
1154            0,
1155            "
1156            fn a() {}
1157            "
1158            .unindent(),
1159            cx,
1160        )
1161        .with_language(Arc::new(rust_lang()), cx);
1162
1163        buffer.edit_via_marked_text(
1164            &"
1165            fn a(«
1166            b») {}
1167            "
1168            .unindent(),
1169            Some(AutoindentMode::EachLine),
1170            cx,
1171        );
1172        assert_eq!(
1173            buffer.text(),
1174            "
1175            fn a(
1176                b) {}
1177            "
1178            .unindent()
1179        );
1180
1181        // The indentation suggestion changed because `@end` node (a close paren)
1182        // is now at the beginning of the line.
1183        buffer.edit_via_marked_text(
1184            &"
1185            fn a(
1186                ˇ) {}
1187            "
1188            .unindent(),
1189            Some(AutoindentMode::EachLine),
1190            cx,
1191        );
1192        assert_eq!(
1193            buffer.text(),
1194            "
1195                fn a(
1196                ) {}
1197            "
1198            .unindent()
1199        );
1200
1201        buffer
1202    });
1203}
1204
1205#[gpui::test]
1206fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
1207    cx.set_global(Settings::test(cx));
1208    cx.add_model(|cx| {
1209        let text = "a\nb";
1210        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1211        buffer.edit(
1212            [(0..1, "\n"), (2..3, "\n")],
1213            Some(AutoindentMode::EachLine),
1214            cx,
1215        );
1216        assert_eq!(buffer.text(), "\n\n\n");
1217        buffer
1218    });
1219}
1220
1221#[gpui::test]
1222fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
1223    cx.set_global(Settings::test(cx));
1224    cx.add_model(|cx| {
1225        let text = "
1226            const a: usize = 1;
1227            fn b() {
1228                if c {
1229                    let d = 2;
1230                }
1231            }
1232        "
1233        .unindent();
1234
1235        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1236        buffer.edit(
1237            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1238            Some(AutoindentMode::EachLine),
1239            cx,
1240        );
1241        assert_eq!(
1242            buffer.text(),
1243            "
1244                const a: usize = 1;
1245                fn b() {
1246                    if c {
1247                        e(
1248                            f()
1249                        );
1250                        let d = 2;
1251                    }
1252                }
1253            "
1254            .unindent()
1255        );
1256
1257        buffer
1258    });
1259}
1260
1261#[gpui::test]
1262fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
1263    cx.set_global(Settings::test(cx));
1264    cx.add_model(|cx| {
1265        let text = r#"
1266            fn a() {
1267                b();
1268            }
1269        "#
1270        .unindent();
1271        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1272
1273        // When this text was copied, both of the quotation marks were at the same
1274        // indent level, but the indentation of the first line was not included in
1275        // the copied text. This information is retained in the
1276        // 'original_indent_columns' vector.
1277        let original_indent_columns = vec![4];
1278        let inserted_text = r#"
1279            "
1280                  c
1281                    d
1282                      e
1283                "
1284        "#
1285        .unindent();
1286
1287        // Insert the block at column zero. The entire block is indented
1288        // so that the first line matches the previous line's indentation.
1289        buffer.edit(
1290            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1291            Some(AutoindentMode::Block {
1292                original_indent_columns: original_indent_columns.clone(),
1293            }),
1294            cx,
1295        );
1296        assert_eq!(
1297            buffer.text(),
1298            r#"
1299            fn a() {
1300                b();
1301                "
1302                  c
1303                    d
1304                      e
1305                "
1306            }
1307            "#
1308            .unindent()
1309        );
1310
1311        // Grouping is disabled in tests, so we need 2 undos
1312        buffer.undo(cx); // Undo the auto-indent
1313        buffer.undo(cx); // Undo the original edit
1314
1315        // Insert the block at a deeper indent level. The entire block is outdented.
1316        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1317        buffer.edit(
1318            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1319            Some(AutoindentMode::Block {
1320                original_indent_columns: original_indent_columns.clone(),
1321            }),
1322            cx,
1323        );
1324        assert_eq!(
1325            buffer.text(),
1326            r#"
1327            fn a() {
1328                b();
1329                "
1330                  c
1331                    d
1332                      e
1333                "
1334            }
1335            "#
1336            .unindent()
1337        );
1338
1339        buffer
1340    });
1341}
1342
1343#[gpui::test]
1344fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut MutableAppContext) {
1345    cx.set_global(Settings::test(cx));
1346    cx.add_model(|cx| {
1347        let text = r#"
1348            fn a() {
1349                if b() {
1350
1351                }
1352            }
1353        "#
1354        .unindent();
1355        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
1356
1357        // The original indent columns are not known, so this text is
1358        // auto-indented in a block as if the first line was copied in
1359        // its entirety.
1360        let original_indent_columns = Vec::new();
1361        let inserted_text = "    c\n        .d()\n        .e();";
1362
1363        // Insert the block at column zero. The entire block is indented
1364        // so that the first line matches the previous line's indentation.
1365        buffer.edit(
1366            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1367            Some(AutoindentMode::Block {
1368                original_indent_columns: original_indent_columns.clone(),
1369            }),
1370            cx,
1371        );
1372        assert_eq!(
1373            buffer.text(),
1374            r#"
1375            fn a() {
1376                if b() {
1377                    c
1378                        .d()
1379                        .e();
1380                }
1381            }
1382            "#
1383            .unindent()
1384        );
1385
1386        // Grouping is disabled in tests, so we need 2 undos
1387        buffer.undo(cx); // Undo the auto-indent
1388        buffer.undo(cx); // Undo the original edit
1389
1390        // Insert the block at a deeper indent level. The entire block is outdented.
1391        buffer.edit(
1392            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1393            None,
1394            cx,
1395        );
1396        buffer.edit(
1397            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1398            Some(AutoindentMode::Block {
1399                original_indent_columns: Vec::new(),
1400            }),
1401            cx,
1402        );
1403        assert_eq!(
1404            buffer.text(),
1405            r#"
1406            fn a() {
1407                if b() {
1408                    c
1409                        .d()
1410                        .e();
1411                }
1412            }
1413            "#
1414            .unindent()
1415        );
1416
1417        buffer
1418    });
1419}
1420
1421#[gpui::test]
1422fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
1423    cx.set_global(Settings::test(cx));
1424    cx.add_model(|cx| {
1425        let text = "
1426            * one
1427                - a
1428                - b
1429            * two
1430        "
1431        .unindent();
1432
1433        let mut buffer = Buffer::new(0, text, cx).with_language(
1434            Arc::new(Language::new(
1435                LanguageConfig {
1436                    name: "Markdown".into(),
1437                    auto_indent_using_last_non_empty_line: false,
1438                    ..Default::default()
1439                },
1440                Some(tree_sitter_json::language()),
1441            )),
1442            cx,
1443        );
1444        buffer.edit(
1445            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1446            Some(AutoindentMode::EachLine),
1447            cx,
1448        );
1449        assert_eq!(
1450            buffer.text(),
1451            "
1452            * one
1453                - a
1454                - b
1455
1456            * two
1457            "
1458            .unindent()
1459        );
1460        buffer
1461    });
1462}
1463
1464#[gpui::test]
1465fn test_autoindent_with_injected_languages(cx: &mut MutableAppContext) {
1466    cx.set_global({
1467        let mut settings = Settings::test(cx);
1468        settings.language_overrides.extend([
1469            (
1470                "HTML".into(),
1471                settings::EditorSettings {
1472                    tab_size: Some(2.try_into().unwrap()),
1473                    ..Default::default()
1474                },
1475            ),
1476            (
1477                "JavaScript".into(),
1478                settings::EditorSettings {
1479                    tab_size: Some(8.try_into().unwrap()),
1480                    ..Default::default()
1481                },
1482            ),
1483        ]);
1484        settings
1485    });
1486
1487    let html_language = Arc::new(
1488        Language::new(
1489            LanguageConfig {
1490                name: "HTML".into(),
1491                ..Default::default()
1492            },
1493            Some(tree_sitter_html::language()),
1494        )
1495        .with_indents_query(
1496            "
1497            (element
1498              (start_tag) @start
1499              (end_tag)? @end) @indent
1500            ",
1501        )
1502        .unwrap()
1503        .with_injection_query(
1504            r#"
1505            (script_element
1506                (raw_text) @content
1507                (#set! "language" "javascript"))
1508            "#,
1509        )
1510        .unwrap(),
1511    );
1512
1513    let javascript_language = Arc::new(
1514        Language::new(
1515            LanguageConfig {
1516                name: "JavaScript".into(),
1517                ..Default::default()
1518            },
1519            Some(tree_sitter_javascript::language()),
1520        )
1521        .with_indents_query(
1522            r#"
1523            (object "}" @end) @indent
1524            "#,
1525        )
1526        .unwrap(),
1527    );
1528
1529    let language_registry = Arc::new(LanguageRegistry::test());
1530    language_registry.add(html_language.clone());
1531    language_registry.add(javascript_language.clone());
1532
1533    cx.add_model(|cx| {
1534        let (text, ranges) = marked_text_ranges(
1535            &"
1536                <div>ˇ
1537                </div>
1538                <script>
1539                    init({ˇ
1540                    })
1541                </script>
1542                <span>ˇ
1543                </span>
1544            "
1545            .unindent(),
1546            false,
1547        );
1548
1549        let mut buffer = Buffer::new(0, text, cx);
1550        buffer.set_language_registry(language_registry);
1551        buffer.set_language(Some(html_language), cx);
1552        buffer.edit(
1553            ranges.into_iter().map(|range| (range, "\na")),
1554            Some(AutoindentMode::EachLine),
1555            cx,
1556        );
1557        assert_eq!(
1558            buffer.text(),
1559            "
1560                <div>
1561                  a
1562                </div>
1563                <script>
1564                    init({
1565                            a
1566                    })
1567                </script>
1568                <span>
1569                  a
1570                </span>
1571            "
1572            .unindent()
1573        );
1574        buffer
1575    });
1576}
1577
1578#[gpui::test]
1579fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
1580    let mut settings = Settings::test(cx);
1581    settings.editor_defaults.tab_size = Some(2.try_into().unwrap());
1582    cx.set_global(settings);
1583    cx.add_model(|cx| {
1584        let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(ruby_lang()), cx);
1585
1586        let text = r#"
1587            class C
1588            def a(b, c)
1589            puts b
1590            puts c
1591            rescue
1592            puts "errored"
1593            exit 1
1594            end
1595            end
1596        "#
1597        .unindent();
1598
1599        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1600
1601        assert_eq!(
1602            buffer.text(),
1603            r#"
1604                class C
1605                  def a(b, c)
1606                    puts b
1607                    puts c
1608                  rescue
1609                    puts "errored"
1610                    exit 1
1611                  end
1612                end
1613            "#
1614            .unindent()
1615        );
1616
1617        buffer
1618    });
1619}
1620
1621#[gpui::test]
1622fn test_language_config_at(cx: &mut MutableAppContext) {
1623    cx.set_global(Settings::test(cx));
1624    cx.add_model(|cx| {
1625        let language = Language::new(
1626            LanguageConfig {
1627                name: "JavaScript".into(),
1628                line_comment: Some("// ".into()),
1629                brackets: BracketPairConfig {
1630                    pairs: vec![
1631                        BracketPair {
1632                            start: "{".into(),
1633                            end: "}".into(),
1634                            close: true,
1635                            newline: false,
1636                        },
1637                        BracketPair {
1638                            start: "'".into(),
1639                            end: "'".into(),
1640                            close: true,
1641                            newline: false,
1642                        },
1643                    ],
1644                    disabled_scopes_by_bracket_ix: vec![
1645                        Vec::new(), //
1646                        vec!["string".into()],
1647                    ],
1648                },
1649                overrides: [(
1650                    "element".into(),
1651                    LanguageConfigOverride {
1652                        line_comment: Override::Remove { remove: true },
1653                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1654                        ..Default::default()
1655                    },
1656                )]
1657                .into_iter()
1658                .collect(),
1659                ..Default::default()
1660            },
1661            Some(tree_sitter_javascript::language()),
1662        )
1663        .with_override_query(
1664            r#"
1665                (jsx_element) @element
1666                (string) @string
1667            "#,
1668        )
1669        .unwrap();
1670
1671        let text = r#"a["b"] = <C d="e"></C>;"#;
1672
1673        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
1674        let snapshot = buffer.snapshot();
1675
1676        let config = snapshot.language_scope_at(0).unwrap();
1677        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1678        // Both bracket pairs are enabled
1679        assert_eq!(
1680            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1681            &[true, true]
1682        );
1683
1684        let string_config = snapshot.language_scope_at(3).unwrap();
1685        assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
1686        // Second bracket pair is disabled
1687        assert_eq!(
1688            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1689            &[true, false]
1690        );
1691
1692        let element_config = snapshot.language_scope_at(10).unwrap();
1693        assert_eq!(element_config.line_comment_prefix(), None);
1694        assert_eq!(
1695            element_config.block_comment_delimiters(),
1696            Some((&"{/*".into(), &"*/}".into()))
1697        );
1698        // Both bracket pairs are enabled
1699        assert_eq!(
1700            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1701            &[true, true]
1702        );
1703
1704        buffer
1705    });
1706}
1707
1708#[gpui::test]
1709fn test_serialization(cx: &mut gpui::MutableAppContext) {
1710    let mut now = Instant::now();
1711
1712    let buffer1 = cx.add_model(|cx| {
1713        let mut buffer = Buffer::new(0, "abc", cx);
1714        buffer.edit([(3..3, "D")], None, cx);
1715
1716        now += Duration::from_secs(1);
1717        buffer.start_transaction_at(now);
1718        buffer.edit([(4..4, "E")], None, cx);
1719        buffer.end_transaction_at(now, cx);
1720        assert_eq!(buffer.text(), "abcDE");
1721
1722        buffer.undo(cx);
1723        assert_eq!(buffer.text(), "abcD");
1724
1725        buffer.edit([(4..4, "F")], None, cx);
1726        assert_eq!(buffer.text(), "abcDF");
1727        buffer
1728    });
1729    assert_eq!(buffer1.read(cx).text(), "abcDF");
1730
1731    let state = buffer1.read(cx).to_proto();
1732    let ops = cx
1733        .background()
1734        .block(buffer1.read(cx).serialize_ops(None, cx));
1735    let buffer2 = cx.add_model(|cx| {
1736        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1737        buffer
1738            .apply_ops(
1739                ops.into_iter()
1740                    .map(|op| proto::deserialize_operation(op).unwrap()),
1741                cx,
1742            )
1743            .unwrap();
1744        buffer
1745    });
1746    assert_eq!(buffer2.read(cx).text(), "abcDF");
1747}
1748
1749#[gpui::test(iterations = 100)]
1750fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1751    let min_peers = env::var("MIN_PEERS")
1752        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1753        .unwrap_or(1);
1754    let max_peers = env::var("MAX_PEERS")
1755        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1756        .unwrap_or(5);
1757    let operations = env::var("OPERATIONS")
1758        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1759        .unwrap_or(10);
1760
1761    let base_text_len = rng.gen_range(0..10);
1762    let base_text = RandomCharIter::new(&mut rng)
1763        .take(base_text_len)
1764        .collect::<String>();
1765    let mut replica_ids = Vec::new();
1766    let mut buffers = Vec::new();
1767    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1768    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1769
1770    for i in 0..rng.gen_range(min_peers..=max_peers) {
1771        let buffer = cx.add_model(|cx| {
1772            let state = base_buffer.read(cx).to_proto();
1773            let ops = cx
1774                .background()
1775                .block(base_buffer.read(cx).serialize_ops(None, cx));
1776            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1777            buffer
1778                .apply_ops(
1779                    ops.into_iter()
1780                        .map(|op| proto::deserialize_operation(op).unwrap()),
1781                    cx,
1782                )
1783                .unwrap();
1784            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1785            let network = network.clone();
1786            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1787                if let Event::Operation(op) = event {
1788                    network
1789                        .borrow_mut()
1790                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1791                }
1792            })
1793            .detach();
1794            buffer
1795        });
1796        buffers.push(buffer);
1797        replica_ids.push(i as ReplicaId);
1798        network.borrow_mut().add_peer(i as ReplicaId);
1799        log::info!("Adding initial peer with replica id {}", i);
1800    }
1801
1802    log::info!("initial text: {:?}", base_text);
1803
1804    let mut now = Instant::now();
1805    let mut mutation_count = operations;
1806    let mut next_diagnostic_id = 0;
1807    let mut active_selections = BTreeMap::default();
1808    loop {
1809        let replica_index = rng.gen_range(0..replica_ids.len());
1810        let replica_id = replica_ids[replica_index];
1811        let buffer = &mut buffers[replica_index];
1812        let mut new_buffer = None;
1813        match rng.gen_range(0..100) {
1814            0..=29 if mutation_count != 0 => {
1815                buffer.update(cx, |buffer, cx| {
1816                    buffer.start_transaction_at(now);
1817                    buffer.randomly_edit(&mut rng, 5, cx);
1818                    buffer.end_transaction_at(now, cx);
1819                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1820                });
1821                mutation_count -= 1;
1822            }
1823            30..=39 if mutation_count != 0 => {
1824                buffer.update(cx, |buffer, cx| {
1825                    if rng.gen_bool(0.2) {
1826                        log::info!("peer {} clearing active selections", replica_id);
1827                        active_selections.remove(&replica_id);
1828                        buffer.remove_active_selections(cx);
1829                    } else {
1830                        let mut selections = Vec::new();
1831                        for id in 0..rng.gen_range(1..=5) {
1832                            let range = buffer.random_byte_range(0, &mut rng);
1833                            selections.push(Selection {
1834                                id,
1835                                start: buffer.anchor_before(range.start),
1836                                end: buffer.anchor_before(range.end),
1837                                reversed: false,
1838                                goal: SelectionGoal::None,
1839                            });
1840                        }
1841                        let selections: Arc<[Selection<Anchor>]> = selections.into();
1842                        log::info!(
1843                            "peer {} setting active selections: {:?}",
1844                            replica_id,
1845                            selections
1846                        );
1847                        active_selections.insert(replica_id, selections.clone());
1848                        buffer.set_active_selections(selections, false, Default::default(), cx);
1849                    }
1850                });
1851                mutation_count -= 1;
1852            }
1853            40..=49 if mutation_count != 0 && replica_id == 0 => {
1854                let entry_count = rng.gen_range(1..=5);
1855                buffer.update(cx, |buffer, cx| {
1856                    let diagnostics = DiagnosticSet::new(
1857                        (0..entry_count).map(|_| {
1858                            let range = buffer.random_byte_range(0, &mut rng);
1859                            let range = range.to_point_utf16(buffer);
1860                            let range = range.start..range.end;
1861                            DiagnosticEntry {
1862                                range,
1863                                diagnostic: Diagnostic {
1864                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1865                                    ..Default::default()
1866                                },
1867                            }
1868                        }),
1869                        buffer,
1870                    );
1871                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1872                    buffer.update_diagnostics(diagnostics, cx);
1873                });
1874                mutation_count -= 1;
1875            }
1876            50..=59 if replica_ids.len() < max_peers => {
1877                let old_buffer_state = buffer.read(cx).to_proto();
1878                let old_buffer_ops = cx
1879                    .background()
1880                    .block(buffer.read(cx).serialize_ops(None, cx));
1881                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1882                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1883                    .choose(&mut rng)
1884                    .unwrap();
1885                log::info!(
1886                    "Adding new replica {} (replicating from {})",
1887                    new_replica_id,
1888                    replica_id
1889                );
1890                new_buffer = Some(cx.add_model(|cx| {
1891                    let mut new_buffer =
1892                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1893                    new_buffer
1894                        .apply_ops(
1895                            old_buffer_ops
1896                                .into_iter()
1897                                .map(|op| deserialize_operation(op).unwrap()),
1898                            cx,
1899                        )
1900                        .unwrap();
1901                    log::info!(
1902                        "New replica {} text: {:?}",
1903                        new_buffer.replica_id(),
1904                        new_buffer.text()
1905                    );
1906                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1907                    let network = network.clone();
1908                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1909                        if let Event::Operation(op) = event {
1910                            network.borrow_mut().broadcast(
1911                                buffer.replica_id(),
1912                                vec![proto::serialize_operation(op)],
1913                            );
1914                        }
1915                    })
1916                    .detach();
1917                    new_buffer
1918                }));
1919                network.borrow_mut().replicate(replica_id, new_replica_id);
1920
1921                if new_replica_id as usize == replica_ids.len() {
1922                    replica_ids.push(new_replica_id);
1923                } else {
1924                    let new_buffer = new_buffer.take().unwrap();
1925                    while network.borrow().has_unreceived(new_replica_id) {
1926                        let ops = network
1927                            .borrow_mut()
1928                            .receive(new_replica_id)
1929                            .into_iter()
1930                            .map(|op| proto::deserialize_operation(op).unwrap());
1931                        if ops.len() > 0 {
1932                            log::info!(
1933                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1934                                new_replica_id,
1935                                buffer.read(cx).version(),
1936                                ops.len(),
1937                                ops
1938                            );
1939                            new_buffer.update(cx, |new_buffer, cx| {
1940                                new_buffer.apply_ops(ops, cx).unwrap();
1941                            });
1942                        }
1943                    }
1944                    buffers[new_replica_id as usize] = new_buffer;
1945                }
1946            }
1947            60..=69 if mutation_count != 0 => {
1948                buffer.update(cx, |buffer, cx| {
1949                    buffer.randomly_undo_redo(&mut rng, cx);
1950                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1951                });
1952                mutation_count -= 1;
1953            }
1954            _ if network.borrow().has_unreceived(replica_id) => {
1955                let ops = network
1956                    .borrow_mut()
1957                    .receive(replica_id)
1958                    .into_iter()
1959                    .map(|op| proto::deserialize_operation(op).unwrap());
1960                if ops.len() > 0 {
1961                    log::info!(
1962                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1963                        replica_id,
1964                        buffer.read(cx).version(),
1965                        ops.len(),
1966                        ops
1967                    );
1968                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1969                }
1970            }
1971            _ => {}
1972        }
1973
1974        now += Duration::from_millis(rng.gen_range(0..=200));
1975        buffers.extend(new_buffer);
1976
1977        for buffer in &buffers {
1978            buffer.read(cx).check_invariants();
1979        }
1980
1981        if mutation_count == 0 && network.borrow().is_idle() {
1982            break;
1983        }
1984    }
1985
1986    let first_buffer = buffers[0].read(cx).snapshot();
1987    for buffer in &buffers[1..] {
1988        let buffer = buffer.read(cx).snapshot();
1989        assert_eq!(
1990            buffer.version(),
1991            first_buffer.version(),
1992            "Replica {} version != Replica 0 version",
1993            buffer.replica_id()
1994        );
1995        assert_eq!(
1996            buffer.text(),
1997            first_buffer.text(),
1998            "Replica {} text != Replica 0 text",
1999            buffer.replica_id()
2000        );
2001        assert_eq!(
2002            buffer
2003                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2004                .collect::<Vec<_>>(),
2005            first_buffer
2006                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2007                .collect::<Vec<_>>(),
2008            "Replica {} diagnostics != Replica 0 diagnostics",
2009            buffer.replica_id()
2010        );
2011    }
2012
2013    for buffer in &buffers {
2014        let buffer = buffer.read(cx).snapshot();
2015        let actual_remote_selections = buffer
2016            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2017            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2018            .collect::<Vec<_>>();
2019        let expected_remote_selections = active_selections
2020            .iter()
2021            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2022            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2023            .collect::<Vec<_>>();
2024        assert_eq!(
2025            actual_remote_selections,
2026            expected_remote_selections,
2027            "Replica {} remote selections != expected selections",
2028            buffer.replica_id()
2029        );
2030    }
2031}
2032
2033#[test]
2034fn test_contiguous_ranges() {
2035    assert_eq!(
2036        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2037        &[1..4, 5..7, 9..13]
2038    );
2039
2040    // Respects the `max_len` parameter
2041    assert_eq!(
2042        contiguous_ranges(
2043            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2044            3
2045        )
2046        .collect::<Vec<_>>(),
2047        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2048    );
2049}
2050
2051#[gpui::test(iterations = 500)]
2052fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2053    // Generate a random multi-line string containing
2054    // some lines with trailing whitespace.
2055    let mut text = String::new();
2056    for _ in 0..rng.gen_range(0..16) {
2057        for _ in 0..rng.gen_range(0..36) {
2058            text.push(match rng.gen_range(0..10) {
2059                0..=1 => ' ',
2060                3 => '\t',
2061                _ => rng.gen_range('a'..'z'),
2062            });
2063        }
2064        text.push('\n');
2065    }
2066
2067    match rng.gen_range(0..10) {
2068        // sometimes remove the last newline
2069        0..=1 => drop(text.pop()), //
2070
2071        // sometimes add extra newlines
2072        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2073        _ => {}
2074    }
2075
2076    let rope = Rope::from(text.as_str());
2077    let actual_ranges = trailing_whitespace_ranges(&rope);
2078    let expected_ranges = TRAILING_WHITESPACE_REGEX
2079        .find_iter(&text)
2080        .map(|m| m.range())
2081        .collect::<Vec<_>>();
2082    assert_eq!(
2083        actual_ranges,
2084        expected_ranges,
2085        "wrong ranges for text lines:\n{:?}",
2086        text.split("\n").collect::<Vec<_>>()
2087    );
2088}
2089
2090fn ruby_lang() -> Language {
2091    Language::new(
2092        LanguageConfig {
2093            name: "Ruby".into(),
2094            path_suffixes: vec!["rb".to_string()],
2095            ..Default::default()
2096        },
2097        Some(tree_sitter_ruby::language()),
2098    )
2099    .with_indents_query(
2100        r#"
2101            (class "end" @end) @indent
2102            (method "end" @end) @indent
2103            (rescue) @outdent
2104            (then) @indent
2105        "#,
2106    )
2107    .unwrap()
2108}
2109
2110fn rust_lang() -> Language {
2111    Language::new(
2112        LanguageConfig {
2113            name: "Rust".into(),
2114            path_suffixes: vec!["rs".to_string()],
2115            ..Default::default()
2116        },
2117        Some(tree_sitter_rust::language()),
2118    )
2119    .with_indents_query(
2120        r#"
2121        (call_expression) @indent
2122        (field_expression) @indent
2123        (_ "(" ")" @end) @indent
2124        (_ "{" "}" @end) @indent
2125        "#,
2126    )
2127    .unwrap()
2128    .with_brackets_query(
2129        r#"
2130        ("{" @open "}" @close)
2131        "#,
2132    )
2133    .unwrap()
2134    .with_outline_query(
2135        r#"
2136        (struct_item
2137            "struct" @context
2138            name: (_) @name) @item
2139        (enum_item
2140            "enum" @context
2141            name: (_) @name) @item
2142        (enum_variant
2143            name: (_) @name) @item
2144        (field_declaration
2145            name: (_) @name) @item
2146        (impl_item
2147            "impl" @context
2148            trait: (_)? @name
2149            "for"? @context
2150            type: (_) @name) @item
2151        (function_item
2152            "fn" @context
2153            name: (_) @name) @item
2154        (mod_item
2155            "mod" @context
2156            name: (_) @name) @item
2157        "#,
2158    )
2159    .unwrap()
2160}
2161
2162fn json_lang() -> Language {
2163    Language::new(
2164        LanguageConfig {
2165            name: "Json".into(),
2166            path_suffixes: vec!["js".to_string()],
2167            ..Default::default()
2168        },
2169        Some(tree_sitter_json::language()),
2170    )
2171}
2172
2173fn javascript_lang() -> Language {
2174    Language::new(
2175        LanguageConfig {
2176            name: "JavaScript".into(),
2177            ..Default::default()
2178        },
2179        Some(tree_sitter_javascript::language()),
2180    )
2181    .with_brackets_query(
2182        r#"
2183        ("{" @open "}" @close)
2184        ("(" @open ")" @close)
2185        "#,
2186    )
2187    .unwrap()
2188}
2189
2190fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2191    buffer.read_with(cx, |buffer, _| {
2192        let snapshot = buffer.snapshot();
2193        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2194        layers[0].node.to_sexp()
2195    })
2196}
2197
2198// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2199fn assert_bracket_pairs(
2200    selection_text: &'static str,
2201    bracket_pair_texts: Vec<&'static str>,
2202    language: Language,
2203    cx: &mut MutableAppContext,
2204) {
2205    cx.set_global(Settings::test(cx));
2206    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2207    let buffer = cx.add_model(|cx| {
2208        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
2209    });
2210    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2211
2212    let selection_range = selection_ranges[0].clone();
2213
2214    let bracket_pairs = bracket_pair_texts
2215        .into_iter()
2216        .map(|pair_text| {
2217            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2218            assert_eq!(bracket_text, expected_text);
2219            (ranges[0].clone(), ranges[1].clone())
2220        })
2221        .collect::<Vec<_>>();
2222
2223    assert_set_eq!(
2224        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2225        bracket_pairs
2226    );
2227}