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