buffer_tests.rs

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