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                    let mut selections = Vec::new();
1826                    for id in 0..rng.gen_range(1..=5) {
1827                        let range = buffer.random_byte_range(0, &mut rng);
1828                        selections.push(Selection {
1829                            id,
1830                            start: buffer.anchor_before(range.start),
1831                            end: buffer.anchor_before(range.end),
1832                            reversed: false,
1833                            goal: SelectionGoal::None,
1834                        });
1835                    }
1836                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1837                    log::info!(
1838                        "peer {} setting active selections: {:?}",
1839                        replica_id,
1840                        selections
1841                    );
1842                    active_selections.insert(replica_id, selections.clone());
1843                    buffer.set_active_selections(selections, false, Default::default(), cx);
1844                });
1845                mutation_count -= 1;
1846            }
1847            40..=49 if mutation_count != 0 && replica_id == 0 => {
1848                let entry_count = rng.gen_range(1..=5);
1849                buffer.update(cx, |buffer, cx| {
1850                    let diagnostics = DiagnosticSet::new(
1851                        (0..entry_count).map(|_| {
1852                            let range = buffer.random_byte_range(0, &mut rng);
1853                            let range = range.to_point_utf16(buffer);
1854                            let range = range.start..range.end;
1855                            DiagnosticEntry {
1856                                range,
1857                                diagnostic: Diagnostic {
1858                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1859                                    ..Default::default()
1860                                },
1861                            }
1862                        }),
1863                        buffer,
1864                    );
1865                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1866                    buffer.update_diagnostics(diagnostics, cx);
1867                });
1868                mutation_count -= 1;
1869            }
1870            50..=59 if replica_ids.len() < max_peers => {
1871                let old_buffer_state = buffer.read(cx).to_proto();
1872                let old_buffer_ops = cx
1873                    .background()
1874                    .block(buffer.read(cx).serialize_ops(None, cx));
1875                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1876                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1877                    .choose(&mut rng)
1878                    .unwrap();
1879                log::info!(
1880                    "Adding new replica {} (replicating from {})",
1881                    new_replica_id,
1882                    replica_id
1883                );
1884                new_buffer = Some(cx.add_model(|cx| {
1885                    let mut new_buffer =
1886                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1887                    new_buffer
1888                        .apply_ops(
1889                            old_buffer_ops
1890                                .into_iter()
1891                                .map(|op| deserialize_operation(op).unwrap()),
1892                            cx,
1893                        )
1894                        .unwrap();
1895                    log::info!(
1896                        "New replica {} text: {:?}",
1897                        new_buffer.replica_id(),
1898                        new_buffer.text()
1899                    );
1900                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1901                    let network = network.clone();
1902                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1903                        if let Event::Operation(op) = event {
1904                            network.borrow_mut().broadcast(
1905                                buffer.replica_id(),
1906                                vec![proto::serialize_operation(op)],
1907                            );
1908                        }
1909                    })
1910                    .detach();
1911                    new_buffer
1912                }));
1913                network.borrow_mut().replicate(replica_id, new_replica_id);
1914
1915                if new_replica_id as usize == replica_ids.len() {
1916                    replica_ids.push(new_replica_id);
1917                } else {
1918                    let new_buffer = new_buffer.take().unwrap();
1919                    while network.borrow().has_unreceived(new_replica_id) {
1920                        let ops = network
1921                            .borrow_mut()
1922                            .receive(new_replica_id)
1923                            .into_iter()
1924                            .map(|op| proto::deserialize_operation(op).unwrap());
1925                        if ops.len() > 0 {
1926                            log::info!(
1927                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1928                                new_replica_id,
1929                                buffer.read(cx).version(),
1930                                ops.len(),
1931                                ops
1932                            );
1933                            new_buffer.update(cx, |new_buffer, cx| {
1934                                new_buffer.apply_ops(ops, cx).unwrap();
1935                            });
1936                        }
1937                    }
1938                    buffers[new_replica_id as usize] = new_buffer;
1939                }
1940            }
1941            60..=69 if mutation_count != 0 => {
1942                buffer.update(cx, |buffer, cx| {
1943                    buffer.randomly_undo_redo(&mut rng, cx);
1944                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1945                });
1946                mutation_count -= 1;
1947            }
1948            _ if network.borrow().has_unreceived(replica_id) => {
1949                let ops = network
1950                    .borrow_mut()
1951                    .receive(replica_id)
1952                    .into_iter()
1953                    .map(|op| proto::deserialize_operation(op).unwrap());
1954                if ops.len() > 0 {
1955                    log::info!(
1956                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1957                        replica_id,
1958                        buffer.read(cx).version(),
1959                        ops.len(),
1960                        ops
1961                    );
1962                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1963                }
1964            }
1965            _ => {}
1966        }
1967
1968        now += Duration::from_millis(rng.gen_range(0..=200));
1969        buffers.extend(new_buffer);
1970
1971        for buffer in &buffers {
1972            buffer.read(cx).check_invariants();
1973        }
1974
1975        if mutation_count == 0 && network.borrow().is_idle() {
1976            break;
1977        }
1978    }
1979
1980    let first_buffer = buffers[0].read(cx).snapshot();
1981    for buffer in &buffers[1..] {
1982        let buffer = buffer.read(cx).snapshot();
1983        assert_eq!(
1984            buffer.version(),
1985            first_buffer.version(),
1986            "Replica {} version != Replica 0 version",
1987            buffer.replica_id()
1988        );
1989        assert_eq!(
1990            buffer.text(),
1991            first_buffer.text(),
1992            "Replica {} text != Replica 0 text",
1993            buffer.replica_id()
1994        );
1995        assert_eq!(
1996            buffer
1997                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1998                .collect::<Vec<_>>(),
1999            first_buffer
2000                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2001                .collect::<Vec<_>>(),
2002            "Replica {} diagnostics != Replica 0 diagnostics",
2003            buffer.replica_id()
2004        );
2005    }
2006
2007    for buffer in &buffers {
2008        let buffer = buffer.read(cx).snapshot();
2009        let actual_remote_selections = buffer
2010            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2011            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2012            .collect::<Vec<_>>();
2013        let expected_remote_selections = active_selections
2014            .iter()
2015            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2016            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2017            .collect::<Vec<_>>();
2018        assert_eq!(
2019            actual_remote_selections,
2020            expected_remote_selections,
2021            "Replica {} remote selections != expected selections",
2022            buffer.replica_id()
2023        );
2024    }
2025}
2026
2027#[test]
2028fn test_contiguous_ranges() {
2029    assert_eq!(
2030        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2031        &[1..4, 5..7, 9..13]
2032    );
2033
2034    // Respects the `max_len` parameter
2035    assert_eq!(
2036        contiguous_ranges(
2037            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2038            3
2039        )
2040        .collect::<Vec<_>>(),
2041        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2042    );
2043}
2044
2045#[gpui::test(iterations = 500)]
2046fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2047    // Generate a random multi-line string containing
2048    // some lines with trailing whitespace.
2049    let mut text = String::new();
2050    for _ in 0..rng.gen_range(0..16) {
2051        for _ in 0..rng.gen_range(0..36) {
2052            text.push(match rng.gen_range(0..10) {
2053                0..=1 => ' ',
2054                3 => '\t',
2055                _ => rng.gen_range('a'..'z'),
2056            });
2057        }
2058        text.push('\n');
2059    }
2060
2061    match rng.gen_range(0..10) {
2062        // sometimes remove the last newline
2063        0..=1 => drop(text.pop()), //
2064
2065        // sometimes add extra newlines
2066        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2067        _ => {}
2068    }
2069
2070    let rope = Rope::from(text.as_str());
2071    let actual_ranges = trailing_whitespace_ranges(&rope);
2072    let expected_ranges = TRAILING_WHITESPACE_REGEX
2073        .find_iter(&text)
2074        .map(|m| m.range())
2075        .collect::<Vec<_>>();
2076    assert_eq!(
2077        actual_ranges,
2078        expected_ranges,
2079        "wrong ranges for text lines:\n{:?}",
2080        text.split("\n").collect::<Vec<_>>()
2081    );
2082}
2083
2084fn ruby_lang() -> Language {
2085    Language::new(
2086        LanguageConfig {
2087            name: "Ruby".into(),
2088            path_suffixes: vec!["rb".to_string()],
2089            ..Default::default()
2090        },
2091        Some(tree_sitter_ruby::language()),
2092    )
2093    .with_indents_query(
2094        r#"
2095            (class "end" @end) @indent
2096            (method "end" @end) @indent
2097            (rescue) @outdent
2098            (then) @indent
2099        "#,
2100    )
2101    .unwrap()
2102}
2103
2104fn rust_lang() -> Language {
2105    Language::new(
2106        LanguageConfig {
2107            name: "Rust".into(),
2108            path_suffixes: vec!["rs".to_string()],
2109            ..Default::default()
2110        },
2111        Some(tree_sitter_rust::language()),
2112    )
2113    .with_indents_query(
2114        r#"
2115        (call_expression) @indent
2116        (field_expression) @indent
2117        (_ "(" ")" @end) @indent
2118        (_ "{" "}" @end) @indent
2119        "#,
2120    )
2121    .unwrap()
2122    .with_brackets_query(
2123        r#"
2124        ("{" @open "}" @close)
2125        "#,
2126    )
2127    .unwrap()
2128    .with_outline_query(
2129        r#"
2130        (struct_item
2131            "struct" @context
2132            name: (_) @name) @item
2133        (enum_item
2134            "enum" @context
2135            name: (_) @name) @item
2136        (enum_variant
2137            name: (_) @name) @item
2138        (field_declaration
2139            name: (_) @name) @item
2140        (impl_item
2141            "impl" @context
2142            trait: (_)? @name
2143            "for"? @context
2144            type: (_) @name) @item
2145        (function_item
2146            "fn" @context
2147            name: (_) @name) @item
2148        (mod_item
2149            "mod" @context
2150            name: (_) @name) @item
2151        "#,
2152    )
2153    .unwrap()
2154}
2155
2156fn json_lang() -> Language {
2157    Language::new(
2158        LanguageConfig {
2159            name: "Json".into(),
2160            path_suffixes: vec!["js".to_string()],
2161            ..Default::default()
2162        },
2163        Some(tree_sitter_json::language()),
2164    )
2165}
2166
2167fn javascript_lang() -> Language {
2168    Language::new(
2169        LanguageConfig {
2170            name: "JavaScript".into(),
2171            ..Default::default()
2172        },
2173        Some(tree_sitter_javascript::language()),
2174    )
2175    .with_brackets_query(
2176        r#"
2177        ("{" @open "}" @close)
2178        ("(" @open ")" @close)
2179        "#,
2180    )
2181    .unwrap()
2182}
2183
2184fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
2185    buffer.read_with(cx, |buffer, _| {
2186        let snapshot = buffer.snapshot();
2187        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2188        layers[0].node.to_sexp()
2189    })
2190}
2191
2192// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2193fn assert_bracket_pairs(
2194    selection_text: &'static str,
2195    bracket_pair_texts: Vec<&'static str>,
2196    language: Language,
2197    cx: &mut MutableAppContext,
2198) {
2199    cx.set_global(Settings::test(cx));
2200    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2201    let buffer = cx.add_model(|cx| {
2202        Buffer::new(0, expected_text.clone(), cx).with_language(Arc::new(language), cx)
2203    });
2204    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2205
2206    let selection_range = selection_ranges[0].clone();
2207
2208    let bracket_pairs = bracket_pair_texts
2209        .into_iter()
2210        .map(|pair_text| {
2211            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2212            assert_eq!(bracket_text, expected_text);
2213            (ranges[0].clone(), ranges[1].clone())
2214        })
2215        .collect::<Vec<_>>();
2216
2217    assert_set_eq!(
2218        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2219        bracket_pairs
2220    );
2221}