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 tasks.
 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, Capability::ReadWrite, 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 =
1971                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
1972            buffer
1973                .apply_ops(
1974                    ops.into_iter()
1975                        .map(|op| proto::deserialize_operation(op).unwrap()),
1976                    cx,
1977                )
1978                .unwrap();
1979            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1980            let network = network.clone();
1981            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1982                if let Event::Operation(op) = event {
1983                    network
1984                        .lock()
1985                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1986                }
1987            })
1988            .detach();
1989            buffer
1990        });
1991
1992        buffers.push(buffer);
1993        replica_ids.push(i as ReplicaId);
1994        network.lock().add_peer(i as ReplicaId);
1995        log::info!("Adding initial peer with replica id {}", i);
1996    }
1997
1998    log::info!("initial text: {:?}", base_text);
1999
2000    let mut now = Instant::now();
2001    let mut mutation_count = operations;
2002    let mut next_diagnostic_id = 0;
2003    let mut active_selections = BTreeMap::default();
2004    loop {
2005        let replica_index = rng.gen_range(0..replica_ids.len());
2006        let replica_id = replica_ids[replica_index];
2007        let buffer = &mut buffers[replica_index];
2008        let mut new_buffer = None;
2009        match rng.gen_range(0..100) {
2010            0..=29 if mutation_count != 0 => {
2011                buffer.update(cx, |buffer, cx| {
2012                    buffer.start_transaction_at(now);
2013                    buffer.randomly_edit(&mut rng, 5, cx);
2014                    buffer.end_transaction_at(now, cx);
2015                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2016                });
2017                mutation_count -= 1;
2018            }
2019            30..=39 if mutation_count != 0 => {
2020                buffer.update(cx, |buffer, cx| {
2021                    if rng.gen_bool(0.2) {
2022                        log::info!("peer {} clearing active selections", replica_id);
2023                        active_selections.remove(&replica_id);
2024                        buffer.remove_active_selections(cx);
2025                    } else {
2026                        let mut selections = Vec::new();
2027                        for id in 0..rng.gen_range(1..=5) {
2028                            let range = buffer.random_byte_range(0, &mut rng);
2029                            selections.push(Selection {
2030                                id,
2031                                start: buffer.anchor_before(range.start),
2032                                end: buffer.anchor_before(range.end),
2033                                reversed: false,
2034                                goal: SelectionGoal::None,
2035                            });
2036                        }
2037                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2038                        log::info!(
2039                            "peer {} setting active selections: {:?}",
2040                            replica_id,
2041                            selections
2042                        );
2043                        active_selections.insert(replica_id, selections.clone());
2044                        buffer.set_active_selections(selections, false, Default::default(), cx);
2045                    }
2046                });
2047                mutation_count -= 1;
2048            }
2049            40..=49 if mutation_count != 0 && replica_id == 0 => {
2050                let entry_count = rng.gen_range(1..=5);
2051                buffer.update(cx, |buffer, cx| {
2052                    let diagnostics = DiagnosticSet::new(
2053                        (0..entry_count).map(|_| {
2054                            let range = buffer.random_byte_range(0, &mut rng);
2055                            let range = range.to_point_utf16(buffer);
2056                            let range = range.start..range.end;
2057                            DiagnosticEntry {
2058                                range,
2059                                diagnostic: Diagnostic {
2060                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2061                                    ..Default::default()
2062                                },
2063                            }
2064                        }),
2065                        buffer,
2066                    );
2067                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2068                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2069                });
2070                mutation_count -= 1;
2071            }
2072            50..=59 if replica_ids.len() < max_peers => {
2073                let old_buffer_state = buffer.read(cx).to_proto();
2074                let old_buffer_ops = cx
2075                    .background_executor()
2076                    .block(buffer.read(cx).serialize_ops(None, cx));
2077                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2078                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2079                    .choose(&mut rng)
2080                    .unwrap();
2081                log::info!(
2082                    "Adding new replica {} (replicating from {})",
2083                    new_replica_id,
2084                    replica_id
2085                );
2086                new_buffer = Some(cx.new_model(|cx| {
2087                    let mut new_buffer = Buffer::from_proto(
2088                        new_replica_id,
2089                        Capability::ReadWrite,
2090                        old_buffer_state,
2091                        None,
2092                    )
2093                    .unwrap();
2094                    new_buffer
2095                        .apply_ops(
2096                            old_buffer_ops
2097                                .into_iter()
2098                                .map(|op| deserialize_operation(op).unwrap()),
2099                            cx,
2100                        )
2101                        .unwrap();
2102                    log::info!(
2103                        "New replica {} text: {:?}",
2104                        new_buffer.replica_id(),
2105                        new_buffer.text()
2106                    );
2107                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2108                    let network = network.clone();
2109                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2110                        if let Event::Operation(op) = event {
2111                            network.lock().broadcast(
2112                                buffer.replica_id(),
2113                                vec![proto::serialize_operation(op)],
2114                            );
2115                        }
2116                    })
2117                    .detach();
2118                    new_buffer
2119                }));
2120                network.lock().replicate(replica_id, new_replica_id);
2121
2122                if new_replica_id as usize == replica_ids.len() {
2123                    replica_ids.push(new_replica_id);
2124                } else {
2125                    let new_buffer = new_buffer.take().unwrap();
2126                    while network.lock().has_unreceived(new_replica_id) {
2127                        let ops = network
2128                            .lock()
2129                            .receive(new_replica_id)
2130                            .into_iter()
2131                            .map(|op| proto::deserialize_operation(op).unwrap());
2132                        if ops.len() > 0 {
2133                            log::info!(
2134                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2135                                new_replica_id,
2136                                buffer.read(cx).version(),
2137                                ops.len(),
2138                                ops
2139                            );
2140                            new_buffer.update(cx, |new_buffer, cx| {
2141                                new_buffer.apply_ops(ops, cx).unwrap();
2142                            });
2143                        }
2144                    }
2145                    buffers[new_replica_id as usize] = new_buffer;
2146                }
2147            }
2148            60..=69 if mutation_count != 0 => {
2149                buffer.update(cx, |buffer, cx| {
2150                    buffer.randomly_undo_redo(&mut rng, cx);
2151                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2152                });
2153                mutation_count -= 1;
2154            }
2155            _ if network.lock().has_unreceived(replica_id) => {
2156                let ops = network
2157                    .lock()
2158                    .receive(replica_id)
2159                    .into_iter()
2160                    .map(|op| proto::deserialize_operation(op).unwrap());
2161                if ops.len() > 0 {
2162                    log::info!(
2163                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2164                        replica_id,
2165                        buffer.read(cx).version(),
2166                        ops.len(),
2167                        ops
2168                    );
2169                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2170                }
2171            }
2172            _ => {}
2173        }
2174
2175        now += Duration::from_millis(rng.gen_range(0..=200));
2176        buffers.extend(new_buffer);
2177
2178        for buffer in &buffers {
2179            buffer.read(cx).check_invariants();
2180        }
2181
2182        if mutation_count == 0 && network.lock().is_idle() {
2183            break;
2184        }
2185    }
2186
2187    let first_buffer = buffers[0].read(cx).snapshot();
2188    for buffer in &buffers[1..] {
2189        let buffer = buffer.read(cx).snapshot();
2190        assert_eq!(
2191            buffer.version(),
2192            first_buffer.version(),
2193            "Replica {} version != Replica 0 version",
2194            buffer.replica_id()
2195        );
2196        assert_eq!(
2197            buffer.text(),
2198            first_buffer.text(),
2199            "Replica {} text != Replica 0 text",
2200            buffer.replica_id()
2201        );
2202        assert_eq!(
2203            buffer
2204                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2205                .collect::<Vec<_>>(),
2206            first_buffer
2207                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2208                .collect::<Vec<_>>(),
2209            "Replica {} diagnostics != Replica 0 diagnostics",
2210            buffer.replica_id()
2211        );
2212    }
2213
2214    for buffer in &buffers {
2215        let buffer = buffer.read(cx).snapshot();
2216        let actual_remote_selections = buffer
2217            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2218            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2219            .collect::<Vec<_>>();
2220        let expected_remote_selections = active_selections
2221            .iter()
2222            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2223            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2224            .collect::<Vec<_>>();
2225        assert_eq!(
2226            actual_remote_selections,
2227            expected_remote_selections,
2228            "Replica {} remote selections != expected selections",
2229            buffer.replica_id()
2230        );
2231    }
2232}
2233
2234#[test]
2235fn test_contiguous_ranges() {
2236    assert_eq!(
2237        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2238        &[1..4, 5..7, 9..13]
2239    );
2240
2241    // Respects the `max_len` parameter
2242    assert_eq!(
2243        contiguous_ranges(
2244            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2245            3
2246        )
2247        .collect::<Vec<_>>(),
2248        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2249    );
2250}
2251
2252#[gpui::test(iterations = 500)]
2253fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2254    // Generate a random multi-line string containing
2255    // some lines with trailing whitespace.
2256    let mut text = String::new();
2257    for _ in 0..rng.gen_range(0..16) {
2258        for _ in 0..rng.gen_range(0..36) {
2259            text.push(match rng.gen_range(0..10) {
2260                0..=1 => ' ',
2261                3 => '\t',
2262                _ => rng.gen_range('a'..'z'),
2263            });
2264        }
2265        text.push('\n');
2266    }
2267
2268    match rng.gen_range(0..10) {
2269        // sometimes remove the last newline
2270        0..=1 => drop(text.pop()), //
2271
2272        // sometimes add extra newlines
2273        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2274        _ => {}
2275    }
2276
2277    let rope = Rope::from(text.as_str());
2278    let actual_ranges = trailing_whitespace_ranges(&rope);
2279    let expected_ranges = TRAILING_WHITESPACE_REGEX
2280        .find_iter(&text)
2281        .map(|m| m.range())
2282        .collect::<Vec<_>>();
2283    assert_eq!(
2284        actual_ranges,
2285        expected_ranges,
2286        "wrong ranges for text lines:\n{:?}",
2287        text.split("\n").collect::<Vec<_>>()
2288    );
2289}
2290
2291fn ruby_lang() -> Language {
2292    Language::new(
2293        LanguageConfig {
2294            name: "Ruby".into(),
2295            path_suffixes: vec!["rb".to_string()],
2296            line_comment: Some("# ".into()),
2297            ..Default::default()
2298        },
2299        Some(tree_sitter_ruby::language()),
2300    )
2301    .with_indents_query(
2302        r#"
2303            (class "end" @end) @indent
2304            (method "end" @end) @indent
2305            (rescue) @outdent
2306            (then) @indent
2307        "#,
2308    )
2309    .unwrap()
2310}
2311
2312fn html_lang() -> Language {
2313    Language::new(
2314        LanguageConfig {
2315            name: "HTML".into(),
2316            block_comment: Some(("<!--".into(), "-->".into())),
2317            ..Default::default()
2318        },
2319        Some(tree_sitter_html::language()),
2320    )
2321    .with_indents_query(
2322        "
2323        (element
2324          (start_tag) @start
2325          (end_tag)? @end) @indent
2326        ",
2327    )
2328    .unwrap()
2329    .with_injection_query(
2330        r#"
2331        (script_element
2332            (raw_text) @content
2333            (#set! "language" "javascript"))
2334        "#,
2335    )
2336    .unwrap()
2337}
2338
2339fn erb_lang() -> Language {
2340    Language::new(
2341        LanguageConfig {
2342            name: "ERB".into(),
2343            path_suffixes: vec!["erb".to_string()],
2344            block_comment: Some(("<%#".into(), "%>".into())),
2345            ..Default::default()
2346        },
2347        Some(tree_sitter_embedded_template::language()),
2348    )
2349    .with_injection_query(
2350        r#"
2351            (
2352                (code) @content
2353                (#set! "language" "ruby")
2354                (#set! "combined")
2355            )
2356
2357            (
2358                (content) @content
2359                (#set! "language" "html")
2360                (#set! "combined")
2361            )
2362        "#,
2363    )
2364    .unwrap()
2365}
2366
2367fn rust_lang() -> Language {
2368    Language::new(
2369        LanguageConfig {
2370            name: "Rust".into(),
2371            path_suffixes: vec!["rs".to_string()],
2372            ..Default::default()
2373        },
2374        Some(tree_sitter_rust::language()),
2375    )
2376    .with_indents_query(
2377        r#"
2378        (call_expression) @indent
2379        (field_expression) @indent
2380        (_ "(" ")" @end) @indent
2381        (_ "{" "}" @end) @indent
2382        "#,
2383    )
2384    .unwrap()
2385    .with_brackets_query(
2386        r#"
2387        ("{" @open "}" @close)
2388        "#,
2389    )
2390    .unwrap()
2391    .with_outline_query(
2392        r#"
2393        (struct_item
2394            "struct" @context
2395            name: (_) @name) @item
2396        (enum_item
2397            "enum" @context
2398            name: (_) @name) @item
2399        (enum_variant
2400            name: (_) @name) @item
2401        (field_declaration
2402            name: (_) @name) @item
2403        (impl_item
2404            "impl" @context
2405            trait: (_)? @name
2406            "for"? @context
2407            type: (_) @name) @item
2408        (function_item
2409            "fn" @context
2410            name: (_) @name) @item
2411        (mod_item
2412            "mod" @context
2413            name: (_) @name) @item
2414        "#,
2415    )
2416    .unwrap()
2417}
2418
2419fn json_lang() -> Language {
2420    Language::new(
2421        LanguageConfig {
2422            name: "Json".into(),
2423            path_suffixes: vec!["js".to_string()],
2424            ..Default::default()
2425        },
2426        Some(tree_sitter_json::language()),
2427    )
2428}
2429
2430fn javascript_lang() -> Language {
2431    Language::new(
2432        LanguageConfig {
2433            name: "JavaScript".into(),
2434            ..Default::default()
2435        },
2436        Some(tree_sitter_typescript::language_tsx()),
2437    )
2438    .with_brackets_query(
2439        r#"
2440        ("{" @open "}" @close)
2441        ("(" @open ")" @close)
2442        "#,
2443    )
2444    .unwrap()
2445    .with_indents_query(
2446        r#"
2447        (object "}" @end) @indent
2448        "#,
2449    )
2450    .unwrap()
2451}
2452
2453fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2454    buffer.update(cx, |buffer, _| {
2455        let snapshot = buffer.snapshot();
2456        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2457        layers[0].node().to_sexp()
2458    })
2459}
2460
2461// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2462fn assert_bracket_pairs(
2463    selection_text: &'static str,
2464    bracket_pair_texts: Vec<&'static str>,
2465    language: Language,
2466    cx: &mut AppContext,
2467) {
2468    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2469    let buffer = cx.new_model(|cx| {
2470        Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone())
2471            .with_language(Arc::new(language), cx)
2472    });
2473    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2474
2475    let selection_range = selection_ranges[0].clone();
2476
2477    let bracket_pairs = bracket_pair_texts
2478        .into_iter()
2479        .map(|pair_text| {
2480            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2481            assert_eq!(bracket_text, expected_text);
2482            (ranges[0].clone(), ranges[1].clone())
2483        })
2484        .collect::<Vec<_>>();
2485
2486    assert_set_eq!(
2487        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2488        bracket_pairs
2489    );
2490}
2491
2492fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2493    let settings_store = SettingsStore::test(cx);
2494    cx.set_global(settings_store);
2495    crate::init(cx);
2496    cx.update_global::<SettingsStore, _>(|settings, cx| {
2497        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2498    });
2499}