tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use gpui::{ModelHandle, MutableAppContext};
   5use proto::deserialize_operation;
   6use rand::prelude::*;
   7use settings::Settings;
   8use std::{
   9    cell::RefCell,
  10    env,
  11    ops::Range,
  12    rc::Rc,
  13    time::{Duration, Instant},
  14};
  15use text::network::Network;
  16use unindent::Unindent as _;
  17use util::post_inc;
  18
  19#[cfg(test)]
  20#[ctor::ctor]
  21fn init_logger() {
  22    if std::env::var("RUST_LOG").is_ok() {
  23        env_logger::init();
  24    }
  25}
  26
  27#[gpui::test]
  28fn test_line_endings(cx: &mut gpui::MutableAppContext) {
  29    cx.set_global(Settings::test(cx));
  30    cx.add_model(|cx| {
  31        let mut buffer =
  32            Buffer::new(0, "one\r\ntwo\rthree", cx).with_language(Arc::new(rust_lang()), cx);
  33        assert_eq!(buffer.text(), "one\ntwo\nthree");
  34        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  35
  36        buffer.check_invariants();
  37        buffer.edit(
  38            [(buffer.len()..buffer.len(), "\r\nfour")],
  39            Some(AutoindentMode::EachLine),
  40            cx,
  41        );
  42        buffer.edit([(0..0, "zero\r\n")], None, cx);
  43        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  44        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  45        buffer.check_invariants();
  46
  47        buffer
  48    });
  49}
  50
  51#[gpui::test]
  52fn test_select_language() {
  53    let registry = LanguageRegistry::test();
  54    registry.add(Arc::new(Language::new(
  55        LanguageConfig {
  56            name: "Rust".into(),
  57            path_suffixes: vec!["rs".to_string()],
  58            ..Default::default()
  59        },
  60        Some(tree_sitter_rust::language()),
  61    )));
  62    registry.add(Arc::new(Language::new(
  63        LanguageConfig {
  64            name: "Make".into(),
  65            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  66            ..Default::default()
  67        },
  68        Some(tree_sitter_rust::language()),
  69    )));
  70
  71    // matching file extension
  72    assert_eq!(
  73        registry.select_language("zed/lib.rs").map(|l| l.name()),
  74        Some("Rust".into())
  75    );
  76    assert_eq!(
  77        registry.select_language("zed/lib.mk").map(|l| l.name()),
  78        Some("Make".into())
  79    );
  80
  81    // matching filename
  82    assert_eq!(
  83        registry.select_language("zed/Makefile").map(|l| l.name()),
  84        Some("Make".into())
  85    );
  86
  87    // matching suffix that is not the full file extension or filename
  88    assert_eq!(registry.select_language("zed/cars").map(|l| l.name()), None);
  89    assert_eq!(
  90        registry.select_language("zed/a.cars").map(|l| l.name()),
  91        None
  92    );
  93    assert_eq!(registry.select_language("zed/sumk").map(|l| l.name()), None);
  94}
  95
  96#[gpui::test]
  97fn test_edit_events(cx: &mut gpui::MutableAppContext) {
  98    let mut now = Instant::now();
  99    let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
 100    let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
 101
 102    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
 103    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
 104    let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
 105    buffer1.update(cx, {
 106        let buffer1_ops = buffer1_ops.clone();
 107        |buffer, cx| {
 108            let buffer_1_events = buffer_1_events.clone();
 109            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 110                Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
 111                event => buffer_1_events.borrow_mut().push(event),
 112            })
 113            .detach();
 114            let buffer_2_events = buffer_2_events.clone();
 115            cx.subscribe(&buffer2, move |_, _, event, _| {
 116                buffer_2_events.borrow_mut().push(event.clone())
 117            })
 118            .detach();
 119
 120            // An edit emits an edited event, followed by a dirty changed event,
 121            // since the buffer was previously in a clean state.
 122            buffer.edit([(2..4, "XYZ")], None, cx);
 123
 124            // An empty transaction does not emit any events.
 125            buffer.start_transaction();
 126            buffer.end_transaction(cx);
 127
 128            // A transaction containing two edits emits one edited event.
 129            now += Duration::from_secs(1);
 130            buffer.start_transaction_at(now);
 131            buffer.edit([(5..5, "u")], None, cx);
 132            buffer.edit([(6..6, "w")], None, cx);
 133            buffer.end_transaction_at(now, cx);
 134
 135            // Undoing a transaction emits one edited event.
 136            buffer.undo(cx);
 137        }
 138    });
 139
 140    // Incorporating a set of remote ops emits a single edited event,
 141    // followed by a dirty changed event.
 142    buffer2.update(cx, |buffer, cx| {
 143        buffer
 144            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 145            .unwrap();
 146    });
 147    assert_eq!(
 148        mem::take(&mut *buffer_1_events.borrow_mut()),
 149        vec![
 150            Event::Edited,
 151            Event::DirtyChanged,
 152            Event::Edited,
 153            Event::Edited,
 154        ]
 155    );
 156    assert_eq!(
 157        mem::take(&mut *buffer_2_events.borrow_mut()),
 158        vec![Event::Edited, Event::DirtyChanged]
 159    );
 160
 161    buffer1.update(cx, |buffer, cx| {
 162        // Undoing the first transaction emits edited event, followed by a
 163        // dirty changed event, since the buffer is again in a clean state.
 164        buffer.undo(cx);
 165    });
 166    // Incorporating the remote ops again emits a single edited event,
 167    // followed by a dirty changed event.
 168    buffer2.update(cx, |buffer, cx| {
 169        buffer
 170            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 171            .unwrap();
 172    });
 173    assert_eq!(
 174        mem::take(&mut *buffer_1_events.borrow_mut()),
 175        vec![Event::Edited, Event::DirtyChanged,]
 176    );
 177    assert_eq!(
 178        mem::take(&mut *buffer_2_events.borrow_mut()),
 179        vec![Event::Edited, Event::DirtyChanged]
 180    );
 181}
 182
 183#[gpui::test]
 184async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
 185    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 186    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 187    let anchor = buffer.read_with(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 188
 189    let text = "a\nccc\ndddd\nffffff\n";
 190    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 191    buffer.update(cx, |buffer, cx| {
 192        buffer.apply_diff(diff, cx).unwrap();
 193        assert_eq!(buffer.text(), text);
 194        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 195    });
 196
 197    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 198    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 199    buffer.update(cx, |buffer, cx| {
 200        buffer.apply_diff(diff, cx).unwrap();
 201        assert_eq!(buffer.text(), text);
 202        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 203    });
 204}
 205
 206#[gpui::test]
 207async fn test_reparse(cx: &mut gpui::TestAppContext) {
 208    let text = "fn a() {}";
 209    let buffer =
 210        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 211
 212    // Wait for the initial text to parse
 213    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 214    assert_eq!(
 215        get_tree_sexp(&buffer, cx),
 216        concat!(
 217            "(source_file (function_item name: (identifier) ",
 218            "parameters: (parameters) ",
 219            "body: (block)))"
 220        )
 221    );
 222
 223    buffer.update(cx, |buffer, _| {
 224        buffer.set_sync_parse_timeout(Duration::ZERO)
 225    });
 226
 227    // Perform some edits (add parameter and variable reference)
 228    // Parsing doesn't begin until the transaction is complete
 229    buffer.update(cx, |buf, cx| {
 230        buf.start_transaction();
 231
 232        let offset = buf.text().find(')').unwrap();
 233        buf.edit([(offset..offset, "b: C")], None, cx);
 234        assert!(!buf.is_parsing());
 235
 236        let offset = buf.text().find('}').unwrap();
 237        buf.edit([(offset..offset, " d; ")], None, cx);
 238        assert!(!buf.is_parsing());
 239
 240        buf.end_transaction(cx);
 241        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 242        assert!(buf.is_parsing());
 243    });
 244    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 245    assert_eq!(
 246        get_tree_sexp(&buffer, cx),
 247        concat!(
 248            "(source_file (function_item name: (identifier) ",
 249            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 250            "body: (block (expression_statement (identifier)))))"
 251        )
 252    );
 253
 254    // Perform a series of edits without waiting for the current parse to complete:
 255    // * turn identifier into a field expression
 256    // * turn field expression into a method call
 257    // * add a turbofish to the method call
 258    buffer.update(cx, |buf, cx| {
 259        let offset = buf.text().find(';').unwrap();
 260        buf.edit([(offset..offset, ".e")], None, cx);
 261        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 262        assert!(buf.is_parsing());
 263    });
 264    buffer.update(cx, |buf, cx| {
 265        let offset = buf.text().find(';').unwrap();
 266        buf.edit([(offset..offset, "(f)")], None, cx);
 267        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 268        assert!(buf.is_parsing());
 269    });
 270    buffer.update(cx, |buf, cx| {
 271        let offset = buf.text().find("(f)").unwrap();
 272        buf.edit([(offset..offset, "::<G>")], None, cx);
 273        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 274        assert!(buf.is_parsing());
 275    });
 276    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 277    assert_eq!(
 278        get_tree_sexp(&buffer, cx),
 279        concat!(
 280            "(source_file (function_item name: (identifier) ",
 281            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 282            "body: (block (expression_statement (call_expression ",
 283            "function: (generic_function ",
 284            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 285            "type_arguments: (type_arguments (type_identifier))) ",
 286            "arguments: (arguments (identifier)))))))",
 287        )
 288    );
 289
 290    buffer.update(cx, |buf, cx| {
 291        buf.undo(cx);
 292        assert_eq!(buf.text(), "fn a() {}");
 293        assert!(buf.is_parsing());
 294    });
 295    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 296    assert_eq!(
 297        get_tree_sexp(&buffer, cx),
 298        concat!(
 299            "(source_file (function_item name: (identifier) ",
 300            "parameters: (parameters) ",
 301            "body: (block)))"
 302        )
 303    );
 304
 305    buffer.update(cx, |buf, cx| {
 306        buf.redo(cx);
 307        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 308        assert!(buf.is_parsing());
 309    });
 310    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 311    assert_eq!(
 312        get_tree_sexp(&buffer, cx),
 313        concat!(
 314            "(source_file (function_item name: (identifier) ",
 315            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 316            "body: (block (expression_statement (call_expression ",
 317            "function: (generic_function ",
 318            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 319            "type_arguments: (type_arguments (type_identifier))) ",
 320            "arguments: (arguments (identifier)))))))",
 321        )
 322    );
 323}
 324
 325#[gpui::test]
 326async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 327    let buffer = cx.add_model(|cx| {
 328        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 329        buffer.set_sync_parse_timeout(Duration::ZERO);
 330        buffer
 331    });
 332
 333    // Wait for the initial text to parse
 334    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 335    assert_eq!(
 336        get_tree_sexp(&buffer, cx),
 337        "(source_file (expression_statement (block)))"
 338    );
 339
 340    buffer.update(cx, |buffer, cx| {
 341        buffer.set_language(Some(Arc::new(json_lang())), cx)
 342    });
 343    buffer.condition(cx, |buffer, _| !buffer.is_parsing()).await;
 344    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 345}
 346
 347#[gpui::test]
 348async fn test_outline(cx: &mut gpui::TestAppContext) {
 349    let text = r#"
 350        struct Person {
 351            name: String,
 352            age: usize,
 353        }
 354
 355        mod module {
 356            enum LoginState {
 357                LoggedOut,
 358                LoggingOn,
 359                LoggedIn {
 360                    person: Person,
 361                    time: Instant,
 362                }
 363            }
 364        }
 365
 366        impl Eq for Person {}
 367
 368        impl Drop for Person {
 369            fn drop(&mut self) {
 370                println!("bye");
 371            }
 372        }
 373    "#
 374    .unindent();
 375
 376    let buffer =
 377        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 378    let outline = buffer
 379        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 380        .unwrap();
 381
 382    assert_eq!(
 383        outline
 384            .items
 385            .iter()
 386            .map(|item| (item.text.as_str(), item.depth))
 387            .collect::<Vec<_>>(),
 388        &[
 389            ("struct Person", 0),
 390            ("name", 1),
 391            ("age", 1),
 392            ("mod module", 0),
 393            ("enum LoginState", 1),
 394            ("LoggedOut", 2),
 395            ("LoggingOn", 2),
 396            ("LoggedIn", 2),
 397            ("person", 3),
 398            ("time", 3),
 399            ("impl Eq for Person", 0),
 400            ("impl Drop for Person", 0),
 401            ("fn drop", 1),
 402        ]
 403    );
 404
 405    // Without space, we only match on names
 406    assert_eq!(
 407        search(&outline, "oon", cx).await,
 408        &[
 409            ("mod module", vec![]),                    // included as the parent of a match
 410            ("enum LoginState", vec![]),               // included as the parent of a match
 411            ("LoggingOn", vec![1, 7, 8]),              // matches
 412            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 413        ]
 414    );
 415
 416    assert_eq!(
 417        search(&outline, "dp p", cx).await,
 418        &[
 419            ("impl Drop for Person", vec![5, 8, 9, 14]),
 420            ("fn drop", vec![]),
 421        ]
 422    );
 423    assert_eq!(
 424        search(&outline, "dpn", cx).await,
 425        &[("impl Drop for Person", vec![5, 14, 19])]
 426    );
 427    assert_eq!(
 428        search(&outline, "impl ", cx).await,
 429        &[
 430            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 431            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 432            ("fn drop", vec![]),
 433        ]
 434    );
 435
 436    async fn search<'a>(
 437        outline: &'a Outline<Anchor>,
 438        query: &'a str,
 439        cx: &'a gpui::TestAppContext,
 440    ) -> Vec<(&'a str, Vec<usize>)> {
 441        let matches = cx
 442            .read(|cx| outline.search(query, cx.background().clone()))
 443            .await;
 444        matches
 445            .into_iter()
 446            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 447            .collect::<Vec<_>>()
 448    }
 449}
 450
 451#[gpui::test]
 452async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 453    let text = r#"
 454        impl Person {
 455            fn one() {
 456                1
 457            }
 458
 459            fn two() {
 460                2
 461            }fn three() {
 462                3
 463            }
 464        }
 465    "#
 466    .unindent();
 467
 468    let buffer =
 469        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 470    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 471
 472    // point is at the start of an item
 473    assert_eq!(
 474        symbols_containing(Point::new(1, 4), &snapshot),
 475        vec![
 476            (
 477                "impl Person".to_string(),
 478                Point::new(0, 0)..Point::new(10, 1)
 479            ),
 480            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 481        ]
 482    );
 483
 484    // point is in the middle of an item
 485    assert_eq!(
 486        symbols_containing(Point::new(2, 8), &snapshot),
 487        vec![
 488            (
 489                "impl Person".to_string(),
 490                Point::new(0, 0)..Point::new(10, 1)
 491            ),
 492            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 493        ]
 494    );
 495
 496    // point is at the end of an item
 497    assert_eq!(
 498        symbols_containing(Point::new(3, 5), &snapshot),
 499        vec![
 500            (
 501                "impl Person".to_string(),
 502                Point::new(0, 0)..Point::new(10, 1)
 503            ),
 504            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 505        ]
 506    );
 507
 508    // point is in between two adjacent items
 509    assert_eq!(
 510        symbols_containing(Point::new(7, 5), &snapshot),
 511        vec![
 512            (
 513                "impl Person".to_string(),
 514                Point::new(0, 0)..Point::new(10, 1)
 515            ),
 516            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 517        ]
 518    );
 519
 520    fn symbols_containing(
 521        position: Point,
 522        snapshot: &BufferSnapshot,
 523    ) -> Vec<(String, Range<Point>)> {
 524        snapshot
 525            .symbols_containing(position, None)
 526            .unwrap()
 527            .into_iter()
 528            .map(|item| {
 529                (
 530                    item.text,
 531                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 532                )
 533            })
 534            .collect()
 535    }
 536}
 537
 538#[gpui::test]
 539fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 540    cx.set_global(Settings::test(cx));
 541    let buffer = cx.add_model(|cx| {
 542        let text = "
 543            mod x {
 544                mod y {
 545
 546                }
 547            }
 548        "
 549        .unindent();
 550        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
 551    });
 552    let buffer = buffer.read(cx);
 553    assert_eq!(
 554        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
 555        Some((
 556            Point::new(0, 6)..Point::new(0, 7),
 557            Point::new(4, 0)..Point::new(4, 1)
 558        ))
 559    );
 560    assert_eq!(
 561        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
 562        Some((
 563            Point::new(1, 10)..Point::new(1, 11),
 564            Point::new(3, 4)..Point::new(3, 5)
 565        ))
 566    );
 567    assert_eq!(
 568        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
 569        Some((
 570            Point::new(1, 10)..Point::new(1, 11),
 571            Point::new(3, 4)..Point::new(3, 5)
 572        ))
 573    );
 574}
 575
 576#[gpui::test]
 577fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 578    cx.add_model(|cx| {
 579        let text = "fn a() { b(|c| {}) }";
 580        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 581        let snapshot = buffer.snapshot();
 582
 583        assert_eq!(
 584            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 585            Some(range_of(text, "|"))
 586        );
 587        assert_eq!(
 588            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 589            Some(range_of(text, "|c|"))
 590        );
 591        assert_eq!(
 592            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 593            Some(range_of(text, "|c| {}"))
 594        );
 595        assert_eq!(
 596            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 597            Some(range_of(text, "(|c| {})"))
 598        );
 599
 600        buffer
 601    });
 602
 603    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 604        let start = text.find(part).unwrap();
 605        start..start
 606    }
 607
 608    fn range_of(text: &str, part: &str) -> Range<usize> {
 609        let start = text.find(part).unwrap();
 610        start..start + part.len()
 611    }
 612}
 613
 614#[gpui::test]
 615fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 616    let settings = Settings::test(cx);
 617    cx.set_global(settings);
 618
 619    cx.add_model(|cx| {
 620        let text = "fn a() {}";
 621        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 622
 623        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 624        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 625
 626        buffer.edit(
 627            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 628            Some(AutoindentMode::EachLine),
 629            cx,
 630        );
 631        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 632
 633        // Create a field expression on a new line, causing that line
 634        // to be indented.
 635        buffer.edit(
 636            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 637            Some(AutoindentMode::EachLine),
 638            cx,
 639        );
 640        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 641
 642        // Remove the dot so that the line is no longer a field expression,
 643        // causing the line to be outdented.
 644        buffer.edit(
 645            [(Point::new(2, 8)..Point::new(2, 9), "")],
 646            Some(AutoindentMode::EachLine),
 647            cx,
 648        );
 649        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 650
 651        buffer
 652    });
 653}
 654
 655#[gpui::test]
 656fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 657    let mut settings = Settings::test(cx);
 658    settings.editor_overrides.hard_tabs = Some(true);
 659    cx.set_global(settings);
 660
 661    cx.add_model(|cx| {
 662        let text = "fn a() {}";
 663        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 664
 665        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 666        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 667
 668        buffer.edit(
 669            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 670            Some(AutoindentMode::EachLine),
 671            cx,
 672        );
 673        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 674
 675        // Create a field expression on a new line, causing that line
 676        // to be indented.
 677        buffer.edit(
 678            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 679            Some(AutoindentMode::EachLine),
 680            cx,
 681        );
 682        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 683
 684        // Remove the dot so that the line is no longer a field expression,
 685        // causing the line to be outdented.
 686        buffer.edit(
 687            [(Point::new(2, 2)..Point::new(2, 3), "")],
 688            Some(AutoindentMode::EachLine),
 689            cx,
 690        );
 691        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 692
 693        buffer
 694    });
 695}
 696
 697#[gpui::test]
 698fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 699    let settings = Settings::test(cx);
 700    cx.set_global(settings);
 701
 702    cx.add_model(|cx| {
 703        let text = "
 704            fn a() {
 705            c;
 706            d;
 707            }
 708        "
 709        .unindent();
 710
 711        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 712
 713        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 714        // their indentation is not adjusted.
 715        buffer.edit(
 716            [
 717                (empty(Point::new(1, 1)), "()"),
 718                (empty(Point::new(2, 1)), "()"),
 719            ],
 720            Some(AutoindentMode::EachLine),
 721            cx,
 722        );
 723        assert_eq!(
 724            buffer.text(),
 725            "
 726            fn a() {
 727            c();
 728            d();
 729            }
 730            "
 731            .unindent()
 732        );
 733
 734        // When appending new content after these lines, the indentation is based on the
 735        // preceding lines' actual indentation.
 736        buffer.edit(
 737            [
 738                (empty(Point::new(1, 1)), "\n.f\n.g"),
 739                (empty(Point::new(2, 1)), "\n.f\n.g"),
 740            ],
 741            Some(AutoindentMode::EachLine),
 742            cx,
 743        );
 744        assert_eq!(
 745            buffer.text(),
 746            "
 747            fn a() {
 748            c
 749                .f
 750                .g();
 751            d
 752                .f
 753                .g();
 754            }
 755            "
 756            .unindent()
 757        );
 758        buffer
 759    });
 760
 761    cx.add_model(|cx| {
 762        let text = "
 763            fn a() {
 764                {
 765                    b()?
 766                }
 767                Ok(())
 768            }
 769        "
 770        .unindent();
 771        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 772
 773        // Delete a closing curly brace changes the suggested indent for the line.
 774        buffer.edit(
 775            [(Point::new(3, 4)..Point::new(3, 5), "")],
 776            Some(AutoindentMode::EachLine),
 777            cx,
 778        );
 779        assert_eq!(
 780            buffer.text(),
 781            "
 782            fn a() {
 783                {
 784                    b()?
 785                        |
 786                Ok(())
 787            }
 788            "
 789            .replace('|', "") // included in the string to preserve trailing whites
 790            .unindent()
 791        );
 792
 793        // Manually editing the leading whitespace
 794        buffer.edit(
 795            [(Point::new(3, 0)..Point::new(3, 12), "")],
 796            Some(AutoindentMode::EachLine),
 797            cx,
 798        );
 799        assert_eq!(
 800            buffer.text(),
 801            "
 802            fn a() {
 803                {
 804                    b()?
 805
 806                Ok(())
 807            }
 808            "
 809            .unindent()
 810        );
 811        buffer
 812    });
 813}
 814
 815#[gpui::test]
 816fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 817    cx.set_global(Settings::test(cx));
 818    cx.add_model(|cx| {
 819        let text = "
 820            fn a() {}
 821        "
 822        .unindent();
 823
 824        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 825
 826        buffer.edit([(5..5, "\nb")], Some(AutoindentMode::EachLine), cx);
 827        assert_eq!(
 828            buffer.text(),
 829            "
 830                fn a(
 831                    b) {}
 832            "
 833            .unindent()
 834        );
 835
 836        // The indentation suggestion changed because `@end` node (a close paren)
 837        // is now at the beginning of the line.
 838        buffer.edit(
 839            [(Point::new(1, 4)..Point::new(1, 5), "")],
 840            Some(AutoindentMode::EachLine),
 841            cx,
 842        );
 843        assert_eq!(
 844            buffer.text(),
 845            "
 846                fn a(
 847                ) {}
 848            "
 849            .unindent()
 850        );
 851
 852        buffer
 853    });
 854}
 855
 856#[gpui::test]
 857fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 858    cx.set_global(Settings::test(cx));
 859    cx.add_model(|cx| {
 860        let text = "a\nb";
 861        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 862        buffer.edit(
 863            [(0..1, "\n"), (2..3, "\n")],
 864            Some(AutoindentMode::EachLine),
 865            cx,
 866        );
 867        assert_eq!(buffer.text(), "\n\n\n");
 868        buffer
 869    });
 870}
 871
 872#[gpui::test]
 873fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 874    cx.set_global(Settings::test(cx));
 875    cx.add_model(|cx| {
 876        let text = "
 877            const a: usize = 1;
 878            fn b() {
 879                if c {
 880                    let d = 2;
 881                }
 882            }
 883        "
 884        .unindent();
 885
 886        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 887        buffer.edit(
 888            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
 889            Some(AutoindentMode::EachLine),
 890            cx,
 891        );
 892        assert_eq!(
 893            buffer.text(),
 894            "
 895                const a: usize = 1;
 896                fn b() {
 897                    if c {
 898                        e(
 899                            f()
 900                        );
 901                        let d = 2;
 902                    }
 903                }
 904            "
 905            .unindent()
 906        );
 907
 908        buffer
 909    });
 910}
 911
 912#[gpui::test]
 913fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
 914    cx.set_global(Settings::test(cx));
 915    cx.add_model(|cx| {
 916        let text = r#"
 917            fn a() {
 918                b();
 919            }
 920        "#
 921        .unindent();
 922        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 923
 924        let inserted_text = r#"
 925            "
 926              c
 927                d
 928                  e
 929            "
 930        "#
 931        .unindent();
 932
 933        // Insert the block at column zero. The entire block is indented
 934        // so that the first line matches the previous line's indentation.
 935        buffer.edit(
 936            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
 937            Some(AutoindentMode::Block {
 938                original_indent_columns: vec![0],
 939            }),
 940            cx,
 941        );
 942        assert_eq!(
 943            buffer.text(),
 944            r#"
 945            fn a() {
 946                b();
 947                "
 948                  c
 949                    d
 950                      e
 951                "
 952            }
 953            "#
 954            .unindent()
 955        );
 956
 957        // Insert the block at a deeper indent level. The entire block is outdented.
 958        buffer.undo(cx);
 959        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
 960        buffer.edit(
 961            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
 962            Some(AutoindentMode::Block {
 963                original_indent_columns: vec![0],
 964            }),
 965            cx,
 966        );
 967        assert_eq!(
 968            buffer.text(),
 969            r#"
 970            fn a() {
 971                b();
 972                "
 973                  c
 974                    d
 975                      e
 976                "
 977            }
 978            "#
 979            .unindent()
 980        );
 981
 982        buffer
 983    });
 984}
 985
 986#[gpui::test]
 987fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
 988    cx.set_global(Settings::test(cx));
 989    cx.add_model(|cx| {
 990        let text = "
 991            * one
 992                - a
 993                - b
 994            * two
 995        "
 996        .unindent();
 997
 998        let mut buffer = Buffer::new(0, text, cx).with_language(
 999            Arc::new(Language::new(
1000                LanguageConfig {
1001                    name: "Markdown".into(),
1002                    auto_indent_using_last_non_empty_line: false,
1003                    ..Default::default()
1004                },
1005                Some(tree_sitter_json::language()),
1006            )),
1007            cx,
1008        );
1009        buffer.edit(
1010            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1011            Some(AutoindentMode::EachLine),
1012            cx,
1013        );
1014        assert_eq!(
1015            buffer.text(),
1016            "
1017            * one
1018                - a
1019                - b
1020
1021            * two
1022            "
1023            .unindent()
1024        );
1025        buffer
1026    });
1027}
1028
1029#[gpui::test]
1030fn test_serialization(cx: &mut gpui::MutableAppContext) {
1031    let mut now = Instant::now();
1032
1033    let buffer1 = cx.add_model(|cx| {
1034        let mut buffer = Buffer::new(0, "abc", cx);
1035        buffer.edit([(3..3, "D")], None, cx);
1036
1037        now += Duration::from_secs(1);
1038        buffer.start_transaction_at(now);
1039        buffer.edit([(4..4, "E")], None, cx);
1040        buffer.end_transaction_at(now, cx);
1041        assert_eq!(buffer.text(), "abcDE");
1042
1043        buffer.undo(cx);
1044        assert_eq!(buffer.text(), "abcD");
1045
1046        buffer.edit([(4..4, "F")], None, cx);
1047        assert_eq!(buffer.text(), "abcDF");
1048        buffer
1049    });
1050    assert_eq!(buffer1.read(cx).text(), "abcDF");
1051
1052    let state = buffer1.read(cx).to_proto();
1053    let ops = cx.background().block(buffer1.read(cx).serialize_ops(cx));
1054    let buffer2 = cx.add_model(|cx| {
1055        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1056        buffer
1057            .apply_ops(
1058                ops.into_iter()
1059                    .map(|op| proto::deserialize_operation(op).unwrap()),
1060                cx,
1061            )
1062            .unwrap();
1063        buffer
1064    });
1065    assert_eq!(buffer2.read(cx).text(), "abcDF");
1066}
1067
1068#[gpui::test(iterations = 100)]
1069fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1070    let min_peers = env::var("MIN_PEERS")
1071        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1072        .unwrap_or(1);
1073    let max_peers = env::var("MAX_PEERS")
1074        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1075        .unwrap_or(5);
1076    let operations = env::var("OPERATIONS")
1077        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1078        .unwrap_or(10);
1079
1080    let base_text_len = rng.gen_range(0..10);
1081    let base_text = RandomCharIter::new(&mut rng)
1082        .take(base_text_len)
1083        .collect::<String>();
1084    let mut replica_ids = Vec::new();
1085    let mut buffers = Vec::new();
1086    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1087    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1088
1089    for i in 0..rng.gen_range(min_peers..=max_peers) {
1090        let buffer = cx.add_model(|cx| {
1091            let state = base_buffer.read(cx).to_proto();
1092            let ops = cx
1093                .background()
1094                .block(base_buffer.read(cx).serialize_ops(cx));
1095            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1096            buffer
1097                .apply_ops(
1098                    ops.into_iter()
1099                        .map(|op| proto::deserialize_operation(op).unwrap()),
1100                    cx,
1101                )
1102                .unwrap();
1103            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1104            let network = network.clone();
1105            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1106                if let Event::Operation(op) = event {
1107                    network
1108                        .borrow_mut()
1109                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1110                }
1111            })
1112            .detach();
1113            buffer
1114        });
1115        buffers.push(buffer);
1116        replica_ids.push(i as ReplicaId);
1117        network.borrow_mut().add_peer(i as ReplicaId);
1118        log::info!("Adding initial peer with replica id {}", i);
1119    }
1120
1121    log::info!("initial text: {:?}", base_text);
1122
1123    let mut now = Instant::now();
1124    let mut mutation_count = operations;
1125    let mut next_diagnostic_id = 0;
1126    let mut active_selections = BTreeMap::default();
1127    loop {
1128        let replica_index = rng.gen_range(0..replica_ids.len());
1129        let replica_id = replica_ids[replica_index];
1130        let buffer = &mut buffers[replica_index];
1131        let mut new_buffer = None;
1132        match rng.gen_range(0..100) {
1133            0..=29 if mutation_count != 0 => {
1134                buffer.update(cx, |buffer, cx| {
1135                    buffer.start_transaction_at(now);
1136                    buffer.randomly_edit(&mut rng, 5, cx);
1137                    buffer.end_transaction_at(now, cx);
1138                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1139                });
1140                mutation_count -= 1;
1141            }
1142            30..=39 if mutation_count != 0 => {
1143                buffer.update(cx, |buffer, cx| {
1144                    let mut selections = Vec::new();
1145                    for id in 0..rng.gen_range(1..=5) {
1146                        let range = buffer.random_byte_range(0, &mut rng);
1147                        selections.push(Selection {
1148                            id,
1149                            start: buffer.anchor_before(range.start),
1150                            end: buffer.anchor_before(range.end),
1151                            reversed: false,
1152                            goal: SelectionGoal::None,
1153                        });
1154                    }
1155                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1156                    log::info!(
1157                        "peer {} setting active selections: {:?}",
1158                        replica_id,
1159                        selections
1160                    );
1161                    active_selections.insert(replica_id, selections.clone());
1162                    buffer.set_active_selections(selections, false, cx);
1163                });
1164                mutation_count -= 1;
1165            }
1166            40..=49 if mutation_count != 0 && replica_id == 0 => {
1167                let entry_count = rng.gen_range(1..=5);
1168                buffer.update(cx, |buffer, cx| {
1169                    let diagnostics = DiagnosticSet::new(
1170                        (0..entry_count).map(|_| {
1171                            let range = buffer.random_byte_range(0, &mut rng);
1172                            let range = range.to_point_utf16(buffer);
1173                            DiagnosticEntry {
1174                                range,
1175                                diagnostic: Diagnostic {
1176                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1177                                    ..Default::default()
1178                                },
1179                            }
1180                        }),
1181                        buffer,
1182                    );
1183                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1184                    buffer.update_diagnostics(diagnostics, cx);
1185                });
1186                mutation_count -= 1;
1187            }
1188            50..=59 if replica_ids.len() < max_peers => {
1189                let old_buffer_state = buffer.read(cx).to_proto();
1190                let old_buffer_ops = cx.background().block(buffer.read(cx).serialize_ops(cx));
1191                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1192                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1193                    .choose(&mut rng)
1194                    .unwrap();
1195                log::info!(
1196                    "Adding new replica {} (replicating from {})",
1197                    new_replica_id,
1198                    replica_id
1199                );
1200                new_buffer = Some(cx.add_model(|cx| {
1201                    let mut new_buffer =
1202                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1203                    new_buffer
1204                        .apply_ops(
1205                            old_buffer_ops
1206                                .into_iter()
1207                                .map(|op| deserialize_operation(op).unwrap()),
1208                            cx,
1209                        )
1210                        .unwrap();
1211                    log::info!(
1212                        "New replica {} text: {:?}",
1213                        new_buffer.replica_id(),
1214                        new_buffer.text()
1215                    );
1216                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1217                    let network = network.clone();
1218                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1219                        if let Event::Operation(op) = event {
1220                            network.borrow_mut().broadcast(
1221                                buffer.replica_id(),
1222                                vec![proto::serialize_operation(op)],
1223                            );
1224                        }
1225                    })
1226                    .detach();
1227                    new_buffer
1228                }));
1229                network.borrow_mut().replicate(replica_id, new_replica_id);
1230
1231                if new_replica_id as usize == replica_ids.len() {
1232                    replica_ids.push(new_replica_id);
1233                } else {
1234                    let new_buffer = new_buffer.take().unwrap();
1235                    while network.borrow().has_unreceived(new_replica_id) {
1236                        let ops = network
1237                            .borrow_mut()
1238                            .receive(new_replica_id)
1239                            .into_iter()
1240                            .map(|op| proto::deserialize_operation(op).unwrap());
1241                        if ops.len() > 0 {
1242                            log::info!(
1243                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1244                                new_replica_id,
1245                                buffer.read(cx).version(),
1246                                ops.len(),
1247                                ops
1248                            );
1249                            new_buffer.update(cx, |new_buffer, cx| {
1250                                new_buffer.apply_ops(ops, cx).unwrap();
1251                            });
1252                        }
1253                    }
1254                    buffers[new_replica_id as usize] = new_buffer;
1255                }
1256            }
1257            60..=69 if mutation_count != 0 => {
1258                buffer.update(cx, |buffer, cx| {
1259                    buffer.randomly_undo_redo(&mut rng, cx);
1260                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1261                });
1262                mutation_count -= 1;
1263            }
1264            _ if network.borrow().has_unreceived(replica_id) => {
1265                let ops = network
1266                    .borrow_mut()
1267                    .receive(replica_id)
1268                    .into_iter()
1269                    .map(|op| proto::deserialize_operation(op).unwrap());
1270                if ops.len() > 0 {
1271                    log::info!(
1272                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1273                        replica_id,
1274                        buffer.read(cx).version(),
1275                        ops.len(),
1276                        ops
1277                    );
1278                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1279                }
1280            }
1281            _ => {}
1282        }
1283
1284        now += Duration::from_millis(rng.gen_range(0..=200));
1285        buffers.extend(new_buffer);
1286
1287        for buffer in &buffers {
1288            buffer.read(cx).check_invariants();
1289        }
1290
1291        if mutation_count == 0 && network.borrow().is_idle() {
1292            break;
1293        }
1294    }
1295
1296    let first_buffer = buffers[0].read(cx).snapshot();
1297    for buffer in &buffers[1..] {
1298        let buffer = buffer.read(cx).snapshot();
1299        assert_eq!(
1300            buffer.version(),
1301            first_buffer.version(),
1302            "Replica {} version != Replica 0 version",
1303            buffer.replica_id()
1304        );
1305        assert_eq!(
1306            buffer.text(),
1307            first_buffer.text(),
1308            "Replica {} text != Replica 0 text",
1309            buffer.replica_id()
1310        );
1311        assert_eq!(
1312            buffer
1313                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1314                .collect::<Vec<_>>(),
1315            first_buffer
1316                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1317                .collect::<Vec<_>>(),
1318            "Replica {} diagnostics != Replica 0 diagnostics",
1319            buffer.replica_id()
1320        );
1321    }
1322
1323    for buffer in &buffers {
1324        let buffer = buffer.read(cx).snapshot();
1325        let actual_remote_selections = buffer
1326            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1327            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1328            .collect::<Vec<_>>();
1329        let expected_remote_selections = active_selections
1330            .iter()
1331            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1332            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1333            .collect::<Vec<_>>();
1334        assert_eq!(
1335            actual_remote_selections,
1336            expected_remote_selections,
1337            "Replica {} remote selections != expected selections",
1338            buffer.replica_id()
1339        );
1340    }
1341}
1342
1343#[test]
1344fn test_contiguous_ranges() {
1345    assert_eq!(
1346        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1347        &[1..4, 5..7, 9..13]
1348    );
1349
1350    // Respects the `max_len` parameter
1351    assert_eq!(
1352        contiguous_ranges(
1353            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1354            3
1355        )
1356        .collect::<Vec<_>>(),
1357        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1358    );
1359}
1360
1361impl Buffer {
1362    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1363        &self,
1364        range: Range<T>,
1365    ) -> Option<(Range<Point>, Range<Point>)> {
1366        self.snapshot()
1367            .enclosing_bracket_ranges(range)
1368            .map(|(start, end)| {
1369                let point_start = start.start.to_point(self)..start.end.to_point(self);
1370                let point_end = end.start.to_point(self)..end.end.to_point(self);
1371                (point_start, point_end)
1372            })
1373    }
1374}
1375
1376fn rust_lang() -> Language {
1377    Language::new(
1378        LanguageConfig {
1379            name: "Rust".into(),
1380            path_suffixes: vec!["rs".to_string()],
1381            ..Default::default()
1382        },
1383        Some(tree_sitter_rust::language()),
1384    )
1385    .with_indents_query(
1386        r#"
1387        (call_expression) @indent
1388        (field_expression) @indent
1389        (_ "(" ")" @end) @indent
1390        (_ "{" "}" @end) @indent
1391        "#,
1392    )
1393    .unwrap()
1394    .with_brackets_query(
1395        r#"
1396        ("{" @open "}" @close)
1397        "#,
1398    )
1399    .unwrap()
1400    .with_outline_query(
1401        r#"
1402        (struct_item
1403            "struct" @context
1404            name: (_) @name) @item
1405        (enum_item
1406            "enum" @context
1407            name: (_) @name) @item
1408        (enum_variant
1409            name: (_) @name) @item
1410        (field_declaration
1411            name: (_) @name) @item
1412        (impl_item
1413            "impl" @context
1414            trait: (_)? @name
1415            "for"? @context
1416            type: (_) @name) @item
1417        (function_item
1418            "fn" @context
1419            name: (_) @name) @item
1420        (mod_item
1421            "mod" @context
1422            name: (_) @name) @item
1423        "#,
1424    )
1425    .unwrap()
1426}
1427
1428fn json_lang() -> Language {
1429    Language::new(
1430        LanguageConfig {
1431            name: "Json".into(),
1432            path_suffixes: vec!["js".to_string()],
1433            ..Default::default()
1434        },
1435        Some(tree_sitter_json::language()),
1436    )
1437}
1438
1439fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1440    buffer.read_with(cx, |buffer, _| {
1441        let snapshot = buffer.snapshot();
1442        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
1443        layers[0].2.to_sexp()
1444    })
1445}
1446
1447fn empty(point: Point) -> Range<Point> {
1448    point..point
1449}