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    // Regression test: avoid crash when querying at the end of the buffer.
 576    assert_eq!(
 577        buffer.enclosing_bracket_point_ranges(buffer.len() - 1..buffer.len()),
 578        Some((
 579            Point::new(0, 6)..Point::new(0, 7),
 580            Point::new(4, 0)..Point::new(4, 1)
 581        ))
 582    );
 583}
 584
 585#[gpui::test]
 586fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 587    cx.add_model(|cx| {
 588        let text = "fn a() { b(|c| {}) }";
 589        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 590        let snapshot = buffer.snapshot();
 591
 592        assert_eq!(
 593            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 594            Some(range_of(text, "|"))
 595        );
 596        assert_eq!(
 597            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 598            Some(range_of(text, "|c|"))
 599        );
 600        assert_eq!(
 601            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 602            Some(range_of(text, "|c| {}"))
 603        );
 604        assert_eq!(
 605            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 606            Some(range_of(text, "(|c| {})"))
 607        );
 608
 609        buffer
 610    });
 611
 612    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 613        let start = text.find(part).unwrap();
 614        start..start
 615    }
 616
 617    fn range_of(text: &str, part: &str) -> Range<usize> {
 618        let start = text.find(part).unwrap();
 619        start..start + part.len()
 620    }
 621}
 622
 623#[gpui::test]
 624fn test_autoindent_with_soft_tabs(cx: &mut MutableAppContext) {
 625    let settings = Settings::test(cx);
 626    cx.set_global(settings);
 627
 628    cx.add_model(|cx| {
 629        let text = "fn a() {}";
 630        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 631
 632        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 633        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 634
 635        buffer.edit(
 636            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 637            Some(AutoindentMode::EachLine),
 638            cx,
 639        );
 640        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 641
 642        // Create a field expression on a new line, causing that line
 643        // to be indented.
 644        buffer.edit(
 645            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 646            Some(AutoindentMode::EachLine),
 647            cx,
 648        );
 649        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 650
 651        // Remove the dot so that the line is no longer a field expression,
 652        // causing the line to be outdented.
 653        buffer.edit(
 654            [(Point::new(2, 8)..Point::new(2, 9), "")],
 655            Some(AutoindentMode::EachLine),
 656            cx,
 657        );
 658        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 659
 660        buffer
 661    });
 662}
 663
 664#[gpui::test]
 665fn test_autoindent_with_hard_tabs(cx: &mut MutableAppContext) {
 666    let mut settings = Settings::test(cx);
 667    settings.editor_overrides.hard_tabs = Some(true);
 668    cx.set_global(settings);
 669
 670    cx.add_model(|cx| {
 671        let text = "fn a() {}";
 672        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 673
 674        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 675        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 676
 677        buffer.edit(
 678            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 679            Some(AutoindentMode::EachLine),
 680            cx,
 681        );
 682        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 683
 684        // Create a field expression on a new line, causing that line
 685        // to be indented.
 686        buffer.edit(
 687            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 688            Some(AutoindentMode::EachLine),
 689            cx,
 690        );
 691        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 692
 693        // Remove the dot so that the line is no longer a field expression,
 694        // causing the line to be outdented.
 695        buffer.edit(
 696            [(Point::new(2, 2)..Point::new(2, 3), "")],
 697            Some(AutoindentMode::EachLine),
 698            cx,
 699        );
 700        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
 701
 702        buffer
 703    });
 704}
 705
 706#[gpui::test]
 707fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 708    let settings = Settings::test(cx);
 709    cx.set_global(settings);
 710
 711    cx.add_model(|cx| {
 712        let text = "
 713            fn a() {
 714            c;
 715            d;
 716            }
 717        "
 718        .unindent();
 719
 720        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 721
 722        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 723        // their indentation is not adjusted.
 724        buffer.edit(
 725            [
 726                (empty(Point::new(1, 1)), "()"),
 727                (empty(Point::new(2, 1)), "()"),
 728            ],
 729            Some(AutoindentMode::EachLine),
 730            cx,
 731        );
 732        assert_eq!(
 733            buffer.text(),
 734            "
 735            fn a() {
 736            c();
 737            d();
 738            }
 739            "
 740            .unindent()
 741        );
 742
 743        // When appending new content after these lines, the indentation is based on the
 744        // preceding lines' actual indentation.
 745        buffer.edit(
 746            [
 747                (empty(Point::new(1, 1)), "\n.f\n.g"),
 748                (empty(Point::new(2, 1)), "\n.f\n.g"),
 749            ],
 750            Some(AutoindentMode::EachLine),
 751            cx,
 752        );
 753        assert_eq!(
 754            buffer.text(),
 755            "
 756            fn a() {
 757            c
 758                .f
 759                .g();
 760            d
 761                .f
 762                .g();
 763            }
 764            "
 765            .unindent()
 766        );
 767        buffer
 768    });
 769
 770    cx.add_model(|cx| {
 771        let text = "
 772            fn a() {
 773                {
 774                    b()?
 775                }
 776                Ok(())
 777            }
 778        "
 779        .unindent();
 780        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 781
 782        // Delete a closing curly brace changes the suggested indent for the line.
 783        buffer.edit(
 784            [(Point::new(3, 4)..Point::new(3, 5), "")],
 785            Some(AutoindentMode::EachLine),
 786            cx,
 787        );
 788        assert_eq!(
 789            buffer.text(),
 790            "
 791            fn a() {
 792                {
 793                    b()?
 794                        |
 795                Ok(())
 796            }
 797            "
 798            .replace('|', "") // included in the string to preserve trailing whites
 799            .unindent()
 800        );
 801
 802        // Manually editing the leading whitespace
 803        buffer.edit(
 804            [(Point::new(3, 0)..Point::new(3, 12), "")],
 805            Some(AutoindentMode::EachLine),
 806            cx,
 807        );
 808        assert_eq!(
 809            buffer.text(),
 810            "
 811            fn a() {
 812                {
 813                    b()?
 814
 815                Ok(())
 816            }
 817            "
 818            .unindent()
 819        );
 820        buffer
 821    });
 822}
 823
 824#[gpui::test]
 825fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 826    cx.set_global(Settings::test(cx));
 827    cx.add_model(|cx| {
 828        let text = "
 829            fn a() {}
 830        "
 831        .unindent();
 832
 833        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 834
 835        buffer.edit([(5..5, "\nb")], Some(AutoindentMode::EachLine), cx);
 836        assert_eq!(
 837            buffer.text(),
 838            "
 839                fn a(
 840                    b) {}
 841            "
 842            .unindent()
 843        );
 844
 845        // The indentation suggestion changed because `@end` node (a close paren)
 846        // is now at the beginning of the line.
 847        buffer.edit(
 848            [(Point::new(1, 4)..Point::new(1, 5), "")],
 849            Some(AutoindentMode::EachLine),
 850            cx,
 851        );
 852        assert_eq!(
 853            buffer.text(),
 854            "
 855                fn a(
 856                ) {}
 857            "
 858            .unindent()
 859        );
 860
 861        buffer
 862    });
 863}
 864
 865#[gpui::test]
 866fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 867    cx.set_global(Settings::test(cx));
 868    cx.add_model(|cx| {
 869        let text = "a\nb";
 870        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 871        buffer.edit(
 872            [(0..1, "\n"), (2..3, "\n")],
 873            Some(AutoindentMode::EachLine),
 874            cx,
 875        );
 876        assert_eq!(buffer.text(), "\n\n\n");
 877        buffer
 878    });
 879}
 880
 881#[gpui::test]
 882fn test_autoindent_multi_line_insertion(cx: &mut MutableAppContext) {
 883    cx.set_global(Settings::test(cx));
 884    cx.add_model(|cx| {
 885        let text = "
 886            const a: usize = 1;
 887            fn b() {
 888                if c {
 889                    let d = 2;
 890                }
 891            }
 892        "
 893        .unindent();
 894
 895        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 896        buffer.edit(
 897            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
 898            Some(AutoindentMode::EachLine),
 899            cx,
 900        );
 901        assert_eq!(
 902            buffer.text(),
 903            "
 904                const a: usize = 1;
 905                fn b() {
 906                    if c {
 907                        e(
 908                            f()
 909                        );
 910                        let d = 2;
 911                    }
 912                }
 913            "
 914            .unindent()
 915        );
 916
 917        buffer
 918    });
 919}
 920
 921#[gpui::test]
 922fn test_autoindent_block_mode(cx: &mut MutableAppContext) {
 923    cx.set_global(Settings::test(cx));
 924    cx.add_model(|cx| {
 925        let text = r#"
 926            fn a() {
 927                b();
 928            }
 929        "#
 930        .unindent();
 931        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 932
 933        let inserted_text = r#"
 934            "
 935              c
 936                d
 937                  e
 938            "
 939        "#
 940        .unindent();
 941
 942        // Insert the block at column zero. The entire block is indented
 943        // so that the first line matches the previous line's indentation.
 944        buffer.edit(
 945            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
 946            Some(AutoindentMode::Block {
 947                original_indent_columns: vec![0],
 948            }),
 949            cx,
 950        );
 951        assert_eq!(
 952            buffer.text(),
 953            r#"
 954            fn a() {
 955                b();
 956                "
 957                  c
 958                    d
 959                      e
 960                "
 961            }
 962            "#
 963            .unindent()
 964        );
 965
 966        // Insert the block at a deeper indent level. The entire block is outdented.
 967        buffer.undo(cx);
 968        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
 969        buffer.edit(
 970            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
 971            Some(AutoindentMode::Block {
 972                original_indent_columns: vec![0],
 973            }),
 974            cx,
 975        );
 976        assert_eq!(
 977            buffer.text(),
 978            r#"
 979            fn a() {
 980                b();
 981                "
 982                  c
 983                    d
 984                      e
 985                "
 986            }
 987            "#
 988            .unindent()
 989        );
 990
 991        buffer
 992    });
 993}
 994
 995#[gpui::test]
 996fn test_autoindent_language_without_indents_query(cx: &mut MutableAppContext) {
 997    cx.set_global(Settings::test(cx));
 998    cx.add_model(|cx| {
 999        let text = "
1000            * one
1001                - a
1002                - b
1003            * two
1004        "
1005        .unindent();
1006
1007        let mut buffer = Buffer::new(0, text, cx).with_language(
1008            Arc::new(Language::new(
1009                LanguageConfig {
1010                    name: "Markdown".into(),
1011                    auto_indent_using_last_non_empty_line: false,
1012                    ..Default::default()
1013                },
1014                Some(tree_sitter_json::language()),
1015            )),
1016            cx,
1017        );
1018        buffer.edit(
1019            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1020            Some(AutoindentMode::EachLine),
1021            cx,
1022        );
1023        assert_eq!(
1024            buffer.text(),
1025            "
1026            * one
1027                - a
1028                - b
1029
1030            * two
1031            "
1032            .unindent()
1033        );
1034        buffer
1035    });
1036}
1037
1038#[gpui::test]
1039fn test_serialization(cx: &mut gpui::MutableAppContext) {
1040    let mut now = Instant::now();
1041
1042    let buffer1 = cx.add_model(|cx| {
1043        let mut buffer = Buffer::new(0, "abc", cx);
1044        buffer.edit([(3..3, "D")], None, cx);
1045
1046        now += Duration::from_secs(1);
1047        buffer.start_transaction_at(now);
1048        buffer.edit([(4..4, "E")], None, cx);
1049        buffer.end_transaction_at(now, cx);
1050        assert_eq!(buffer.text(), "abcDE");
1051
1052        buffer.undo(cx);
1053        assert_eq!(buffer.text(), "abcD");
1054
1055        buffer.edit([(4..4, "F")], None, cx);
1056        assert_eq!(buffer.text(), "abcDF");
1057        buffer
1058    });
1059    assert_eq!(buffer1.read(cx).text(), "abcDF");
1060
1061    let state = buffer1.read(cx).to_proto();
1062    let ops = cx.background().block(buffer1.read(cx).serialize_ops(cx));
1063    let buffer2 = cx.add_model(|cx| {
1064        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1065        buffer
1066            .apply_ops(
1067                ops.into_iter()
1068                    .map(|op| proto::deserialize_operation(op).unwrap()),
1069                cx,
1070            )
1071            .unwrap();
1072        buffer
1073    });
1074    assert_eq!(buffer2.read(cx).text(), "abcDF");
1075}
1076
1077#[gpui::test(iterations = 100)]
1078fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1079    let min_peers = env::var("MIN_PEERS")
1080        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1081        .unwrap_or(1);
1082    let max_peers = env::var("MAX_PEERS")
1083        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1084        .unwrap_or(5);
1085    let operations = env::var("OPERATIONS")
1086        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1087        .unwrap_or(10);
1088
1089    let base_text_len = rng.gen_range(0..10);
1090    let base_text = RandomCharIter::new(&mut rng)
1091        .take(base_text_len)
1092        .collect::<String>();
1093    let mut replica_ids = Vec::new();
1094    let mut buffers = Vec::new();
1095    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1096    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1097
1098    for i in 0..rng.gen_range(min_peers..=max_peers) {
1099        let buffer = cx.add_model(|cx| {
1100            let state = base_buffer.read(cx).to_proto();
1101            let ops = cx
1102                .background()
1103                .block(base_buffer.read(cx).serialize_ops(cx));
1104            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1105            buffer
1106                .apply_ops(
1107                    ops.into_iter()
1108                        .map(|op| proto::deserialize_operation(op).unwrap()),
1109                    cx,
1110                )
1111                .unwrap();
1112            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1113            let network = network.clone();
1114            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1115                if let Event::Operation(op) = event {
1116                    network
1117                        .borrow_mut()
1118                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1119                }
1120            })
1121            .detach();
1122            buffer
1123        });
1124        buffers.push(buffer);
1125        replica_ids.push(i as ReplicaId);
1126        network.borrow_mut().add_peer(i as ReplicaId);
1127        log::info!("Adding initial peer with replica id {}", i);
1128    }
1129
1130    log::info!("initial text: {:?}", base_text);
1131
1132    let mut now = Instant::now();
1133    let mut mutation_count = operations;
1134    let mut next_diagnostic_id = 0;
1135    let mut active_selections = BTreeMap::default();
1136    loop {
1137        let replica_index = rng.gen_range(0..replica_ids.len());
1138        let replica_id = replica_ids[replica_index];
1139        let buffer = &mut buffers[replica_index];
1140        let mut new_buffer = None;
1141        match rng.gen_range(0..100) {
1142            0..=29 if mutation_count != 0 => {
1143                buffer.update(cx, |buffer, cx| {
1144                    buffer.start_transaction_at(now);
1145                    buffer.randomly_edit(&mut rng, 5, cx);
1146                    buffer.end_transaction_at(now, cx);
1147                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1148                });
1149                mutation_count -= 1;
1150            }
1151            30..=39 if mutation_count != 0 => {
1152                buffer.update(cx, |buffer, cx| {
1153                    let mut selections = Vec::new();
1154                    for id in 0..rng.gen_range(1..=5) {
1155                        let range = buffer.random_byte_range(0, &mut rng);
1156                        selections.push(Selection {
1157                            id,
1158                            start: buffer.anchor_before(range.start),
1159                            end: buffer.anchor_before(range.end),
1160                            reversed: false,
1161                            goal: SelectionGoal::None,
1162                        });
1163                    }
1164                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1165                    log::info!(
1166                        "peer {} setting active selections: {:?}",
1167                        replica_id,
1168                        selections
1169                    );
1170                    active_selections.insert(replica_id, selections.clone());
1171                    buffer.set_active_selections(selections, false, cx);
1172                });
1173                mutation_count -= 1;
1174            }
1175            40..=49 if mutation_count != 0 && replica_id == 0 => {
1176                let entry_count = rng.gen_range(1..=5);
1177                buffer.update(cx, |buffer, cx| {
1178                    let diagnostics = DiagnosticSet::new(
1179                        (0..entry_count).map(|_| {
1180                            let range = buffer.random_byte_range(0, &mut rng);
1181                            let range = range.to_point_utf16(buffer);
1182                            DiagnosticEntry {
1183                                range,
1184                                diagnostic: Diagnostic {
1185                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1186                                    ..Default::default()
1187                                },
1188                            }
1189                        }),
1190                        buffer,
1191                    );
1192                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1193                    buffer.update_diagnostics(diagnostics, cx);
1194                });
1195                mutation_count -= 1;
1196            }
1197            50..=59 if replica_ids.len() < max_peers => {
1198                let old_buffer_state = buffer.read(cx).to_proto();
1199                let old_buffer_ops = cx.background().block(buffer.read(cx).serialize_ops(cx));
1200                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1201                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1202                    .choose(&mut rng)
1203                    .unwrap();
1204                log::info!(
1205                    "Adding new replica {} (replicating from {})",
1206                    new_replica_id,
1207                    replica_id
1208                );
1209                new_buffer = Some(cx.add_model(|cx| {
1210                    let mut new_buffer =
1211                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
1212                    new_buffer
1213                        .apply_ops(
1214                            old_buffer_ops
1215                                .into_iter()
1216                                .map(|op| deserialize_operation(op).unwrap()),
1217                            cx,
1218                        )
1219                        .unwrap();
1220                    log::info!(
1221                        "New replica {} text: {:?}",
1222                        new_buffer.replica_id(),
1223                        new_buffer.text()
1224                    );
1225                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1226                    let network = network.clone();
1227                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1228                        if let Event::Operation(op) = event {
1229                            network.borrow_mut().broadcast(
1230                                buffer.replica_id(),
1231                                vec![proto::serialize_operation(op)],
1232                            );
1233                        }
1234                    })
1235                    .detach();
1236                    new_buffer
1237                }));
1238                network.borrow_mut().replicate(replica_id, new_replica_id);
1239
1240                if new_replica_id as usize == replica_ids.len() {
1241                    replica_ids.push(new_replica_id);
1242                } else {
1243                    let new_buffer = new_buffer.take().unwrap();
1244                    while network.borrow().has_unreceived(new_replica_id) {
1245                        let ops = network
1246                            .borrow_mut()
1247                            .receive(new_replica_id)
1248                            .into_iter()
1249                            .map(|op| proto::deserialize_operation(op).unwrap());
1250                        if ops.len() > 0 {
1251                            log::info!(
1252                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1253                                new_replica_id,
1254                                buffer.read(cx).version(),
1255                                ops.len(),
1256                                ops
1257                            );
1258                            new_buffer.update(cx, |new_buffer, cx| {
1259                                new_buffer.apply_ops(ops, cx).unwrap();
1260                            });
1261                        }
1262                    }
1263                    buffers[new_replica_id as usize] = new_buffer;
1264                }
1265            }
1266            60..=69 if mutation_count != 0 => {
1267                buffer.update(cx, |buffer, cx| {
1268                    buffer.randomly_undo_redo(&mut rng, cx);
1269                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1270                });
1271                mutation_count -= 1;
1272            }
1273            _ if network.borrow().has_unreceived(replica_id) => {
1274                let ops = network
1275                    .borrow_mut()
1276                    .receive(replica_id)
1277                    .into_iter()
1278                    .map(|op| proto::deserialize_operation(op).unwrap());
1279                if ops.len() > 0 {
1280                    log::info!(
1281                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1282                        replica_id,
1283                        buffer.read(cx).version(),
1284                        ops.len(),
1285                        ops
1286                    );
1287                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1288                }
1289            }
1290            _ => {}
1291        }
1292
1293        now += Duration::from_millis(rng.gen_range(0..=200));
1294        buffers.extend(new_buffer);
1295
1296        for buffer in &buffers {
1297            buffer.read(cx).check_invariants();
1298        }
1299
1300        if mutation_count == 0 && network.borrow().is_idle() {
1301            break;
1302        }
1303    }
1304
1305    let first_buffer = buffers[0].read(cx).snapshot();
1306    for buffer in &buffers[1..] {
1307        let buffer = buffer.read(cx).snapshot();
1308        assert_eq!(
1309            buffer.version(),
1310            first_buffer.version(),
1311            "Replica {} version != Replica 0 version",
1312            buffer.replica_id()
1313        );
1314        assert_eq!(
1315            buffer.text(),
1316            first_buffer.text(),
1317            "Replica {} text != Replica 0 text",
1318            buffer.replica_id()
1319        );
1320        assert_eq!(
1321            buffer
1322                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1323                .collect::<Vec<_>>(),
1324            first_buffer
1325                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1326                .collect::<Vec<_>>(),
1327            "Replica {} diagnostics != Replica 0 diagnostics",
1328            buffer.replica_id()
1329        );
1330    }
1331
1332    for buffer in &buffers {
1333        let buffer = buffer.read(cx).snapshot();
1334        let actual_remote_selections = buffer
1335            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1336            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1337            .collect::<Vec<_>>();
1338        let expected_remote_selections = active_selections
1339            .iter()
1340            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1341            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1342            .collect::<Vec<_>>();
1343        assert_eq!(
1344            actual_remote_selections,
1345            expected_remote_selections,
1346            "Replica {} remote selections != expected selections",
1347            buffer.replica_id()
1348        );
1349    }
1350}
1351
1352#[test]
1353fn test_contiguous_ranges() {
1354    assert_eq!(
1355        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1356        &[1..4, 5..7, 9..13]
1357    );
1358
1359    // Respects the `max_len` parameter
1360    assert_eq!(
1361        contiguous_ranges(
1362            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1363            3
1364        )
1365        .collect::<Vec<_>>(),
1366        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1367    );
1368}
1369
1370impl Buffer {
1371    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1372        &self,
1373        range: Range<T>,
1374    ) -> Option<(Range<Point>, Range<Point>)> {
1375        self.snapshot()
1376            .enclosing_bracket_ranges(range)
1377            .map(|(start, end)| {
1378                let point_start = start.start.to_point(self)..start.end.to_point(self);
1379                let point_end = end.start.to_point(self)..end.end.to_point(self);
1380                (point_start, point_end)
1381            })
1382    }
1383}
1384
1385fn rust_lang() -> Language {
1386    Language::new(
1387        LanguageConfig {
1388            name: "Rust".into(),
1389            path_suffixes: vec!["rs".to_string()],
1390            ..Default::default()
1391        },
1392        Some(tree_sitter_rust::language()),
1393    )
1394    .with_indents_query(
1395        r#"
1396        (call_expression) @indent
1397        (field_expression) @indent
1398        (_ "(" ")" @end) @indent
1399        (_ "{" "}" @end) @indent
1400        "#,
1401    )
1402    .unwrap()
1403    .with_brackets_query(
1404        r#"
1405        ("{" @open "}" @close)
1406        "#,
1407    )
1408    .unwrap()
1409    .with_outline_query(
1410        r#"
1411        (struct_item
1412            "struct" @context
1413            name: (_) @name) @item
1414        (enum_item
1415            "enum" @context
1416            name: (_) @name) @item
1417        (enum_variant
1418            name: (_) @name) @item
1419        (field_declaration
1420            name: (_) @name) @item
1421        (impl_item
1422            "impl" @context
1423            trait: (_)? @name
1424            "for"? @context
1425            type: (_) @name) @item
1426        (function_item
1427            "fn" @context
1428            name: (_) @name) @item
1429        (mod_item
1430            "mod" @context
1431            name: (_) @name) @item
1432        "#,
1433    )
1434    .unwrap()
1435}
1436
1437fn json_lang() -> Language {
1438    Language::new(
1439        LanguageConfig {
1440            name: "Json".into(),
1441            path_suffixes: vec!["js".to_string()],
1442            ..Default::default()
1443        },
1444        Some(tree_sitter_json::language()),
1445    )
1446}
1447
1448fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1449    buffer.read_with(cx, |buffer, _| {
1450        let snapshot = buffer.snapshot();
1451        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
1452        layers[0].2.to_sexp()
1453    })
1454}
1455
1456fn empty(point: Point) -> Range<Point> {
1457    point..point
1458}