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_comments: vec!["// ".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_comments: 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_prefixes().unwrap(), &[Arc::from("// ")]);
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!(
1732            string_config.line_comment_prefixes().unwrap(),
1733            &[Arc::from("// ")]
1734        );
1735        // Second bracket pair is disabled
1736        assert_eq!(
1737            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1738            &[true, false]
1739        );
1740
1741        // In between JSX tags: use the `element` override.
1742        let element_config = snapshot
1743            .language_scope_at(text.find("<F>").unwrap())
1744            .unwrap();
1745        assert_eq!(element_config.line_comment_prefixes(), None);
1746        assert_eq!(
1747            element_config.block_comment_delimiters(),
1748            Some((&"{/*".into(), &"*/}".into()))
1749        );
1750        assert_eq!(
1751            element_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1752            &[true, true]
1753        );
1754
1755        // Within a JSX tag: use the default config.
1756        let tag_config = snapshot
1757            .language_scope_at(text.find(" d=").unwrap() + 1)
1758            .unwrap();
1759        assert_eq!(
1760            tag_config.line_comment_prefixes().unwrap(),
1761            &[Arc::from("// ")]
1762        );
1763        assert_eq!(
1764            tag_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1765            &[true, true]
1766        );
1767
1768        // In a JSX expression: use the default config.
1769        let expression_in_element_config = snapshot
1770            .language_scope_at(text.find("{").unwrap() + 1)
1771            .unwrap();
1772        assert_eq!(
1773            expression_in_element_config
1774                .line_comment_prefixes()
1775                .unwrap(),
1776            &[Arc::from("// ")]
1777        );
1778        assert_eq!(
1779            expression_in_element_config
1780                .brackets()
1781                .map(|e| e.1)
1782                .collect::<Vec<_>>(),
1783            &[true, true]
1784        );
1785
1786        buffer
1787    });
1788}
1789
1790#[gpui::test]
1791fn test_language_scope_at_with_rust(cx: &mut AppContext) {
1792    init_settings(cx, |_| {});
1793
1794    cx.new_model(|cx| {
1795        let language = Language::new(
1796            LanguageConfig {
1797                name: "Rust".into(),
1798                brackets: BracketPairConfig {
1799                    pairs: vec![
1800                        BracketPair {
1801                            start: "{".into(),
1802                            end: "}".into(),
1803                            close: true,
1804                            newline: false,
1805                        },
1806                        BracketPair {
1807                            start: "'".into(),
1808                            end: "'".into(),
1809                            close: true,
1810                            newline: false,
1811                        },
1812                    ],
1813                    disabled_scopes_by_bracket_ix: vec![
1814                        Vec::new(), //
1815                        vec!["string".into()],
1816                    ],
1817                },
1818                ..Default::default()
1819            },
1820            Some(tree_sitter_rust::language()),
1821        )
1822        .with_override_query(
1823            r#"
1824                (string_literal) @string
1825            "#,
1826        )
1827        .unwrap();
1828
1829        let text = r#"
1830            const S: &'static str = "hello";
1831        "#
1832        .unindent();
1833
1834        let buffer = Buffer::new(0, cx.entity_id().as_u64(), text.clone())
1835            .with_language(Arc::new(language), cx);
1836        let snapshot = buffer.snapshot();
1837
1838        // By default, all brackets are enabled
1839        let config = snapshot.language_scope_at(0).unwrap();
1840        assert_eq!(
1841            config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1842            &[true, true]
1843        );
1844
1845        // Within a string, the quotation brackets are disabled.
1846        let string_config = snapshot
1847            .language_scope_at(text.find("ello").unwrap())
1848            .unwrap();
1849        assert_eq!(
1850            string_config.brackets().map(|e| e.1).collect::<Vec<_>>(),
1851            &[true, false]
1852        );
1853
1854        buffer
1855    });
1856}
1857
1858#[gpui::test]
1859fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) {
1860    init_settings(cx, |_| {});
1861
1862    cx.new_model(|cx| {
1863        let text = r#"
1864            <ol>
1865            <% people.each do |person| %>
1866                <li>
1867                    <%= person.name %>
1868                </li>
1869            <% end %>
1870            </ol>
1871        "#
1872        .unindent();
1873
1874        let language_registry = Arc::new(LanguageRegistry::test());
1875        language_registry.add(Arc::new(ruby_lang()));
1876        language_registry.add(Arc::new(html_lang()));
1877        language_registry.add(Arc::new(erb_lang()));
1878
1879        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text);
1880        buffer.set_language_registry(language_registry.clone());
1881        buffer.set_language(
1882            language_registry
1883                .language_for_name("ERB")
1884                .now_or_never()
1885                .unwrap()
1886                .ok(),
1887            cx,
1888        );
1889
1890        let snapshot = buffer.snapshot();
1891        let html_config = snapshot.language_scope_at(Point::new(2, 4)).unwrap();
1892        assert_eq!(html_config.line_comment_prefixes(), Some(&vec![]));
1893        assert_eq!(
1894            html_config.block_comment_delimiters(),
1895            Some((&"<!--".into(), &"-->".into()))
1896        );
1897
1898        let ruby_config = snapshot.language_scope_at(Point::new(3, 12)).unwrap();
1899        assert_eq!(
1900            ruby_config.line_comment_prefixes().unwrap(),
1901            &[Arc::from("# ")]
1902        );
1903        assert_eq!(ruby_config.block_comment_delimiters(), None);
1904
1905        buffer
1906    });
1907}
1908
1909#[gpui::test]
1910fn test_serialization(cx: &mut gpui::AppContext) {
1911    let mut now = Instant::now();
1912
1913    let buffer1 = cx.new_model(|cx| {
1914        let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "abc");
1915        buffer.edit([(3..3, "D")], None, cx);
1916
1917        now += Duration::from_secs(1);
1918        buffer.start_transaction_at(now);
1919        buffer.edit([(4..4, "E")], None, cx);
1920        buffer.end_transaction_at(now, cx);
1921        assert_eq!(buffer.text(), "abcDE");
1922
1923        buffer.undo(cx);
1924        assert_eq!(buffer.text(), "abcD");
1925
1926        buffer.edit([(4..4, "F")], None, cx);
1927        assert_eq!(buffer.text(), "abcDF");
1928        buffer
1929    });
1930    assert_eq!(buffer1.read(cx).text(), "abcDF");
1931
1932    let state = buffer1.read(cx).to_proto();
1933    let ops = cx
1934        .background_executor()
1935        .block(buffer1.read(cx).serialize_ops(None, cx));
1936    let buffer2 = cx.new_model(|cx| {
1937        let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
1938        buffer
1939            .apply_ops(
1940                ops.into_iter()
1941                    .map(|op| proto::deserialize_operation(op).unwrap()),
1942                cx,
1943            )
1944            .unwrap();
1945        buffer
1946    });
1947    assert_eq!(buffer2.read(cx).text(), "abcDF");
1948}
1949
1950#[gpui::test(iterations = 100)]
1951fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
1952    let min_peers = env::var("MIN_PEERS")
1953        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
1954        .unwrap_or(1);
1955    let max_peers = env::var("MAX_PEERS")
1956        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
1957        .unwrap_or(5);
1958    let operations = env::var("OPERATIONS")
1959        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
1960        .unwrap_or(10);
1961
1962    let base_text_len = rng.gen_range(0..10);
1963    let base_text = RandomCharIter::new(&mut rng)
1964        .take(base_text_len)
1965        .collect::<String>();
1966    let mut replica_ids = Vec::new();
1967    let mut buffers = Vec::new();
1968    let network = Arc::new(Mutex::new(Network::new(rng.clone())));
1969    let base_buffer =
1970        cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str()));
1971
1972    for i in 0..rng.gen_range(min_peers..=max_peers) {
1973        let buffer = cx.new_model(|cx| {
1974            let state = base_buffer.read(cx).to_proto();
1975            let ops = cx
1976                .background_executor()
1977                .block(base_buffer.read(cx).serialize_ops(None, cx));
1978            let mut buffer =
1979                Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
1980            buffer
1981                .apply_ops(
1982                    ops.into_iter()
1983                        .map(|op| proto::deserialize_operation(op).unwrap()),
1984                    cx,
1985                )
1986                .unwrap();
1987            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
1988            let network = network.clone();
1989            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
1990                if let Event::Operation(op) = event {
1991                    network
1992                        .lock()
1993                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
1994                }
1995            })
1996            .detach();
1997            buffer
1998        });
1999
2000        buffers.push(buffer);
2001        replica_ids.push(i as ReplicaId);
2002        network.lock().add_peer(i as ReplicaId);
2003        log::info!("Adding initial peer with replica id {}", i);
2004    }
2005
2006    log::info!("initial text: {:?}", base_text);
2007
2008    let mut now = Instant::now();
2009    let mut mutation_count = operations;
2010    let mut next_diagnostic_id = 0;
2011    let mut active_selections = BTreeMap::default();
2012    loop {
2013        let replica_index = rng.gen_range(0..replica_ids.len());
2014        let replica_id = replica_ids[replica_index];
2015        let buffer = &mut buffers[replica_index];
2016        let mut new_buffer = None;
2017        match rng.gen_range(0..100) {
2018            0..=29 if mutation_count != 0 => {
2019                buffer.update(cx, |buffer, cx| {
2020                    buffer.start_transaction_at(now);
2021                    buffer.randomly_edit(&mut rng, 5, cx);
2022                    buffer.end_transaction_at(now, cx);
2023                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2024                });
2025                mutation_count -= 1;
2026            }
2027            30..=39 if mutation_count != 0 => {
2028                buffer.update(cx, |buffer, cx| {
2029                    if rng.gen_bool(0.2) {
2030                        log::info!("peer {} clearing active selections", replica_id);
2031                        active_selections.remove(&replica_id);
2032                        buffer.remove_active_selections(cx);
2033                    } else {
2034                        let mut selections = Vec::new();
2035                        for id in 0..rng.gen_range(1..=5) {
2036                            let range = buffer.random_byte_range(0, &mut rng);
2037                            selections.push(Selection {
2038                                id,
2039                                start: buffer.anchor_before(range.start),
2040                                end: buffer.anchor_before(range.end),
2041                                reversed: false,
2042                                goal: SelectionGoal::None,
2043                            });
2044                        }
2045                        let selections: Arc<[Selection<Anchor>]> = selections.into();
2046                        log::info!(
2047                            "peer {} setting active selections: {:?}",
2048                            replica_id,
2049                            selections
2050                        );
2051                        active_selections.insert(replica_id, selections.clone());
2052                        buffer.set_active_selections(selections, false, Default::default(), cx);
2053                    }
2054                });
2055                mutation_count -= 1;
2056            }
2057            40..=49 if mutation_count != 0 && replica_id == 0 => {
2058                let entry_count = rng.gen_range(1..=5);
2059                buffer.update(cx, |buffer, cx| {
2060                    let diagnostics = DiagnosticSet::new(
2061                        (0..entry_count).map(|_| {
2062                            let range = buffer.random_byte_range(0, &mut rng);
2063                            let range = range.to_point_utf16(buffer);
2064                            let range = range.start..range.end;
2065                            DiagnosticEntry {
2066                                range,
2067                                diagnostic: Diagnostic {
2068                                    message: post_inc(&mut next_diagnostic_id).to_string(),
2069                                    ..Default::default()
2070                                },
2071                            }
2072                        }),
2073                        buffer,
2074                    );
2075                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
2076                    buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
2077                });
2078                mutation_count -= 1;
2079            }
2080            50..=59 if replica_ids.len() < max_peers => {
2081                let old_buffer_state = buffer.read(cx).to_proto();
2082                let old_buffer_ops = cx
2083                    .background_executor()
2084                    .block(buffer.read(cx).serialize_ops(None, cx));
2085                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
2086                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
2087                    .choose(&mut rng)
2088                    .unwrap();
2089                log::info!(
2090                    "Adding new replica {} (replicating from {})",
2091                    new_replica_id,
2092                    replica_id
2093                );
2094                new_buffer = Some(cx.new_model(|cx| {
2095                    let mut new_buffer = Buffer::from_proto(
2096                        new_replica_id,
2097                        Capability::ReadWrite,
2098                        old_buffer_state,
2099                        None,
2100                    )
2101                    .unwrap();
2102                    new_buffer
2103                        .apply_ops(
2104                            old_buffer_ops
2105                                .into_iter()
2106                                .map(|op| deserialize_operation(op).unwrap()),
2107                            cx,
2108                        )
2109                        .unwrap();
2110                    log::info!(
2111                        "New replica {} text: {:?}",
2112                        new_buffer.replica_id(),
2113                        new_buffer.text()
2114                    );
2115                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
2116                    let network = network.clone();
2117                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
2118                        if let Event::Operation(op) = event {
2119                            network.lock().broadcast(
2120                                buffer.replica_id(),
2121                                vec![proto::serialize_operation(op)],
2122                            );
2123                        }
2124                    })
2125                    .detach();
2126                    new_buffer
2127                }));
2128                network.lock().replicate(replica_id, new_replica_id);
2129
2130                if new_replica_id as usize == replica_ids.len() {
2131                    replica_ids.push(new_replica_id);
2132                } else {
2133                    let new_buffer = new_buffer.take().unwrap();
2134                    while network.lock().has_unreceived(new_replica_id) {
2135                        let ops = network
2136                            .lock()
2137                            .receive(new_replica_id)
2138                            .into_iter()
2139                            .map(|op| proto::deserialize_operation(op).unwrap());
2140                        if ops.len() > 0 {
2141                            log::info!(
2142                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2143                                new_replica_id,
2144                                buffer.read(cx).version(),
2145                                ops.len(),
2146                                ops
2147                            );
2148                            new_buffer.update(cx, |new_buffer, cx| {
2149                                new_buffer.apply_ops(ops, cx).unwrap();
2150                            });
2151                        }
2152                    }
2153                    buffers[new_replica_id as usize] = new_buffer;
2154                }
2155            }
2156            60..=69 if mutation_count != 0 => {
2157                buffer.update(cx, |buffer, cx| {
2158                    buffer.randomly_undo_redo(&mut rng, cx);
2159                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
2160                });
2161                mutation_count -= 1;
2162            }
2163            _ if network.lock().has_unreceived(replica_id) => {
2164                let ops = network
2165                    .lock()
2166                    .receive(replica_id)
2167                    .into_iter()
2168                    .map(|op| proto::deserialize_operation(op).unwrap());
2169                if ops.len() > 0 {
2170                    log::info!(
2171                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
2172                        replica_id,
2173                        buffer.read(cx).version(),
2174                        ops.len(),
2175                        ops
2176                    );
2177                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
2178                }
2179            }
2180            _ => {}
2181        }
2182
2183        now += Duration::from_millis(rng.gen_range(0..=200));
2184        buffers.extend(new_buffer);
2185
2186        for buffer in &buffers {
2187            buffer.read(cx).check_invariants();
2188        }
2189
2190        if mutation_count == 0 && network.lock().is_idle() {
2191            break;
2192        }
2193    }
2194
2195    let first_buffer = buffers[0].read(cx).snapshot();
2196    for buffer in &buffers[1..] {
2197        let buffer = buffer.read(cx).snapshot();
2198        assert_eq!(
2199            buffer.version(),
2200            first_buffer.version(),
2201            "Replica {} version != Replica 0 version",
2202            buffer.replica_id()
2203        );
2204        assert_eq!(
2205            buffer.text(),
2206            first_buffer.text(),
2207            "Replica {} text != Replica 0 text",
2208            buffer.replica_id()
2209        );
2210        assert_eq!(
2211            buffer
2212                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
2213                .collect::<Vec<_>>(),
2214            first_buffer
2215                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
2216                .collect::<Vec<_>>(),
2217            "Replica {} diagnostics != Replica 0 diagnostics",
2218            buffer.replica_id()
2219        );
2220    }
2221
2222    for buffer in &buffers {
2223        let buffer = buffer.read(cx).snapshot();
2224        let actual_remote_selections = buffer
2225            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
2226            .map(|(replica_id, _, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
2227            .collect::<Vec<_>>();
2228        let expected_remote_selections = active_selections
2229            .iter()
2230            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
2231            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
2232            .collect::<Vec<_>>();
2233        assert_eq!(
2234            actual_remote_selections,
2235            expected_remote_selections,
2236            "Replica {} remote selections != expected selections",
2237            buffer.replica_id()
2238        );
2239    }
2240}
2241
2242#[test]
2243fn test_contiguous_ranges() {
2244    assert_eq!(
2245        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
2246        &[1..4, 5..7, 9..13]
2247    );
2248
2249    // Respects the `max_len` parameter
2250    assert_eq!(
2251        contiguous_ranges(
2252            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
2253            3
2254        )
2255        .collect::<Vec<_>>(),
2256        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
2257    );
2258}
2259
2260#[gpui::test(iterations = 500)]
2261fn test_trailing_whitespace_ranges(mut rng: StdRng) {
2262    // Generate a random multi-line string containing
2263    // some lines with trailing whitespace.
2264    let mut text = String::new();
2265    for _ in 0..rng.gen_range(0..16) {
2266        for _ in 0..rng.gen_range(0..36) {
2267            text.push(match rng.gen_range(0..10) {
2268                0..=1 => ' ',
2269                3 => '\t',
2270                _ => rng.gen_range('a'..'z'),
2271            });
2272        }
2273        text.push('\n');
2274    }
2275
2276    match rng.gen_range(0..10) {
2277        // sometimes remove the last newline
2278        0..=1 => drop(text.pop()), //
2279
2280        // sometimes add extra newlines
2281        2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
2282        _ => {}
2283    }
2284
2285    let rope = Rope::from(text.as_str());
2286    let actual_ranges = trailing_whitespace_ranges(&rope);
2287    let expected_ranges = TRAILING_WHITESPACE_REGEX
2288        .find_iter(&text)
2289        .map(|m| m.range())
2290        .collect::<Vec<_>>();
2291    assert_eq!(
2292        actual_ranges,
2293        expected_ranges,
2294        "wrong ranges for text lines:\n{:?}",
2295        text.split("\n").collect::<Vec<_>>()
2296    );
2297}
2298
2299fn ruby_lang() -> Language {
2300    Language::new(
2301        LanguageConfig {
2302            name: "Ruby".into(),
2303            path_suffixes: vec!["rb".to_string()],
2304            line_comments: vec!["# ".into()],
2305            ..Default::default()
2306        },
2307        Some(tree_sitter_ruby::language()),
2308    )
2309    .with_indents_query(
2310        r#"
2311            (class "end" @end) @indent
2312            (method "end" @end) @indent
2313            (rescue) @outdent
2314            (then) @indent
2315        "#,
2316    )
2317    .unwrap()
2318}
2319
2320fn html_lang() -> Language {
2321    Language::new(
2322        LanguageConfig {
2323            name: "HTML".into(),
2324            block_comment: Some(("<!--".into(), "-->".into())),
2325            ..Default::default()
2326        },
2327        Some(tree_sitter_html::language()),
2328    )
2329    .with_indents_query(
2330        "
2331        (element
2332          (start_tag) @start
2333          (end_tag)? @end) @indent
2334        ",
2335    )
2336    .unwrap()
2337    .with_injection_query(
2338        r#"
2339        (script_element
2340            (raw_text) @content
2341            (#set! "language" "javascript"))
2342        "#,
2343    )
2344    .unwrap()
2345}
2346
2347fn erb_lang() -> Language {
2348    Language::new(
2349        LanguageConfig {
2350            name: "ERB".into(),
2351            path_suffixes: vec!["erb".to_string()],
2352            block_comment: Some(("<%#".into(), "%>".into())),
2353            ..Default::default()
2354        },
2355        Some(tree_sitter_embedded_template::language()),
2356    )
2357    .with_injection_query(
2358        r#"
2359            (
2360                (code) @content
2361                (#set! "language" "ruby")
2362                (#set! "combined")
2363            )
2364
2365            (
2366                (content) @content
2367                (#set! "language" "html")
2368                (#set! "combined")
2369            )
2370        "#,
2371    )
2372    .unwrap()
2373}
2374
2375fn rust_lang() -> Language {
2376    Language::new(
2377        LanguageConfig {
2378            name: "Rust".into(),
2379            path_suffixes: vec!["rs".to_string()],
2380            ..Default::default()
2381        },
2382        Some(tree_sitter_rust::language()),
2383    )
2384    .with_indents_query(
2385        r#"
2386        (call_expression) @indent
2387        (field_expression) @indent
2388        (_ "(" ")" @end) @indent
2389        (_ "{" "}" @end) @indent
2390        "#,
2391    )
2392    .unwrap()
2393    .with_brackets_query(
2394        r#"
2395        ("{" @open "}" @close)
2396        "#,
2397    )
2398    .unwrap()
2399    .with_outline_query(
2400        r#"
2401        (struct_item
2402            "struct" @context
2403            name: (_) @name) @item
2404        (enum_item
2405            "enum" @context
2406            name: (_) @name) @item
2407        (enum_variant
2408            name: (_) @name) @item
2409        (field_declaration
2410            name: (_) @name) @item
2411        (impl_item
2412            "impl" @context
2413            trait: (_)? @name
2414            "for"? @context
2415            type: (_) @name) @item
2416        (function_item
2417            "fn" @context
2418            name: (_) @name) @item
2419        (mod_item
2420            "mod" @context
2421            name: (_) @name) @item
2422        "#,
2423    )
2424    .unwrap()
2425}
2426
2427fn json_lang() -> Language {
2428    Language::new(
2429        LanguageConfig {
2430            name: "Json".into(),
2431            path_suffixes: vec!["js".to_string()],
2432            ..Default::default()
2433        },
2434        Some(tree_sitter_json::language()),
2435    )
2436}
2437
2438fn javascript_lang() -> Language {
2439    Language::new(
2440        LanguageConfig {
2441            name: "JavaScript".into(),
2442            ..Default::default()
2443        },
2444        Some(tree_sitter_typescript::language_tsx()),
2445    )
2446    .with_brackets_query(
2447        r#"
2448        ("{" @open "}" @close)
2449        ("(" @open ")" @close)
2450        "#,
2451    )
2452    .unwrap()
2453    .with_indents_query(
2454        r#"
2455        (object "}" @end) @indent
2456        "#,
2457    )
2458    .unwrap()
2459}
2460
2461fn get_tree_sexp(buffer: &Model<Buffer>, cx: &mut gpui::TestAppContext) -> String {
2462    buffer.update(cx, |buffer, _| {
2463        let snapshot = buffer.snapshot();
2464        let layers = snapshot.syntax.layers(buffer.as_text_snapshot());
2465        layers[0].node().to_sexp()
2466    })
2467}
2468
2469// Assert that the enclosing bracket ranges around the selection match the pairs indicated by the marked text in `range_markers`
2470fn assert_bracket_pairs(
2471    selection_text: &'static str,
2472    bracket_pair_texts: Vec<&'static str>,
2473    language: Language,
2474    cx: &mut AppContext,
2475) {
2476    let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false);
2477    let buffer = cx.new_model(|cx| {
2478        Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone())
2479            .with_language(Arc::new(language), cx)
2480    });
2481    let buffer = buffer.update(cx, |buffer, _cx| buffer.snapshot());
2482
2483    let selection_range = selection_ranges[0].clone();
2484
2485    let bracket_pairs = bracket_pair_texts
2486        .into_iter()
2487        .map(|pair_text| {
2488            let (bracket_text, ranges) = marked_text_ranges(pair_text, false);
2489            assert_eq!(bracket_text, expected_text);
2490            (ranges[0].clone(), ranges[1].clone())
2491        })
2492        .collect::<Vec<_>>();
2493
2494    assert_set_eq!(
2495        buffer.bracket_ranges(selection_range).collect::<Vec<_>>(),
2496        bracket_pairs
2497    );
2498}
2499
2500fn init_settings(cx: &mut AppContext, f: fn(&mut AllLanguageSettingsContent)) {
2501    let settings_store = SettingsStore::test(cx);
2502    cx.set_global(settings_store);
2503    crate::init(cx);
2504    cx.update_global::<SettingsStore, _>(|settings, cx| {
2505        settings.update_user_settings::<AllLanguageSettings>(cx, f);
2506    });
2507}