tests.rs

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