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                    ..Default::default()
1002                },
1003                Some(tree_sitter_json::language()),
1004            )),
1005            cx,
1006        );
1007        buffer.edit(
1008            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1009            Some(AutoindentMode::EachLine),
1010            cx,
1011        );
1012        assert_eq!(
1013            buffer.text(),
1014            "
1015            * one
1016                - a
1017                - b
1018
1019            * two
1020            "
1021            .unindent()
1022        );
1023        buffer
1024    });
1025}
1026
1027#[gpui::test]
1028fn test_serialization(cx: &mut gpui::MutableAppContext) {
1029    let mut now = Instant::now();
1030
1031    let buffer1 = cx.add_model(|cx| {
1032        let mut buffer = Buffer::new(0, "abc", cx);
1033        buffer.edit([(3..3, "D")], None, cx);
1034
1035        now += Duration::from_secs(1);
1036        buffer.start_transaction_at(now);
1037        buffer.edit([(4..4, "E")], None, cx);
1038        buffer.end_transaction_at(now, cx);
1039        assert_eq!(buffer.text(), "abcDE");
1040
1041        buffer.undo(cx);
1042        assert_eq!(buffer.text(), "abcD");
1043
1044        buffer.edit([(4..4, "F")], None, cx);
1045        assert_eq!(buffer.text(), "abcDF");
1046        buffer
1047    });
1048    assert_eq!(buffer1.read(cx).text(), "abcDF");
1049
1050    let message = buffer1.read(cx).to_proto();
1051    let buffer2 = cx.add_model(|cx| Buffer::from_proto(1, message, None, cx).unwrap());
1052    assert_eq!(buffer2.read(cx).text(), "abcDF");
1053}
1054
1055#[gpui::test(iterations = 100)]
1056fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
1057    let min_peers = env::var("MIN_PEERS")
1058        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1059        .unwrap_or(1);
1060    let max_peers = env::var("MAX_PEERS")
1061        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1062        .unwrap_or(5);
1063    let operations = env::var("OPERATIONS")
1064        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1065        .unwrap_or(10);
1066
1067    let base_text_len = rng.gen_range(0..10);
1068    let base_text = RandomCharIter::new(&mut rng)
1069        .take(base_text_len)
1070        .collect::<String>();
1071    let mut replica_ids = Vec::new();
1072    let mut buffers = Vec::new();
1073    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
1074    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
1075
1076    for i in 0..rng.gen_range(min_peers..=max_peers) {
1077        let buffer = cx.add_model(|cx| {
1078            let mut buffer =
1079                Buffer::from_proto(i as ReplicaId, base_buffer.read(cx).to_proto(), None, cx)
1080                    .unwrap();
1081            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1082            let network = network.clone();
1083            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1084                if let Event::Operation(op) = event {
1085                    network
1086                        .borrow_mut()
1087                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1088                }
1089            })
1090            .detach();
1091            buffer
1092        });
1093        buffers.push(buffer);
1094        replica_ids.push(i as ReplicaId);
1095        network.borrow_mut().add_peer(i as ReplicaId);
1096        log::info!("Adding initial peer with replica id {}", i);
1097    }
1098
1099    log::info!("initial text: {:?}", base_text);
1100
1101    let mut now = Instant::now();
1102    let mut mutation_count = operations;
1103    let mut next_diagnostic_id = 0;
1104    let mut active_selections = BTreeMap::default();
1105    loop {
1106        let replica_index = rng.gen_range(0..replica_ids.len());
1107        let replica_id = replica_ids[replica_index];
1108        let buffer = &mut buffers[replica_index];
1109        let mut new_buffer = None;
1110        match rng.gen_range(0..100) {
1111            0..=29 if mutation_count != 0 => {
1112                buffer.update(cx, |buffer, cx| {
1113                    buffer.start_transaction_at(now);
1114                    buffer.randomly_edit(&mut rng, 5, cx);
1115                    buffer.end_transaction_at(now, cx);
1116                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1117                });
1118                mutation_count -= 1;
1119            }
1120            30..=39 if mutation_count != 0 => {
1121                buffer.update(cx, |buffer, cx| {
1122                    let mut selections = Vec::new();
1123                    for id in 0..rng.gen_range(1..=5) {
1124                        let range = buffer.random_byte_range(0, &mut rng);
1125                        selections.push(Selection {
1126                            id,
1127                            start: buffer.anchor_before(range.start),
1128                            end: buffer.anchor_before(range.end),
1129                            reversed: false,
1130                            goal: SelectionGoal::None,
1131                        });
1132                    }
1133                    let selections: Arc<[Selection<Anchor>]> = selections.into();
1134                    log::info!(
1135                        "peer {} setting active selections: {:?}",
1136                        replica_id,
1137                        selections
1138                    );
1139                    active_selections.insert(replica_id, selections.clone());
1140                    buffer.set_active_selections(selections, false, cx);
1141                });
1142                mutation_count -= 1;
1143            }
1144            40..=49 if mutation_count != 0 && replica_id == 0 => {
1145                let entry_count = rng.gen_range(1..=5);
1146                buffer.update(cx, |buffer, cx| {
1147                    let diagnostics = DiagnosticSet::new(
1148                        (0..entry_count).map(|_| {
1149                            let range = buffer.random_byte_range(0, &mut rng);
1150                            let range = range.to_point_utf16(buffer);
1151                            DiagnosticEntry {
1152                                range,
1153                                diagnostic: Diagnostic {
1154                                    message: post_inc(&mut next_diagnostic_id).to_string(),
1155                                    ..Default::default()
1156                                },
1157                            }
1158                        }),
1159                        buffer,
1160                    );
1161                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
1162                    buffer.update_diagnostics(diagnostics, cx);
1163                });
1164                mutation_count -= 1;
1165            }
1166            50..=59 if replica_ids.len() < max_peers => {
1167                let old_buffer = buffer.read(cx).to_proto();
1168                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
1169                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
1170                    .choose(&mut rng)
1171                    .unwrap();
1172                log::info!(
1173                    "Adding new replica {} (replicating from {})",
1174                    new_replica_id,
1175                    replica_id
1176                );
1177                new_buffer = Some(cx.add_model(|cx| {
1178                    let mut new_buffer =
1179                        Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap();
1180                    log::info!(
1181                        "New replica {} text: {:?}",
1182                        new_buffer.replica_id(),
1183                        new_buffer.text()
1184                    );
1185                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1186                    let network = network.clone();
1187                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1188                        if let Event::Operation(op) = event {
1189                            network.borrow_mut().broadcast(
1190                                buffer.replica_id(),
1191                                vec![proto::serialize_operation(op)],
1192                            );
1193                        }
1194                    })
1195                    .detach();
1196                    new_buffer
1197                }));
1198                network.borrow_mut().replicate(replica_id, new_replica_id);
1199
1200                if new_replica_id as usize == replica_ids.len() {
1201                    replica_ids.push(new_replica_id);
1202                } else {
1203                    let new_buffer = new_buffer.take().unwrap();
1204                    while network.borrow().has_unreceived(new_replica_id) {
1205                        let ops = network
1206                            .borrow_mut()
1207                            .receive(new_replica_id)
1208                            .into_iter()
1209                            .map(|op| proto::deserialize_operation(op).unwrap());
1210                        if ops.len() > 0 {
1211                            log::info!(
1212                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1213                                new_replica_id,
1214                                buffer.read(cx).version(),
1215                                ops.len(),
1216                                ops
1217                            );
1218                            new_buffer.update(cx, |new_buffer, cx| {
1219                                new_buffer.apply_ops(ops, cx).unwrap();
1220                            });
1221                        }
1222                    }
1223                    buffers[new_replica_id as usize] = new_buffer;
1224                }
1225            }
1226            60..=69 if mutation_count != 0 => {
1227                buffer.update(cx, |buffer, cx| {
1228                    buffer.randomly_undo_redo(&mut rng, cx);
1229                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
1230                });
1231                mutation_count -= 1;
1232            }
1233            _ if network.borrow().has_unreceived(replica_id) => {
1234                let ops = network
1235                    .borrow_mut()
1236                    .receive(replica_id)
1237                    .into_iter()
1238                    .map(|op| proto::deserialize_operation(op).unwrap());
1239                if ops.len() > 0 {
1240                    log::info!(
1241                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
1242                        replica_id,
1243                        buffer.read(cx).version(),
1244                        ops.len(),
1245                        ops
1246                    );
1247                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
1248                }
1249            }
1250            _ => {}
1251        }
1252
1253        now += Duration::from_millis(rng.gen_range(0..=200));
1254        buffers.extend(new_buffer);
1255
1256        for buffer in &buffers {
1257            buffer.read(cx).check_invariants();
1258        }
1259
1260        if mutation_count == 0 && network.borrow().is_idle() {
1261            break;
1262        }
1263    }
1264
1265    let first_buffer = buffers[0].read(cx).snapshot();
1266    for buffer in &buffers[1..] {
1267        let buffer = buffer.read(cx).snapshot();
1268        assert_eq!(
1269            buffer.version(),
1270            first_buffer.version(),
1271            "Replica {} version != Replica 0 version",
1272            buffer.replica_id()
1273        );
1274        assert_eq!(
1275            buffer.text(),
1276            first_buffer.text(),
1277            "Replica {} text != Replica 0 text",
1278            buffer.replica_id()
1279        );
1280        assert_eq!(
1281            buffer
1282                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
1283                .collect::<Vec<_>>(),
1284            first_buffer
1285                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
1286                .collect::<Vec<_>>(),
1287            "Replica {} diagnostics != Replica 0 diagnostics",
1288            buffer.replica_id()
1289        );
1290    }
1291
1292    for buffer in &buffers {
1293        let buffer = buffer.read(cx).snapshot();
1294        let actual_remote_selections = buffer
1295            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1296            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
1297            .collect::<Vec<_>>();
1298        let expected_remote_selections = active_selections
1299            .iter()
1300            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
1301            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
1302            .collect::<Vec<_>>();
1303        assert_eq!(
1304            actual_remote_selections,
1305            expected_remote_selections,
1306            "Replica {} remote selections != expected selections",
1307            buffer.replica_id()
1308        );
1309    }
1310}
1311
1312#[test]
1313fn test_contiguous_ranges() {
1314    assert_eq!(
1315        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1316        &[1..4, 5..7, 9..13]
1317    );
1318
1319    // Respects the `max_len` parameter
1320    assert_eq!(
1321        contiguous_ranges(
1322            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1323            3
1324        )
1325        .collect::<Vec<_>>(),
1326        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1327    );
1328}
1329
1330impl Buffer {
1331    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1332        &self,
1333        range: Range<T>,
1334    ) -> Option<(Range<Point>, Range<Point>)> {
1335        self.snapshot()
1336            .enclosing_bracket_ranges(range)
1337            .map(|(start, end)| {
1338                let point_start = start.start.to_point(self)..start.end.to_point(self);
1339                let point_end = end.start.to_point(self)..end.end.to_point(self);
1340                (point_start, point_end)
1341            })
1342    }
1343}
1344
1345fn rust_lang() -> Language {
1346    Language::new(
1347        LanguageConfig {
1348            name: "Rust".into(),
1349            path_suffixes: vec!["rs".to_string()],
1350            ..Default::default()
1351        },
1352        Some(tree_sitter_rust::language()),
1353    )
1354    .with_indents_query(
1355        r#"
1356        (call_expression) @indent
1357        (field_expression) @indent
1358        (_ "(" ")" @end) @indent
1359        (_ "{" "}" @end) @indent
1360        "#,
1361    )
1362    .unwrap()
1363    .with_brackets_query(
1364        r#"
1365        ("{" @open "}" @close)
1366        "#,
1367    )
1368    .unwrap()
1369    .with_outline_query(
1370        r#"
1371        (struct_item
1372            "struct" @context
1373            name: (_) @name) @item
1374        (enum_item
1375            "enum" @context
1376            name: (_) @name) @item
1377        (enum_variant
1378            name: (_) @name) @item
1379        (field_declaration
1380            name: (_) @name) @item
1381        (impl_item
1382            "impl" @context
1383            trait: (_)? @name
1384            "for"? @context
1385            type: (_) @name) @item
1386        (function_item
1387            "fn" @context
1388            name: (_) @name) @item
1389        (mod_item
1390            "mod" @context
1391            name: (_) @name) @item
1392        "#,
1393    )
1394    .unwrap()
1395}
1396
1397fn json_lang() -> Language {
1398    Language::new(
1399        LanguageConfig {
1400            name: "Json".into(),
1401            path_suffixes: vec!["js".to_string()],
1402            ..Default::default()
1403        },
1404        Some(tree_sitter_json::language()),
1405    )
1406}
1407
1408fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1409    buffer.read_with(cx, |buffer, _| {
1410        let syntax_map = buffer.syntax_map();
1411        let layers = syntax_map.layers(buffer.as_text_snapshot());
1412        layers[0].2.to_sexp()
1413    })
1414}
1415
1416fn empty(point: Point) -> Range<Point> {
1417    point..point
1418}