buffer_tests.rs

   1use super::*;
   2use crate::language_settings::{
   3    AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent,
   4};
   5use crate::Buffer;
   6use clock::ReplicaId;
   7use collections::BTreeMap;
   8use gpui::{AppContext, Model};
   9use gpui::{Context, TestAppContext};
  10use indoc::indoc;
  11use proto::deserialize_operation;
  12use rand::prelude::*;
  13use regex::RegexBuilder;
  14use settings::SettingsStore;
  15use std::{
  16    env,
  17    ops::Range,
  18    time::{Duration, Instant},
  19};
  20use text::network::Network;
  21use text::LineEnding;
  22use text::{Point, ToPoint};
  23use unindent::Unindent as _;
  24use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
  25
  26lazy_static! {
  27    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
  28        .multi_line(true)
  29        .build()
  30        .unwrap();
  31}
  32
  33#[cfg(test)]
  34#[ctor::ctor]
  35fn init_logger() {
  36    if std::env::var("RUST_LOG").is_ok() {
  37        env_logger::init();
  38    }
  39}
  40
  41#[gpui::test]
  42fn test_line_endings(cx: &mut gpui::AppContext) {
  43    init_settings(cx, |_| {});
  44
  45    cx.new_model(|cx| {
  46        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "one\r\ntwo\rthree")
  47            .with_language(Arc::new(rust_lang()), cx);
  48        assert_eq!(buffer.text(), "one\ntwo\nthree");
  49        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  50
  51        buffer.check_invariants();
  52        buffer.edit(
  53            [(buffer.len()..buffer.len(), "\r\nfour")],
  54            Some(AutoindentMode::EachLine),
  55            cx,
  56        );
  57        buffer.edit([(0..0, "zero\r\n")], None, cx);
  58        assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
  59        assert_eq!(buffer.line_ending(), LineEnding::Windows);
  60        buffer.check_invariants();
  61
  62        buffer
  63    });
  64}
  65
  66#[gpui::test]
  67fn test_select_language() {
  68    let registry = Arc::new(LanguageRegistry::test());
  69    registry.add(Arc::new(Language::new(
  70        LanguageConfig {
  71            name: "Rust".into(),
  72            path_suffixes: vec!["rs".to_string()],
  73            ..Default::default()
  74        },
  75        Some(tree_sitter_rust::language()),
  76    )));
  77    registry.add(Arc::new(Language::new(
  78        LanguageConfig {
  79            name: "Make".into(),
  80            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  81            ..Default::default()
  82        },
  83        Some(tree_sitter_rust::language()),
  84    )));
  85
  86    // matching file extension
  87    assert_eq!(
  88        registry
  89            .language_for_file("zed/lib.rs", None)
  90            .now_or_never()
  91            .and_then(|l| Some(l.ok()?.name())),
  92        Some("Rust".into())
  93    );
  94    assert_eq!(
  95        registry
  96            .language_for_file("zed/lib.mk", None)
  97            .now_or_never()
  98            .and_then(|l| Some(l.ok()?.name())),
  99        Some("Make".into())
 100    );
 101
 102    // matching filename
 103    assert_eq!(
 104        registry
 105            .language_for_file("zed/Makefile", None)
 106            .now_or_never()
 107            .and_then(|l| Some(l.ok()?.name())),
 108        Some("Make".into())
 109    );
 110
 111    // matching suffix that is not the full file extension or filename
 112    assert_eq!(
 113        registry
 114            .language_for_file("zed/cars", None)
 115            .now_or_never()
 116            .and_then(|l| Some(l.ok()?.name())),
 117        None
 118    );
 119    assert_eq!(
 120        registry
 121            .language_for_file("zed/a.cars", None)
 122            .now_or_never()
 123            .and_then(|l| Some(l.ok()?.name())),
 124        None
 125    );
 126    assert_eq!(
 127        registry
 128            .language_for_file("zed/sumk", None)
 129            .now_or_never()
 130            .and_then(|l| Some(l.ok()?.name())),
 131        None
 132    );
 133}
 134
 135#[gpui::test]
 136fn test_edit_events(cx: &mut gpui::AppContext) {
 137    let mut now = Instant::now();
 138    let buffer_1_events = Arc::new(Mutex::new(Vec::new()));
 139    let buffer_2_events = Arc::new(Mutex::new(Vec::new()));
 140
 141    let buffer1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef"));
 142    let buffer2 = cx.new_model(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef"));
 143    let buffer1_ops = Arc::new(Mutex::new(Vec::new()));
 144    buffer1.update(cx, {
 145        let buffer1_ops = buffer1_ops.clone();
 146        |buffer, cx| {
 147            let buffer_1_events = buffer_1_events.clone();
 148            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
 149                Event::Operation(op) => buffer1_ops.lock().push(op),
 150                event => buffer_1_events.lock().push(event),
 151            })
 152            .detach();
 153            let buffer_2_events = buffer_2_events.clone();
 154            cx.subscribe(&buffer2, move |_, _, event, _| {
 155                buffer_2_events.lock().push(event.clone())
 156            })
 157            .detach();
 158
 159            // An edit emits an edited event, followed by a dirty changed event,
 160            // since the buffer was previously in a clean state.
 161            buffer.edit([(2..4, "XYZ")], None, cx);
 162
 163            // An empty transaction does not emit any events.
 164            buffer.start_transaction();
 165            buffer.end_transaction(cx);
 166
 167            // A transaction containing two edits emits one edited event.
 168            now += Duration::from_secs(1);
 169            buffer.start_transaction_at(now);
 170            buffer.edit([(5..5, "u")], None, cx);
 171            buffer.edit([(6..6, "w")], None, cx);
 172            buffer.end_transaction_at(now, cx);
 173
 174            // Undoing a transaction emits one edited event.
 175            buffer.undo(cx);
 176        }
 177    });
 178
 179    // Incorporating a set of remote ops emits a single edited event,
 180    // followed by a dirty changed event.
 181    buffer2.update(cx, |buffer, cx| {
 182        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 183    });
 184    assert_eq!(
 185        mem::take(&mut *buffer_1_events.lock()),
 186        vec![
 187            Event::Edited,
 188            Event::DirtyChanged,
 189            Event::Edited,
 190            Event::Edited,
 191        ]
 192    );
 193    assert_eq!(
 194        mem::take(&mut *buffer_2_events.lock()),
 195        vec![Event::Edited, Event::DirtyChanged]
 196    );
 197
 198    buffer1.update(cx, |buffer, cx| {
 199        // Undoing the first transaction emits edited event, followed by a
 200        // dirty changed event, since the buffer is again in a clean state.
 201        buffer.undo(cx);
 202    });
 203    // Incorporating the remote ops again emits a single edited event,
 204    // followed by a dirty changed event.
 205    buffer2.update(cx, |buffer, cx| {
 206        buffer.apply_ops(buffer1_ops.lock().drain(..), cx).unwrap();
 207    });
 208    assert_eq!(
 209        mem::take(&mut *buffer_1_events.lock()),
 210        vec![Event::Edited, Event::DirtyChanged,]
 211    );
 212    assert_eq!(
 213        mem::take(&mut *buffer_2_events.lock()),
 214        vec![Event::Edited, Event::DirtyChanged]
 215    );
 216}
 217
 218#[gpui::test]
 219async fn test_apply_diff(cx: &mut TestAppContext) {
 220    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 221    let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
 222    let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3)));
 223
 224    let text = "a\nccc\ndddd\nffffff\n";
 225    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 226    buffer.update(cx, |buffer, cx| {
 227        buffer.apply_diff(diff, cx).unwrap();
 228        assert_eq!(buffer.text(), text);
 229        assert_eq!(anchor.to_point(buffer), Point::new(2, 3));
 230    });
 231
 232    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 233    let diff = buffer.update(cx, |b, cx| b.diff(text.into(), cx)).await;
 234    buffer.update(cx, |buffer, cx| {
 235        buffer.apply_diff(diff, cx).unwrap();
 236        assert_eq!(buffer.text(), text);
 237        assert_eq!(anchor.to_point(buffer), Point::new(4, 4));
 238    });
 239}
 240
 241#[gpui::test(iterations = 10)]
 242async fn test_normalize_whitespace(cx: &mut gpui::TestAppContext) {
 243    let text = [
 244        "zero",     //
 245        "one  ",    // 2 trailing spaces
 246        "two",      //
 247        "three   ", // 3 trailing spaces
 248        "four",     //
 249        "five    ", // 4 trailing spaces
 250    ]
 251    .join("\n");
 252
 253    let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
 254
 255    // Spawn a task to format the buffer's whitespace.
 256    // Pause so that the foratting task starts running.
 257    let format = buffer.update(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx));
 258    smol::future::yield_now().await;
 259
 260    // Edit the buffer while the normalization task is running.
 261    let version_before_edit = buffer.update(cx, |buffer, _| buffer.version());
 262    buffer.update(cx, |buffer, cx| {
 263        buffer.edit(
 264            [
 265                (Point::new(0, 1)..Point::new(0, 1), "EE"),
 266                (Point::new(3, 5)..Point::new(3, 5), "EEE"),
 267            ],
 268            None,
 269            cx,
 270        );
 271    });
 272
 273    let format_diff = format.await;
 274    buffer.update(cx, |buffer, cx| {
 275        let version_before_format = format_diff.base_version.clone();
 276        buffer.apply_diff(format_diff, cx);
 277
 278        // The outcome depends on the order of concurrent taks.
 279        //
 280        // If the edit occurred while searching for trailing whitespace ranges,
 281        // then the trailing whitespace region touched by the edit is left intact.
 282        if version_before_format == version_before_edit {
 283            assert_eq!(
 284                buffer.text(),
 285                [
 286                    "zEEero",      //
 287                    "one",         //
 288                    "two",         //
 289                    "threeEEE   ", //
 290                    "four",        //
 291                    "five",        //
 292                ]
 293                .join("\n")
 294            );
 295        }
 296        // Otherwise, all trailing whitespace is removed.
 297        else {
 298            assert_eq!(
 299                buffer.text(),
 300                [
 301                    "zEEero",   //
 302                    "one",      //
 303                    "two",      //
 304                    "threeEEE", //
 305                    "four",     //
 306                    "five",     //
 307                ]
 308                .join("\n")
 309            );
 310        }
 311    });
 312}
 313
 314#[gpui::test]
 315async fn test_reparse(cx: &mut gpui::TestAppContext) {
 316    let text = "fn a() {}";
 317    let buffer = cx.new_model(|cx| {
 318        Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
 319    });
 320
 321    // Wait for the initial text to parse
 322    cx.executor().run_until_parked();
 323    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 324    assert_eq!(
 325        get_tree_sexp(&buffer, cx),
 326        concat!(
 327            "(source_file (function_item name: (identifier) ",
 328            "parameters: (parameters) ",
 329            "body: (block)))"
 330        )
 331    );
 332
 333    buffer.update(cx, |buffer, _| {
 334        buffer.set_sync_parse_timeout(Duration::ZERO)
 335    });
 336
 337    // Perform some edits (add parameter and variable reference)
 338    // Parsing doesn't begin until the transaction is complete
 339    buffer.update(cx, |buf, cx| {
 340        buf.start_transaction();
 341
 342        let offset = buf.text().find(')').unwrap();
 343        buf.edit([(offset..offset, "b: C")], None, cx);
 344        assert!(!buf.is_parsing());
 345
 346        let offset = buf.text().find('}').unwrap();
 347        buf.edit([(offset..offset, " d; ")], None, cx);
 348        assert!(!buf.is_parsing());
 349
 350        buf.end_transaction(cx);
 351        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 352        assert!(buf.is_parsing());
 353    });
 354    cx.executor().run_until_parked();
 355    assert!(!buffer.update(cx, |buffer, _| buffer.is_parsing()));
 356    assert_eq!(
 357        get_tree_sexp(&buffer, cx),
 358        concat!(
 359            "(source_file (function_item name: (identifier) ",
 360            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 361            "body: (block (expression_statement (identifier)))))"
 362        )
 363    );
 364
 365    // Perform a series of edits without waiting for the current parse to complete:
 366    // * turn identifier into a field expression
 367    // * turn field expression into a method call
 368    // * add a turbofish to the method call
 369    buffer.update(cx, |buf, cx| {
 370        let offset = buf.text().find(';').unwrap();
 371        buf.edit([(offset..offset, ".e")], None, cx);
 372        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 373        assert!(buf.is_parsing());
 374    });
 375    buffer.update(cx, |buf, cx| {
 376        let offset = buf.text().find(';').unwrap();
 377        buf.edit([(offset..offset, "(f)")], None, cx);
 378        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 379        assert!(buf.is_parsing());
 380    });
 381    buffer.update(cx, |buf, cx| {
 382        let offset = buf.text().find("(f)").unwrap();
 383        buf.edit([(offset..offset, "::<G>")], None, cx);
 384        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 385        assert!(buf.is_parsing());
 386    });
 387    cx.executor().run_until_parked();
 388    assert_eq!(
 389        get_tree_sexp(&buffer, cx),
 390        concat!(
 391            "(source_file (function_item name: (identifier) ",
 392            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 393            "body: (block (expression_statement (call_expression ",
 394            "function: (generic_function ",
 395            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 396            "type_arguments: (type_arguments (type_identifier))) ",
 397            "arguments: (arguments (identifier)))))))",
 398        )
 399    );
 400
 401    buffer.update(cx, |buf, cx| {
 402        buf.undo(cx);
 403        buf.undo(cx);
 404        buf.undo(cx);
 405        buf.undo(cx);
 406        assert_eq!(buf.text(), "fn a() {}");
 407        assert!(buf.is_parsing());
 408    });
 409
 410    cx.executor().run_until_parked();
 411    assert_eq!(
 412        get_tree_sexp(&buffer, cx),
 413        concat!(
 414            "(source_file (function_item name: (identifier) ",
 415            "parameters: (parameters) ",
 416            "body: (block)))"
 417        )
 418    );
 419
 420    buffer.update(cx, |buf, cx| {
 421        buf.redo(cx);
 422        buf.redo(cx);
 423        buf.redo(cx);
 424        buf.redo(cx);
 425        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 426        assert!(buf.is_parsing());
 427    });
 428    cx.executor().run_until_parked();
 429    assert_eq!(
 430        get_tree_sexp(&buffer, cx),
 431        concat!(
 432            "(source_file (function_item name: (identifier) ",
 433            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 434            "body: (block (expression_statement (call_expression ",
 435            "function: (generic_function ",
 436            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 437            "type_arguments: (type_arguments (type_identifier))) ",
 438            "arguments: (arguments (identifier)))))))",
 439        )
 440    );
 441}
 442
 443#[gpui::test]
 444async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 445    let buffer = cx.new_model(|cx| {
 446        let mut buffer =
 447            Buffer::new(0, cx.entity_id().as_u64(), "{}").with_language(Arc::new(rust_lang()), cx);
 448        buffer.set_sync_parse_timeout(Duration::ZERO);
 449        buffer
 450    });
 451
 452    // Wait for the initial text to parse
 453    cx.executor().run_until_parked();
 454    assert_eq!(
 455        get_tree_sexp(&buffer, cx),
 456        "(source_file (expression_statement (block)))"
 457    );
 458
 459    buffer.update(cx, |buffer, cx| {
 460        buffer.set_language(Some(Arc::new(json_lang())), cx)
 461    });
 462    cx.executor().run_until_parked();
 463    assert_eq!(get_tree_sexp(&buffer, cx), "(document (object))");
 464}
 465
 466#[gpui::test]
 467async fn test_outline(cx: &mut gpui::TestAppContext) {
 468    let text = r#"
 469        struct Person {
 470            name: String,
 471            age: usize,
 472        }
 473
 474        mod module {
 475            enum LoginState {
 476                LoggedOut,
 477                LoggingOn,
 478                LoggedIn {
 479                    person: Person,
 480                    time: Instant,
 481                }
 482            }
 483        }
 484
 485        impl Eq for Person {}
 486
 487        impl Drop for Person {
 488            fn drop(&mut self) {
 489                println!("bye");
 490            }
 491        }
 492    "#
 493    .unindent();
 494
 495    let buffer = cx.new_model(|cx| {
 496        Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
 497    });
 498    let outline = buffer
 499        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 500        .unwrap();
 501
 502    assert_eq!(
 503        outline
 504            .items
 505            .iter()
 506            .map(|item| (item.text.as_str(), item.depth))
 507            .collect::<Vec<_>>(),
 508        &[
 509            ("struct Person", 0),
 510            ("name", 1),
 511            ("age", 1),
 512            ("mod module", 0),
 513            ("enum LoginState", 1),
 514            ("LoggedOut", 2),
 515            ("LoggingOn", 2),
 516            ("LoggedIn", 2),
 517            ("person", 3),
 518            ("time", 3),
 519            ("impl Eq for Person", 0),
 520            ("impl Drop for Person", 0),
 521            ("fn drop", 1),
 522        ]
 523    );
 524
 525    // Without space, we only match on names
 526    assert_eq!(
 527        search(&outline, "oon", cx).await,
 528        &[
 529            ("mod module", vec![]),                    // included as the parent of a match
 530            ("enum LoginState", vec![]),               // included as the parent of a match
 531            ("LoggingOn", vec![1, 7, 8]),              // matches
 532            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 533        ]
 534    );
 535
 536    assert_eq!(
 537        search(&outline, "dp p", cx).await,
 538        &[
 539            ("impl Drop for Person", vec![5, 8, 9, 14]),
 540            ("fn drop", vec![]),
 541        ]
 542    );
 543    assert_eq!(
 544        search(&outline, "dpn", cx).await,
 545        &[("impl Drop for Person", vec![5, 14, 19])]
 546    );
 547    assert_eq!(
 548        search(&outline, "impl ", cx).await,
 549        &[
 550            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 551            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 552            ("fn drop", vec![]),
 553        ]
 554    );
 555
 556    async fn search<'a>(
 557        outline: &'a Outline<Anchor>,
 558        query: &'a str,
 559        cx: &'a gpui::TestAppContext,
 560    ) -> Vec<(&'a str, Vec<usize>)> {
 561        let matches = cx
 562            .update(|cx| outline.search(query, cx.background_executor().clone()))
 563            .await;
 564        matches
 565            .into_iter()
 566            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 567            .collect::<Vec<_>>()
 568    }
 569}
 570
 571#[gpui::test]
 572async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
 573    let text = r#"
 574        impl A for B<
 575            C
 576        > {
 577        };
 578    "#
 579    .unindent();
 580
 581    let buffer = cx.new_model(|cx| {
 582        Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
 583    });
 584    let outline = buffer
 585        .update(cx, |buffer, _| buffer.snapshot().outline(None))
 586        .unwrap();
 587
 588    assert_eq!(
 589        outline
 590            .items
 591            .iter()
 592            .map(|item| (item.text.as_str(), item.depth))
 593            .collect::<Vec<_>>(),
 594        &[("impl A for B<", 0)]
 595    );
 596}
 597
 598#[gpui::test]
 599async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
 600    let language = javascript_lang()
 601        .with_outline_query(
 602            r#"
 603            (function_declaration
 604                "function" @context
 605                name: (_) @name
 606                parameters: (formal_parameters
 607                    "(" @context.extra
 608                    ")" @context.extra)) @item
 609            "#,
 610        )
 611        .unwrap();
 612
 613    let text = r#"
 614        function a() {}
 615        function b(c) {}
 616    "#
 617    .unindent();
 618
 619    let buffer = cx.new_model(|cx| {
 620        Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(language), cx)
 621    });
 622    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 623
 624    // extra context nodes are included in the outline.
 625    let outline = snapshot.outline(None).unwrap();
 626    assert_eq!(
 627        outline
 628            .items
 629            .iter()
 630            .map(|item| (item.text.as_str(), item.depth))
 631            .collect::<Vec<_>>(),
 632        &[("function a()", 0), ("function b( )", 0),]
 633    );
 634
 635    // extra context nodes do not appear in breadcrumbs.
 636    let symbols = snapshot.symbols_containing(3, None).unwrap();
 637    assert_eq!(
 638        symbols
 639            .iter()
 640            .map(|item| (item.text.as_str(), item.depth))
 641            .collect::<Vec<_>>(),
 642        &[("function a", 0)]
 643    );
 644}
 645
 646#[gpui::test]
 647async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 648    let text = r#"
 649        impl Person {
 650            fn one() {
 651                1
 652            }
 653
 654            fn two() {
 655                2
 656            }fn three() {
 657                3
 658            }
 659        }
 660    "#
 661    .unindent();
 662
 663    let buffer = cx.new_model(|cx| {
 664        Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx)
 665    });
 666    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
 667
 668    // point is at the start of an item
 669    assert_eq!(
 670        symbols_containing(Point::new(1, 4), &snapshot),
 671        vec![
 672            (
 673                "impl Person".to_string(),
 674                Point::new(0, 0)..Point::new(10, 1)
 675            ),
 676            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 677        ]
 678    );
 679
 680    // point is in the middle of an item
 681    assert_eq!(
 682        symbols_containing(Point::new(2, 8), &snapshot),
 683        vec![
 684            (
 685                "impl Person".to_string(),
 686                Point::new(0, 0)..Point::new(10, 1)
 687            ),
 688            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 689        ]
 690    );
 691
 692    // point is at the end of an item
 693    assert_eq!(
 694        symbols_containing(Point::new(3, 5), &snapshot),
 695        vec![
 696            (
 697                "impl Person".to_string(),
 698                Point::new(0, 0)..Point::new(10, 1)
 699            ),
 700            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 701        ]
 702    );
 703
 704    // point is in between two adjacent items
 705    assert_eq!(
 706        symbols_containing(Point::new(7, 5), &snapshot),
 707        vec![
 708            (
 709                "impl Person".to_string(),
 710                Point::new(0, 0)..Point::new(10, 1)
 711            ),
 712            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 713        ]
 714    );
 715
 716    fn symbols_containing(
 717        position: Point,
 718        snapshot: &BufferSnapshot,
 719    ) -> Vec<(String, Range<Point>)> {
 720        snapshot
 721            .symbols_containing(position, None)
 722            .unwrap()
 723            .into_iter()
 724            .map(|item| {
 725                (
 726                    item.text,
 727                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 728                )
 729            })
 730            .collect()
 731    }
 732}
 733
 734#[gpui::test]
 735fn test_enclosing_bracket_ranges(cx: &mut AppContext) {
 736    let mut assert = |selection_text, range_markers| {
 737        assert_bracket_pairs(selection_text, range_markers, rust_lang(), cx)
 738    };
 739
 740    assert(
 741        indoc! {"
 742            mod x {
 743                moˇd y {
 744
 745                }
 746            }
 747            let foo = 1;"},
 748        vec![indoc! {"
 749            mod x «{»
 750                mod y {
 751
 752                }
 753            «}»
 754            let foo = 1;"}],
 755    );
 756
 757    assert(
 758        indoc! {"
 759            mod x {
 760                mod y ˇ{
 761
 762                }
 763            }
 764            let foo = 1;"},
 765        vec![
 766            indoc! {"
 767                mod x «{»
 768                    mod y {
 769
 770                    }
 771                «}»
 772                let foo = 1;"},
 773            indoc! {"
 774                mod x {
 775                    mod y «{»
 776
 777                    «}»
 778                }
 779                let foo = 1;"},
 780        ],
 781    );
 782
 783    assert(
 784        indoc! {"
 785            mod x {
 786                mod y {
 787
 788 789            }
 790            let foo = 1;"},
 791        vec![
 792            indoc! {"
 793                mod x «{»
 794                    mod y {
 795
 796                    }
 797                «}»
 798                let foo = 1;"},
 799            indoc! {"
 800                mod x {
 801                    mod y «{»
 802
 803                    «}»
 804                }
 805                let foo = 1;"},
 806        ],
 807    );
 808
 809    assert(
 810        indoc! {"
 811            mod x {
 812                mod y {
 813
 814                }
 815            ˇ}
 816            let foo = 1;"},
 817        vec![indoc! {"
 818            mod x «{»
 819                mod y {
 820
 821                }
 822            «}»
 823            let foo = 1;"}],
 824    );
 825
 826    assert(
 827        indoc! {"
 828            mod x {
 829                mod y {
 830
 831                }
 832            }
 833            let fˇoo = 1;"},
 834        vec![],
 835    );
 836
 837    // Regression test: avoid crash when querying at the end of the buffer.
 838    assert(
 839        indoc! {"
 840            mod x {
 841                mod y {
 842
 843                }
 844            }
 845            let foo = 1;ˇ"},
 846        vec![],
 847    );
 848}
 849
 850#[gpui::test]
 851fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: &mut AppContext) {
 852    let mut assert = |selection_text, bracket_pair_texts| {
 853        assert_bracket_pairs(selection_text, bracket_pair_texts, javascript_lang(), cx)
 854    };
 855
 856    assert(
 857        indoc! {"
 858        for (const a in b)ˇ {
 859            // a comment that's longer than the for-loop header
 860        }"},
 861        vec![indoc! {"
 862        for «(»const a in b«)» {
 863            // a comment that's longer than the for-loop header
 864        }"}],
 865    );
 866
 867    // Regression test: even though the parent node of the parentheses (the for loop) does
 868    // intersect the given range, the parentheses themselves do not contain the range, so
 869    // they should not be returned. Only the curly braces contain the range.
 870    assert(
 871        indoc! {"
 872        for (const a in b) {ˇ
 873            // a comment that's longer than the for-loop header
 874        }"},
 875        vec![indoc! {"
 876        for (const a in b) «{»
 877            // a comment that's longer than the for-loop header
 878        «}»"}],
 879    );
 880}
 881
 882#[gpui::test]
 883fn test_range_for_syntax_ancestor(cx: &mut AppContext) {
 884    cx.new_model(|cx| {
 885        let text = "fn a() { b(|c| {}) }";
 886        let buffer =
 887            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
 888        let snapshot = buffer.snapshot();
 889
 890        assert_eq!(
 891            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 892            Some(range_of(text, "|"))
 893        );
 894        assert_eq!(
 895            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 896            Some(range_of(text, "|c|"))
 897        );
 898        assert_eq!(
 899            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 900            Some(range_of(text, "|c| {}"))
 901        );
 902        assert_eq!(
 903            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 904            Some(range_of(text, "(|c| {})"))
 905        );
 906
 907        buffer
 908    });
 909
 910    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 911        let start = text.find(part).unwrap();
 912        start..start
 913    }
 914
 915    fn range_of(text: &str, part: &str) -> Range<usize> {
 916        let start = text.find(part).unwrap();
 917        start..start + part.len()
 918    }
 919}
 920
 921#[gpui::test]
 922fn test_autoindent_with_soft_tabs(cx: &mut AppContext) {
 923    init_settings(cx, |_| {});
 924
 925    cx.new_model(|cx| {
 926        let text = "fn a() {}";
 927        let mut buffer =
 928            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
 929
 930        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 931        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 932
 933        buffer.edit(
 934            [(Point::new(1, 4)..Point::new(1, 4), "b()\n")],
 935            Some(AutoindentMode::EachLine),
 936            cx,
 937        );
 938        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 939
 940        // Create a field expression on a new line, causing that line
 941        // to be indented.
 942        buffer.edit(
 943            [(Point::new(2, 4)..Point::new(2, 4), ".c")],
 944            Some(AutoindentMode::EachLine),
 945            cx,
 946        );
 947        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 948
 949        // Remove the dot so that the line is no longer a field expression,
 950        // causing the line to be outdented.
 951        buffer.edit(
 952            [(Point::new(2, 8)..Point::new(2, 9), "")],
 953            Some(AutoindentMode::EachLine),
 954            cx,
 955        );
 956        assert_eq!(buffer.text(), "fn a() {\n    b()\n    c\n}");
 957
 958        buffer
 959    });
 960}
 961
 962#[gpui::test]
 963fn test_autoindent_with_hard_tabs(cx: &mut AppContext) {
 964    init_settings(cx, |settings| {
 965        settings.defaults.hard_tabs = Some(true);
 966    });
 967
 968    cx.new_model(|cx| {
 969        let text = "fn a() {}";
 970        let mut buffer =
 971            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
 972
 973        buffer.edit([(8..8, "\n\n")], Some(AutoindentMode::EachLine), cx);
 974        assert_eq!(buffer.text(), "fn a() {\n\t\n}");
 975
 976        buffer.edit(
 977            [(Point::new(1, 1)..Point::new(1, 1), "b()\n")],
 978            Some(AutoindentMode::EachLine),
 979            cx,
 980        );
 981        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\n}");
 982
 983        // Create a field expression on a new line, causing that line
 984        // to be indented.
 985        buffer.edit(
 986            [(Point::new(2, 1)..Point::new(2, 1), ".c")],
 987            Some(AutoindentMode::EachLine),
 988            cx,
 989        );
 990        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\t\t.c\n}");
 991
 992        // Remove the dot so that the line is no longer a field expression,
 993        // causing the line to be outdented.
 994        buffer.edit(
 995            [(Point::new(2, 2)..Point::new(2, 3), "")],
 996            Some(AutoindentMode::EachLine),
 997            cx,
 998        );
 999        assert_eq!(buffer.text(), "fn a() {\n\tb()\n\tc\n}");
1000
1001        buffer
1002    });
1003}
1004
1005#[gpui::test]
1006fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) {
1007    init_settings(cx, |_| {});
1008
1009    cx.new_model(|cx| {
1010        let entity_id = cx.entity_id();
1011        let mut buffer = Buffer::new(
1012            0,
1013            entity_id.as_u64(),
1014            "
1015            fn a() {
1016            c;
1017            d;
1018            }
1019            "
1020            .unindent(),
1021        )
1022        .with_language(Arc::new(rust_lang()), cx);
1023
1024        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
1025        // their indentation is not adjusted.
1026        buffer.edit_via_marked_text(
1027            &"
1028            fn a() {
1029            c«()»;
1030            d«()»;
1031            }
1032            "
1033            .unindent(),
1034            Some(AutoindentMode::EachLine),
1035            cx,
1036        );
1037        assert_eq!(
1038            buffer.text(),
1039            "
1040            fn a() {
1041            c();
1042            d();
1043            }
1044            "
1045            .unindent()
1046        );
1047
1048        // When appending new content after these lines, the indentation is based on the
1049        // preceding lines' actual indentation.
1050        buffer.edit_via_marked_text(
1051            &"
1052            fn a() {
10531054            .f
1055            .g()»;
10561057            .f
1058            .g()»;
1059            }
1060            "
1061            .unindent(),
1062            Some(AutoindentMode::EachLine),
1063            cx,
1064        );
1065
1066        assert_eq!(
1067            buffer.text(),
1068            "
1069            fn a() {
1070            c
1071                .f
1072                .g();
1073            d
1074                .f
1075                .g();
1076            }
1077            "
1078            .unindent()
1079        );
1080        buffer
1081    });
1082
1083    cx.new_model(|cx| {
1084        eprintln!("second buffer: {:?}", cx.entity_id());
1085
1086        let mut buffer = Buffer::new(
1087            0,
1088            cx.entity_id().as_u64(),
1089            "
1090            fn a() {
1091                b();
1092                |
1093            "
1094            .replace("|", "") // marker to preserve trailing whitespace
1095            .unindent(),
1096        )
1097        .with_language(Arc::new(rust_lang()), cx);
1098
1099        // Insert a closing brace. It is outdented.
1100        buffer.edit_via_marked_text(
1101            &"
1102            fn a() {
1103                b();
1104                «}»
1105            "
1106            .unindent(),
1107            Some(AutoindentMode::EachLine),
1108            cx,
1109        );
1110        assert_eq!(
1111            buffer.text(),
1112            "
1113            fn a() {
1114                b();
1115            }
1116            "
1117            .unindent()
1118        );
1119
1120        // Manually edit the leading whitespace. The edit is preserved.
1121        buffer.edit_via_marked_text(
1122            &"
1123            fn a() {
1124                b();
1125            «    »}
1126            "
1127            .unindent(),
1128            Some(AutoindentMode::EachLine),
1129            cx,
1130        );
1131        assert_eq!(
1132            buffer.text(),
1133            "
1134            fn a() {
1135                b();
1136                }
1137            "
1138            .unindent()
1139        );
1140        buffer
1141    });
1142
1143    eprintln!("DONE");
1144}
1145
1146#[gpui::test]
1147fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) {
1148    init_settings(cx, |_| {});
1149
1150    cx.new_model(|cx| {
1151        let mut buffer = Buffer::new(
1152            0,
1153            cx.entity_id().as_u64(),
1154            "
1155            fn a() {
1156                i
1157            }
1158            "
1159            .unindent(),
1160        )
1161        .with_language(Arc::new(rust_lang()), cx);
1162
1163        // Regression test: line does not get outdented due to syntax error
1164        buffer.edit_via_marked_text(
1165            &"
1166            fn a() {
1167                i«f let Some(x) = y»
1168            }
1169            "
1170            .unindent(),
1171            Some(AutoindentMode::EachLine),
1172            cx,
1173        );
1174        assert_eq!(
1175            buffer.text(),
1176            "
1177            fn a() {
1178                if let Some(x) = y
1179            }
1180            "
1181            .unindent()
1182        );
1183
1184        buffer.edit_via_marked_text(
1185            &"
1186            fn a() {
1187                if let Some(x) = y« {»
1188            }
1189            "
1190            .unindent(),
1191            Some(AutoindentMode::EachLine),
1192            cx,
1193        );
1194        assert_eq!(
1195            buffer.text(),
1196            "
1197            fn a() {
1198                if let Some(x) = y {
1199            }
1200            "
1201            .unindent()
1202        );
1203
1204        buffer
1205    });
1206}
1207
1208#[gpui::test]
1209fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) {
1210    init_settings(cx, |_| {});
1211
1212    cx.new_model(|cx| {
1213        let mut buffer = Buffer::new(
1214            0,
1215            cx.entity_id().as_u64(),
1216            "
1217            fn a() {}
1218            "
1219            .unindent(),
1220        )
1221        .with_language(Arc::new(rust_lang()), cx);
1222
1223        buffer.edit_via_marked_text(
1224            &"
1225            fn a(«
1226            b») {}
1227            "
1228            .unindent(),
1229            Some(AutoindentMode::EachLine),
1230            cx,
1231        );
1232        assert_eq!(
1233            buffer.text(),
1234            "
1235            fn a(
1236                b) {}
1237            "
1238            .unindent()
1239        );
1240
1241        // The indentation suggestion changed because `@end` node (a close paren)
1242        // is now at the beginning of the line.
1243        buffer.edit_via_marked_text(
1244            &"
1245            fn a(
1246                ˇ) {}
1247            "
1248            .unindent(),
1249            Some(AutoindentMode::EachLine),
1250            cx,
1251        );
1252        assert_eq!(
1253            buffer.text(),
1254            "
1255                fn a(
1256                ) {}
1257            "
1258            .unindent()
1259        );
1260
1261        buffer
1262    });
1263}
1264
1265#[gpui::test]
1266fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) {
1267    init_settings(cx, |_| {});
1268
1269    cx.new_model(|cx| {
1270        let text = "a\nb";
1271        let mut buffer =
1272            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
1273        buffer.edit(
1274            [(0..1, "\n"), (2..3, "\n")],
1275            Some(AutoindentMode::EachLine),
1276            cx,
1277        );
1278        assert_eq!(buffer.text(), "\n\n\n");
1279        buffer
1280    });
1281}
1282
1283#[gpui::test]
1284fn test_autoindent_multi_line_insertion(cx: &mut AppContext) {
1285    init_settings(cx, |_| {});
1286
1287    cx.new_model(|cx| {
1288        let text = "
1289            const a: usize = 1;
1290            fn b() {
1291                if c {
1292                    let d = 2;
1293                }
1294            }
1295        "
1296        .unindent();
1297
1298        let mut buffer =
1299            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
1300        buffer.edit(
1301            [(Point::new(3, 0)..Point::new(3, 0), "e(\n    f()\n);\n")],
1302            Some(AutoindentMode::EachLine),
1303            cx,
1304        );
1305        assert_eq!(
1306            buffer.text(),
1307            "
1308                const a: usize = 1;
1309                fn b() {
1310                    if c {
1311                        e(
1312                            f()
1313                        );
1314                        let d = 2;
1315                    }
1316                }
1317            "
1318            .unindent()
1319        );
1320
1321        buffer
1322    });
1323}
1324
1325#[gpui::test]
1326fn test_autoindent_block_mode(cx: &mut AppContext) {
1327    init_settings(cx, |_| {});
1328
1329    cx.new_model(|cx| {
1330        let text = r#"
1331            fn a() {
1332                b();
1333            }
1334        "#
1335        .unindent();
1336        let mut buffer =
1337            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
1338
1339        // When this text was copied, both of the quotation marks were at the same
1340        // indent level, but the indentation of the first line was not included in
1341        // the copied text. This information is retained in the
1342        // 'original_indent_columns' vector.
1343        let original_indent_columns = vec![4];
1344        let inserted_text = r#"
1345            "
1346                  c
1347                    d
1348                      e
1349                "
1350        "#
1351        .unindent();
1352
1353        // Insert the block at column zero. The entire block is indented
1354        // so that the first line matches the previous line's indentation.
1355        buffer.edit(
1356            [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
1357            Some(AutoindentMode::Block {
1358                original_indent_columns: original_indent_columns.clone(),
1359            }),
1360            cx,
1361        );
1362        assert_eq!(
1363            buffer.text(),
1364            r#"
1365            fn a() {
1366                b();
1367                "
1368                  c
1369                    d
1370                      e
1371                "
1372            }
1373            "#
1374            .unindent()
1375        );
1376
1377        // Grouping is disabled in tests, so we need 2 undos
1378        buffer.undo(cx); // Undo the auto-indent
1379        buffer.undo(cx); // Undo the original edit
1380
1381        // Insert the block at a deeper indent level. The entire block is outdented.
1382        buffer.edit([(Point::new(2, 0)..Point::new(2, 0), "        ")], None, cx);
1383        buffer.edit(
1384            [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
1385            Some(AutoindentMode::Block {
1386                original_indent_columns: original_indent_columns.clone(),
1387            }),
1388            cx,
1389        );
1390        assert_eq!(
1391            buffer.text(),
1392            r#"
1393            fn a() {
1394                b();
1395                "
1396                  c
1397                    d
1398                      e
1399                "
1400            }
1401            "#
1402            .unindent()
1403        );
1404
1405        buffer
1406    });
1407}
1408
1409#[gpui::test]
1410fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) {
1411    init_settings(cx, |_| {});
1412
1413    cx.new_model(|cx| {
1414        let text = r#"
1415            fn a() {
1416                if b() {
1417
1418                }
1419            }
1420        "#
1421        .unindent();
1422        let mut buffer =
1423            Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx);
1424
1425        // The original indent columns are not known, so this text is
1426        // auto-indented in a block as if the first line was copied in
1427        // its entirety.
1428        let original_indent_columns = Vec::new();
1429        let inserted_text = "    c\n        .d()\n        .e();";
1430
1431        // Insert the block at column zero. The entire block is indented
1432        // so that the first line matches the previous line's indentation.
1433        buffer.edit(
1434            [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
1435            Some(AutoindentMode::Block {
1436                original_indent_columns: original_indent_columns.clone(),
1437            }),
1438            cx,
1439        );
1440        assert_eq!(
1441            buffer.text(),
1442            r#"
1443            fn a() {
1444                if b() {
1445                    c
1446                        .d()
1447                        .e();
1448                }
1449            }
1450            "#
1451            .unindent()
1452        );
1453
1454        // Grouping is disabled in tests, so we need 2 undos
1455        buffer.undo(cx); // Undo the auto-indent
1456        buffer.undo(cx); // Undo the original edit
1457
1458        // Insert the block at a deeper indent level. The entire block is outdented.
1459        buffer.edit(
1460            [(Point::new(2, 0)..Point::new(2, 0), " ".repeat(12))],
1461            None,
1462            cx,
1463        );
1464        buffer.edit(
1465            [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
1466            Some(AutoindentMode::Block {
1467                original_indent_columns: Vec::new(),
1468            }),
1469            cx,
1470        );
1471        assert_eq!(
1472            buffer.text(),
1473            r#"
1474            fn a() {
1475                if b() {
1476                    c
1477                        .d()
1478                        .e();
1479                }
1480            }
1481            "#
1482            .unindent()
1483        );
1484
1485        buffer
1486    });
1487}
1488
1489#[gpui::test]
1490fn test_autoindent_language_without_indents_query(cx: &mut AppContext) {
1491    init_settings(cx, |_| {});
1492
1493    cx.new_model(|cx| {
1494        let text = "
1495            * one
1496                - a
1497                - b
1498            * two
1499        "
1500        .unindent();
1501
1502        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(
1503            Arc::new(Language::new(
1504                LanguageConfig {
1505                    name: "Markdown".into(),
1506                    auto_indent_using_last_non_empty_line: false,
1507                    ..Default::default()
1508                },
1509                Some(tree_sitter_json::language()),
1510            )),
1511            cx,
1512        );
1513        buffer.edit(
1514            [(Point::new(3, 0)..Point::new(3, 0), "\n")],
1515            Some(AutoindentMode::EachLine),
1516            cx,
1517        );
1518        assert_eq!(
1519            buffer.text(),
1520            "
1521            * one
1522                - a
1523                - b
1524
1525            * two
1526            "
1527            .unindent()
1528        );
1529        buffer
1530    });
1531}
1532
1533#[gpui::test]
1534fn test_autoindent_with_injected_languages(cx: &mut AppContext) {
1535    init_settings(cx, |settings| {
1536        settings.languages.extend([
1537            (
1538                "HTML".into(),
1539                LanguageSettingsContent {
1540                    tab_size: Some(2.try_into().unwrap()),
1541                    ..Default::default()
1542                },
1543            ),
1544            (
1545                "JavaScript".into(),
1546                LanguageSettingsContent {
1547                    tab_size: Some(8.try_into().unwrap()),
1548                    ..Default::default()
1549                },
1550            ),
1551        ])
1552    });
1553
1554    let html_language = Arc::new(html_lang());
1555
1556    let javascript_language = Arc::new(javascript_lang());
1557
1558    let language_registry = Arc::new(LanguageRegistry::test());
1559    language_registry.add(html_language.clone());
1560    language_registry.add(javascript_language.clone());
1561
1562    cx.new_model(|cx| {
1563        let (text, ranges) = marked_text_ranges(
1564            &"
1565                <div>ˇ
1566                </div>
1567                <script>
1568                    init({ˇ
1569                    })
1570                </script>
1571                <span>ˇ
1572                </span>
1573            "
1574            .unindent(),
1575            false,
1576        );
1577
1578        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text);
1579        buffer.set_language_registry(language_registry);
1580        buffer.set_language(Some(html_language), cx);
1581        buffer.edit(
1582            ranges.into_iter().map(|range| (range, "\na")),
1583            Some(AutoindentMode::EachLine),
1584            cx,
1585        );
1586        assert_eq!(
1587            buffer.text(),
1588            "
1589                <div>
1590                  a
1591                </div>
1592                <script>
1593                    init({
1594                            a
1595                    })
1596                </script>
1597                <span>
1598                  a
1599                </span>
1600            "
1601            .unindent()
1602        );
1603        buffer
1604    });
1605}
1606
1607#[gpui::test]
1608fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) {
1609    init_settings(cx, |settings| {
1610        settings.defaults.tab_size = Some(2.try_into().unwrap());
1611    });
1612
1613    cx.new_model(|cx| {
1614        let mut buffer =
1615            Buffer::new(0, cx.entity_id().as_u64(), "").with_language(Arc::new(ruby_lang()), cx);
1616
1617        let text = r#"
1618            class C
1619            def a(b, c)
1620            puts b
1621            puts c
1622            rescue
1623            puts "errored"
1624            exit 1
1625            end
1626            end
1627        "#
1628        .unindent();
1629
1630        buffer.edit([(0..0, text)], Some(AutoindentMode::EachLine), cx);
1631
1632        assert_eq!(
1633            buffer.text(),
1634            r#"
1635                class C
1636                  def a(b, c)
1637                    puts b
1638                    puts c
1639                  rescue
1640                    puts "errored"
1641                    exit 1
1642                  end
1643                end
1644            "#
1645            .unindent()
1646        );
1647
1648        buffer
1649    });
1650}
1651
1652#[gpui::test]
1653fn test_language_scope_at_with_javascript(cx: &mut AppContext) {
1654    init_settings(cx, |_| {});
1655
1656    cx.new_model(|cx| {
1657        let language = Language::new(
1658            LanguageConfig {
1659                name: "JavaScript".into(),
1660                line_comment: Some("// ".into()),
1661                brackets: BracketPairConfig {
1662                    pairs: vec![
1663                        BracketPair {
1664                            start: "{".into(),
1665                            end: "}".into(),
1666                            close: true,
1667                            newline: false,
1668                        },
1669                        BracketPair {
1670                            start: "'".into(),
1671                            end: "'".into(),
1672                            close: true,
1673                            newline: false,
1674                        },
1675                    ],
1676                    disabled_scopes_by_bracket_ix: vec![
1677                        Vec::new(), //
1678                        vec!["string".into()],
1679                    ],
1680                },
1681                overrides: [(
1682                    "element".into(),
1683                    LanguageConfigOverride {
1684                        line_comment: Override::Remove { remove: true },
1685                        block_comment: Override::Set(("{/*".into(), "*/}".into())),
1686                        ..Default::default()
1687                    },
1688                )]
1689                .into_iter()
1690                .collect(),
1691                ..Default::default()
1692            },
1693            Some(tree_sitter_typescript::language_tsx()),
1694        )
1695        .with_override_query(
1696            r#"
1697                (jsx_element) @element
1698                (string) @string
1699                [
1700                    (jsx_opening_element)
1701                    (jsx_closing_element)
1702                    (jsx_expression)
1703                ] @default
1704            "#,
1705        )
1706        .unwrap();
1707
1708        let text = r#"
1709            a["b"] = <C d="e">
1710                <F></F>
1711                { g() }
1712            </C>;
1713        "#
1714        .unindent();
1715
1716        let buffer =
1717            Buffer::new(0, cx.entity_id().as_u64(), &text).with_language(Arc::new(language), cx);
1718        let snapshot = buffer.snapshot();
1719
1720        let config = snapshot.language_scope_at(0).unwrap();
1721        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
1722        // Both bracket pairs are enabled
1723        assert_eq!(
1724            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1725            &[true, true]
1726        );
1727
1728        let string_config = snapshot
1729            .language_scope_at(text.find("b\"").unwrap())
1730            .unwrap();
1731        assert_eq!(string_config.line_comment_prefix().unwrap().as_ref(), "// ");
1732        // Second bracket pair is disabled
1733        assert_eq!(
1734            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1735            &[true, false]
1736        );
1737
1738        // In between JSX tags: use the `element` override.
1739        let element_config = snapshot
1740            .language_scope_at(text.find("<F>").unwrap())
1741            .unwrap();
1742        assert_eq!(element_config.line_comment_prefix(), None);
1743        assert_eq!(
1744            element_config.block_comment_delimiters(),
1745            Some((&"{/*".into(), &"*/}".into()))
1746        );
1747        assert_eq!(
1748            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1749            &[true, true]
1750        );
1751
1752        // Within a JSX tag: use the default config.
1753        let tag_config = snapshot
1754            .language_scope_at(text.find(" d=").unwrap() + 1)
1755            .unwrap();
1756        assert_eq!(tag_config.line_comment_prefix().unwrap().as_ref(), "// ");
1757        assert_eq!(
1758            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1759            &[true, true]
1760        );
1761
1762        // In a JSX expression: use the default config.
1763        let expression_in_element_config = snapshot
1764            .language_scope_at(text.find("{").unwrap() + 1)
1765            .unwrap();
1766        assert_eq!(
1767            expression_in_element_config
1768                .line_comment_prefix()
1769                .unwrap()
1770                .as_ref(),
1771            "// "
1772        );
1773        assert_eq!(
1774            expression_in_element_config
1775                .brackets()
1776                .map(|e| e.1)
1777                .collect::<Vec<_>>(),
1778            &[true, true]
1779        );
1780
1781        buffer
1782    });
1783}
1784
1785#[gpui::test]
1786fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1787    init_settings(cx, |_| {});
1788
1789    cx.new_model(|cx| {
1790        let language = Language::new(
1791            LanguageConfig {
1792                name: "Rust".into(),
1793                brackets: BracketPairConfig {
1794                    pairs: vec![
1795                        BracketPair {
1796                            start: "{".into(),
1797                            end: "}".into(),
1798                            close: true,
1799                            newline: false,
1800                        },
1801                        BracketPair {
1802                            start: "'".into(),
1803                            end: "'".into(),
1804                            close: true,
1805                            newline: false,
1806                        },
1807                    ],
1808                    disabled_scopes_by_bracket_ix: vec![
1809                        Vec::new(), //
1810                        vec!["string".into()],
1811                    ],
1812                },
1813                ..Default::default()
1814            },
1815            Some(tree_sitter_rust::language()),
1816        )
1817        .with_override_query(
1818            r#"
1819                (string_literal) @string
1820            "#,
1821        )
1822        .unwrap();
1823
1824        let text = r#"
1825            const S: &'static str = "hello";
1826        "#
1827        .unindent();
1828
1829        let buffer = Buffer::new(0, cx.entity_id().as_u64(), text.clone())
1830            .with_language(Arc::new(language), cx);
1831        let snapshot = buffer.snapshot();
1832
1833        // By default, all brackets are enabled
1834        let config = snapshot.language_scope_at(0).unwrap();
1835        assert_eq!(
1836            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1837            &[true, true]
1838        );
1839
1840        // Within a string, the quotation brackets are disabled.
1841        let string_config = snapshot
1842            .language_scope_at(text.find("ello").unwrap())
1843            .unwrap();
1844        assert_eq!(
1845            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1846            &[true, false]
1847        );
1848
1849        buffer
1850    });
1851}
1852
1853#[gpui::test]
1854fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1855    init_settings(cx, |_| {});
1856
1857    cx.new_model(|cx| {
1858        let text = r#"
1859            <ol>
1860            <% people.each do |person| %>
1861                <li>
1862                    <%= person.name %>
1863                </li>
1864            <% end %>
1865            </ol>
1866        "#
1867        .unindent();
1868
1869        let language_registry = Arc::new(LanguageRegistry::test());
1870        language_registry.add(Arc::new(ruby_lang()));
1871        language_registry.add(Arc::new(html_lang()));
1872        language_registry.add(Arc::new(erb_lang()));
1873
1874        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text);
1875        buffer.set_language_registry(language_registry.clone());
1876        buffer.set_language(
1877            language_registry
1878                .language_for_name("ERB")
1879                .now_or_never()
1880                .unwrap()
1881                .ok(),
1882            cx,
1883        );
1884
1885        let snapshot = buffer.snapshot();
1886        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1887        assert_eq!(html_config.line_comment_prefix(), None);
1888        assert_eq!(
1889            html_config.block_comment_delimiters(),
1890            Some((&"<!--".into(), &"-->".into()))
1891        );
1892
1893        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1894        assert_eq!(ruby_config.line_comment_prefix().unwrap().as_ref(), "# ");
1895        assert_eq!(ruby_config.block_comment_delimiters(), None);
1896
1897        buffer
1898    });
1899}
1900
1901#[gpui::test]
1902fn test_serialization(cx: &mut gpui::AppContext) {
1903    let mut now = Instant::now();
1904
1905    let buffer1 = cx.new_model(|cx| {
1906        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "abc");
1907        buffer.edit([(3..3, "D")], None, cx);
1908
1909        now += Duration::from_secs(1);
1910        buffer.start_transaction_at(now);
1911        buffer.edit([(4..4, "E")], None, cx);
1912        buffer.end_transaction_at(now, cx);
1913        assert_eq!(buffer.text(), "abcDE");
1914
1915        buffer.undo(cx);
1916        assert_eq!(buffer.text(), "abcD");
1917
1918        buffer.edit([(4..4, "F")], None, cx);
1919        assert_eq!(buffer.text(), "abcDF");
1920        buffer
1921    });
1922    assert_eq!(buffer1.read(cx).text(), "abcDF");
1923
1924    let state = buffer1.read(cx).to_proto();
1925    let ops = cx
1926        .background_executor()
1927        .block(buffer1.read(cx).serialize_ops(None, cx));
1928    let buffer2 = cx.new_model(|cx| {
1929        let mut buffer = Buffer::from_proto(1, state, None).unwrap();
1930        buffer
1931            .apply_ops(
1932                ops.into_iter()
1933                    .map(|op| proto::deserialize_operation(op).unwrap()),
1934                cx,
1935            )
1936            .unwrap();
1937        buffer
1938    });
1939    assert_eq!(buffer2.read(cx).text(), "abcDF");
1940}
1941
1942#[gpui::test(iterations = 100)]
1943fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1944    let min_peers = env::var("MIN_PEERS")
1945        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1946        .unwrap_or(1);
1947    let max_peers = env::var("MAX_PEERS")
1948        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1949        .unwrap_or(5);
1950    let operations = env::var("OPERATIONS")
1951        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1952        .unwrap_or(10);
1953
1954    let base_text_len = rng.gen_range(0..10);
1955    let base_text = RandomCharIter::new(&mut rng)
1956        .take(base_text_len)
1957        .collect::<String>();
1958    let mut replica_ids = Vec::new();
1959    let mut buffers = Vec::new();
1960    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
1961    let base_buffer =
1962        cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str()));
1963
1964    for i in 0..rng.gen_range(min_peers..=max_peers) {
1965        let buffer = cx.new_model(|cx| {
1966            let state = base_buffer.read(cx).to_proto();
1967            let ops = cx
1968                .background_executor()
1969                .block(base_buffer.read(cx).serialize_ops(None, cx));
1970            let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
1971            buffer
1972                .apply_ops(
1973                    ops.into_iter()
1974                        .map(|op| proto::deserialize_operation(op).unwrap()),
1975                    cx,
1976                )
1977                .unwrap();
1978            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1979            let network = network.clone();
1980            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1981                if let Event::Operation(op) = event {
1982                    network
1983                        .lock()
1984                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1985                }
1986            })
1987            .detach();
1988            buffer
1989        });
1990
1991        buffers.push(buffer);
1992        replica_ids.push(i as ReplicaId);
1993        network.lock().add_peer(i as ReplicaId);
1994        log::info!("Adding initial peer with replica id {}", i);
1995    }
1996
1997    log::info!("initial text: {:?}", base_text);
1998
1999    let mut now = Instant::now();
2000    let mut mutation_count = operations;
2001    let mut next_diagnostic_id = 0;
2002    let mut active_selections = BTreeMap::default();
2003    loop {
2004        let replica_index = rng.gen_range(0..replica_ids.len());
2005        let replica_id = replica_ids[replica_index];
2006        let buffer = &mut buffers[replica_index];
2007        let mut new_buffer = None;
2008        match rng.gen_range(0..100) {
2009            0..=29 if mutation_count != 0 => {
2010                buffer.update(cx, |buffer, cx| {
2011                    buffer.start_transaction_at(now);
2012                    buffer.randomly_edit(&mut rng, 5, cx);
2013                    buffer.end_transaction_at(now, cx);
2014                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2015                });
2016                mutation_count -= 1;
2017            }
2018            30..=39 if mutation_count != 0 => {
2019                buffer.update(cx, |buffer, cx| {
2020                    if rng.gen_bool(0.2) {
2021                        log::info!("peer {} clearing active selections", replica_id);
2022                        active_selections.remove(&replica_id);
2023                        buffer.remove_active_selections(cx);
2024                    } else {
2025                        let mut selections = Vec::new();
2026                        for id in 0..rng.gen_range(1..=5) {
2027                            let range = buffer.random_byte_range(0, &mut rng);
2028                            selections.push(Selection {
2029                                id,
2030                                start: buffer.anchor_before(range.start),
2031                                end: buffer.anchor_before(range.end),
2032                                reversed: false,
2033                                goal: SelectionGoal::None,
2034                            });
2035                        }
2036                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2037                        log::info!(
2038                            "peer {} setting active selections: {:?}",
2039                            replica_id,
2040                            selections
2041                        );
2042                        active_selections.insert(replica_id, selections.clone());
2043                        buffer.set_active_selections(selections, false, Default::default(), cx);
2044                    }
2045                });
2046                mutation_count -= 1;
2047            }
2048            40..=49 if mutation_count != 0 && replica_id == 0 => {
2049                let entry_count = rng.gen_range(1..=5);
2050                buffer.update(cx, |buffer, cx| {
2051                    let diagnostics = DiagnosticSet::new(
2052                        (0..entry_count).map(|_| {
2053                            let range = buffer.random_byte_range(0, &mut rng);
2054                            let range = range.to_point_utf16(buffer);
2055                            let range = range.start..range.end;
2056                            DiagnosticEntry {
2057                                range,
2058                                diagnostic: Diagnostic {
2059                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2060                                    ..Default::default()
2061                                },
2062                            }
2063                        }),
2064                        buffer,
2065                    );
2066                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2067                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2068                });
2069                mutation_count -= 1;
2070            }
2071            50..=59 if replica_ids.len() < max_peers => {
2072                let old_buffer_state = buffer.read(cx).to_proto();
2073                let old_buffer_ops = cx
2074                    .background_executor()
2075                    .block(buffer.read(cx).serialize_ops(None, cx));
2076                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2077                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2078                    .choose(&mut rng)
2079                    .unwrap();
2080                log::info!(
2081                    "Adding new replica {} (replicating from {})",
2082                    new_replica_id,
2083                    replica_id
2084                );
2085                new_buffer = Some(cx.new_model(|cx| {
2086                    let mut new_buffer =
2087                        Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
2088                    new_buffer
2089                        .apply_ops(
2090                            old_buffer_ops
2091                                .into_iter()
2092                                .map(|op| deserialize_operation(op).unwrap()),
2093                            cx,
2094                        )
2095                        .unwrap();
2096                    log::info!(
2097                        "New replica {} text: {:?}",
2098                        new_buffer.replica_id(),
2099                        new_buffer.text()
2100                    );
2101                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2102                    let network = network.clone();
2103                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2104                        if let Event::Operation(op) = event {
2105                            network.lock().broadcast(
2106                                buffer.replica_id(),
2107                                vec![proto::serialize_operation(op)],
2108                            );
2109                        }
2110                    })
2111                    .detach();
2112                    new_buffer
2113                }));
2114                network.lock().replicate(replica_id, new_replica_id);
2115
2116                if new_replica_id as usize == replica_ids.len() {
2117                    replica_ids.push(new_replica_id);
2118                } else {
2119                    let new_buffer = new_buffer.take().unwrap();
2120                    while network.lock().has_unreceived(new_replica_id) {
2121                        let ops = network
2122                            .lock()
2123                            .receive(new_replica_id)
2124                            .into_iter()
2125                            .map(|op| proto::deserialize_operation(op).unwrap());
2126                        if ops.len() > 0 {
2127                            log::info!(
2128                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2129                                new_replica_id,
2130                                buffer.read(cx).version(),
2131                                ops.len(),
2132                                ops
2133                            );
2134                            new_buffer.update(cx, |new_buffer, cx| {
2135                                new_buffer.apply_ops(ops, cx).unwrap();
2136                            });
2137                        }
2138                    }
2139                    buffers[new_replica_id as usize] = new_buffer;
2140                }
2141            }
2142            60..=69 if mutation_count != 0 => {
2143                buffer.update(cx, |buffer, cx| {
2144                    buffer.randomly_undo_redo(&mut rng, cx);
2145                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2146                });
2147                mutation_count -= 1;
2148            }
2149            _ if network.lock().has_unreceived(replica_id) => {
2150                let ops = network
2151                    .lock()
2152                    .receive(replica_id)
2153                    .into_iter()
2154                    .map(|op| proto::deserialize_operation(op).unwrap());
2155                if ops.len() > 0 {
2156                    log::info!(
2157                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2158                        replica_id,
2159                        buffer.read(cx).version(),
2160                        ops.len(),
2161                        ops
2162                    );
2163                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2164                }
2165            }
2166            _ => {}
2167        }
2168
2169        now += Duration::from_millis(rng.gen_range(0..=200));
2170        buffers.extend(new_buffer);
2171
2172        for buffer in &buffers {
2173            buffer.read(cx).check_invariants();
2174        }
2175
2176        if mutation_count == 0 && network.lock().is_idle() {
2177            break;
2178        }
2179    }
2180
2181    let first_buffer = buffers[0].read(cx).snapshot();
2182    for buffer in &buffers[1..] {
2183        let buffer = buffer.read(cx).snapshot();
2184        assert_eq!(
2185            buffer.version(),
2186            first_buffer.version(),
2187            "Replica {} version != Replica 0 version",
2188            buffer.replica_id()
2189        );
2190        assert_eq!(
2191            buffer.text(),
2192            first_buffer.text(),
2193            "Replica {} text != Replica 0 text",
2194            buffer.replica_id()
2195        );
2196        assert_eq!(
2197            buffer
2198                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2199                .collect::<Vec<_>>(),
2200            first_buffer
2201                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2202                .collect::<Vec<_>>(),
2203            "Replica {} diagnostics != Replica 0 diagnostics",
2204            buffer.replica_id()
2205        );
2206    }
2207
2208    for buffer in &buffers {
2209        let buffer = buffer.read(cx).snapshot();
2210        let actual_remote_selections = buffer
2211            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2212            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2213            .collect::<Vec<_>>();
2214        let expected_remote_selections = active_selections
2215            .iter()
2216            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2217            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2218            .collect::<Vec<_>>();
2219        assert_eq!(
2220            actual_remote_selections,
2221            expected_remote_selections,
2222            "Replica {} remote selections != expected selections",
2223            buffer.replica_id()
2224        );
2225    }
2226}
2227
2228#[test]
2229fn test_contiguous_ranges() {
2230    assert_eq!(
2231        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2232        &[1..4, 5..7, 9..13]
2233    );
2234
2235    // Respects the `max_len` parameter
2236    assert_eq!(
2237        contiguous_ranges(
2238            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2239            3
2240        )
2241        .collect::<Vec<_>>(),
2242        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2243    );
2244}
2245
2246#[gpui::test(iterations = 500)]
2247fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2248    // Generate a random multi-line string containing
2249    // some lines with trailing whitespace.
2250    let mut text = String::new();
2251    for _ in 0..rng.gen_range(0..16) {
2252        for _ in 0..rng.gen_range(0..36) {
2253            text.push(match rng.gen_range(0..10) {
2254                0..=1 => ' ',
2255                3 => '\t',
2256                _ => rng.gen_range('a'..'z'),
2257            });
2258        }
2259        text.push('\n');
2260    }
2261
2262    match rng.gen_range(0..10) {
2263        // sometimes remove the last newline
2264        0..=1 => drop(text.pop()), //
2265
2266        // sometimes add extra newlines
2267        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2268        _ => {}
2269    }
2270
2271    let rope = Rope::from(text.as_str());
2272    let actual_ranges = trailing_whitespace_ranges(&rope);
2273    let expected_ranges = TRAILING_WHITESPACE_REGEX
2274        .find_iter(&text)
2275        .map(|m| m.range())
2276        .collect::<Vec<_>>();
2277    assert_eq!(
2278        actual_ranges,
2279        expected_ranges,
2280        "wrong ranges for text lines:\n{:?}",
2281        text.split("\n").collect::<Vec<_>>()
2282    );
2283}
2284
2285fn ruby_lang() -> Language {
2286    Language::new(
2287        LanguageConfig {
2288            name: "Ruby".into(),
2289            path_suffixes: vec!["rb".to_string()],
2290            line_comment: Some("# ".into()),
2291            ..Default::default()
2292        },
2293        Some(tree_sitter_ruby::language()),
2294    )
2295    .with_indents_query(
2296        r#"
2297            (class "end" @end) @indent
2298            (method "end" @end) @indent
2299            (rescue) @outdent
2300            (then) @indent
2301        "#,
2302    )
2303    .unwrap()
2304}
2305
2306fn html_lang() -> Language {
2307    Language::new(
2308        LanguageConfig {
2309            name: "HTML".into(),
2310            block_comment: Some(("<!--".into(), "-->".into())),
2311            ..Default::default()
2312        },
2313        Some(tree_sitter_html::language()),
2314    )
2315    .with_indents_query(
2316        "
2317        (element
2318          (start_tag) @start
2319          (end_tag)? @end) @indent
2320        ",
2321    )
2322    .unwrap()
2323    .with_injection_query(
2324        r#"
2325        (script_element
2326            (raw_text) @content
2327            (#set! "language" "javascript"))
2328        "#,
2329    )
2330    .unwrap()
2331}
2332
2333fn erb_lang() -> Language {
2334    Language::new(
2335        LanguageConfig {
2336            name: "ERB".into(),
2337            path_suffixes: vec!["erb".to_string()],
2338            block_comment: Some(("<%#".into(), "%>".into())),
2339            ..Default::default()
2340        },
2341        Some(tree_sitter_embedded_template::language()),
2342    )
2343    .with_injection_query(
2344        r#"
2345            (
2346                (code) @content
2347                (#set! "language" "ruby")
2348                (#set! "combined")
2349            )
2350
2351            (
2352                (content) @content
2353                (#set! "language" "html")
2354                (#set! "combined")
2355            )
2356        "#,
2357    )
2358    .unwrap()
2359}
2360
2361fn rust_lang() -> Language {
2362    Language::new(
2363        LanguageConfig {
2364            name: "Rust".into(),
2365            path_suffixes: vec!["rs".to_string()],
2366            ..Default::default()
2367        },
2368        Some(tree_sitter_rust::language()),
2369    )
2370    .with_indents_query(
2371        r#"
2372        (call_expression) @indent
2373        (field_expression) @indent
2374        (_ "(" ")" @end) @indent
2375        (_ "{" "}" @end) @indent
2376        "#,
2377    )
2378    .unwrap()
2379    .with_brackets_query(
2380        r#"
2381        ("{" @open "}" @close)
2382        "#,
2383    )
2384    .unwrap()
2385    .with_outline_query(
2386        r#"
2387        (struct_item
2388            "struct" @context
2389            name: (_) @name) @item
2390        (enum_item
2391            "enum" @context
2392            name: (_) @name) @item
2393        (enum_variant
2394            name: (_) @name) @item
2395        (field_declaration
2396            name: (_) @name) @item
2397        (impl_item
2398            "impl" @context
2399            trait: (_)? @name
2400            "for"? @context
2401            type: (_) @name) @item
2402        (function_item
2403            "fn" @context
2404            name: (_) @name) @item
2405        (mod_item
2406            "mod" @context
2407            name: (_) @name) @item
2408        "#,
2409    )
2410    .unwrap()
2411}
2412
2413fn json_lang() -> Language {
2414    Language::new(
2415        LanguageConfig {
2416            name: "Json".into(),
2417            path_suffixes: vec!["js".to_string()],
2418            ..Default::default()
2419        },
2420        Some(tree_sitter_json::language()),
2421    )
2422}
2423
2424fn javascript_lang() -> Language {
2425    Language::new(
2426        LanguageConfig {
2427            name: "JavaScript".into(),
2428            ..Default::default()
2429        },
2430        Some(tree_sitter_typescript::language_tsx()),
2431    )
2432    .with_brackets_query(
2433        r#"
2434        ("{" @open "}" @close)
2435        ("(" @open ")" @close)
2436        "#,
2437    )
2438    .unwrap()
2439    .with_indents_query(
2440        r#"
2441        (object "}" @end) @indent
2442        "#,
2443    )
2444    .unwrap()
2445}
2446
2447fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2448    buffer.update(cx, |buffer, _| {
2449        let snapshot = buffer.snapshot();
2450        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2451        layers[0].node().to_sexp()
2452    })
2453}
2454
2455// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2456fn assert_bracket_pairs(
2457    selection_text: &'static str,
2458    bracket_pair_texts: Vec<&'static str>,
2459    language: Language,
2460    cx: &mut AppContext,
2461) {
2462    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2463    let buffer = cx.new_model(|cx| {
2464        Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone())
2465            .with_language(Arc::new(language), cx)
2466    });
2467    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2468
2469    let selection_range = selection_ranges[0].clone();
2470
2471    let bracket_pairs = bracket_pair_texts
2472        .into_iter()
2473        .map(|pair_text| {
2474            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2475            assert_eq!(bracket_text, expected_text);
2476            (ranges[0].clone(), ranges[1].clone())
2477        })
2478        .collect::<Vec<_>>();
2479
2480    assert_set_eq!(
2481        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2482        bracket_pairs
2483    );
2484}
2485
2486fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2487    let settings_store = SettingsStore::test(cx);
2488    cx.set_global(settings_store);
2489    crate::init(cx);
2490    cx.update_global::<SettingsStore, _>(|settings, cx| {
2491        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2492    });
2493}