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