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