code_completion_tests.rs

   1use crate::{
   2    code_context_menus::{CompletionsMenu, SortableMatch},
   3    editor_settings::SnippetSortOrder,
   4};
   5use fuzzy::StringMatch;
   6use gpui::TestAppContext;
   7
   8#[gpui::test]
   9fn test_sort_matches_local_variable_over_global_variable(_cx: &mut TestAppContext) {
  10    // Case 1: "foo"
  11    let query: Option<&str> = Some("foo");
  12    let mut matches: Vec<SortableMatch<'_>> = vec![
  13        SortableMatch {
  14            string_match: StringMatch {
  15                candidate_id: 0,
  16                score: 0.2727272727272727,
  17                positions: vec![],
  18                string: "foo_bar_baz".to_string(),
  19            },
  20            is_snippet: false,
  21            sort_text: Some("7fffffff"),
  22            sort_key: (2, "foo_bar_baz"),
  23        },
  24        SortableMatch {
  25            string_match: StringMatch {
  26                candidate_id: 0,
  27                score: 0.2727272727272727,
  28                positions: vec![],
  29                string: "foo_bar_qux".to_string(),
  30            },
  31            is_snippet: false,
  32            sort_text: Some("7ffffffe"),
  33            sort_key: (1, "foo_bar_qux"),
  34        },
  35        SortableMatch {
  36            string_match: StringMatch {
  37                candidate_id: 0,
  38                score: 0.22499999999999998,
  39                positions: vec![],
  40                string: "floorf64".to_string(),
  41            },
  42            is_snippet: false,
  43            sort_text: Some("80000000"),
  44            sort_key: (2, "floorf64"),
  45        },
  46        SortableMatch {
  47            string_match: StringMatch {
  48                candidate_id: 0,
  49                score: 0.22499999999999998,
  50                positions: vec![],
  51                string: "floorf32".to_string(),
  52            },
  53            is_snippet: false,
  54            sort_text: Some("80000000"),
  55            sort_key: (2, "floorf32"),
  56        },
  57        SortableMatch {
  58            string_match: StringMatch {
  59                candidate_id: 0,
  60                score: 0.22499999999999998,
  61                positions: vec![],
  62                string: "floorf16".to_string(),
  63            },
  64            is_snippet: false,
  65            sort_text: Some("80000000"),
  66            sort_key: (2, "floorf16"),
  67        },
  68        SortableMatch {
  69            string_match: StringMatch {
  70                candidate_id: 0,
  71                score: 0.2,
  72                positions: vec![],
  73                string: "floorf128".to_string(),
  74            },
  75            is_snippet: false,
  76            sort_text: Some("80000000"),
  77            sort_key: (2, "floorf128"),
  78        },
  79    ];
  80    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
  81    assert_eq!(
  82        matches[0].string_match.string.as_str(),
  83        "foo_bar_qux",
  84        "Match order not expected"
  85    );
  86    assert_eq!(
  87        matches[1].string_match.string.as_str(),
  88        "foo_bar_baz",
  89        "Match order not expected"
  90    );
  91    assert_eq!(
  92        matches[2].string_match.string.as_str(),
  93        "floorf16",
  94        "Match order not expected"
  95    );
  96    assert_eq!(
  97        matches[3].string_match.string.as_str(),
  98        "floorf32",
  99        "Match order not expected"
 100    );
 101
 102    // Case 2: "foobar"
 103    let query: Option<&str> = Some("foobar");
 104    let mut matches: Vec<SortableMatch<'_>> = vec![
 105        SortableMatch {
 106            string_match: StringMatch {
 107                candidate_id: 0,
 108                score: 0.4363636363636364,
 109                positions: vec![],
 110                string: "foo_bar_baz".to_string(),
 111            },
 112            is_snippet: false,
 113            sort_text: Some("7fffffff"),
 114            sort_key: (2, "foo_bar_baz"),
 115        },
 116        SortableMatch {
 117            string_match: StringMatch {
 118                candidate_id: 0,
 119                score: 0.4363636363636364,
 120                positions: vec![],
 121                string: "foo_bar_qux".to_string(),
 122            },
 123            is_snippet: false,
 124            sort_text: Some("7ffffffe"),
 125            sort_key: (1, "foo_bar_qux"),
 126        },
 127    ];
 128    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 129    assert_eq!(
 130        matches[0].string_match.string.as_str(),
 131        "foo_bar_qux",
 132        "Match order not expected"
 133    );
 134    assert_eq!(
 135        matches[1].string_match.string.as_str(),
 136        "foo_bar_baz",
 137        "Match order not expected"
 138    );
 139}
 140
 141#[gpui::test]
 142fn test_sort_matches_local_variable_over_global_enum(_cx: &mut TestAppContext) {
 143    // Case 1: "ele"
 144    let query: Option<&str> = Some("ele");
 145    let mut matches: Vec<SortableMatch<'_>> = vec![
 146        SortableMatch {
 147            string_match: StringMatch {
 148                candidate_id: 0,
 149                score: 0.2727272727272727,
 150                positions: vec![],
 151                string: "ElementType".to_string(),
 152            },
 153            is_snippet: false,
 154            sort_text: Some("7fffffff"),
 155            sort_key: (2, "ElementType"),
 156        },
 157        SortableMatch {
 158            string_match: StringMatch {
 159                candidate_id: 0,
 160                score: 0.25,
 161                positions: vec![],
 162                string: "element_type".to_string(),
 163            },
 164            is_snippet: false,
 165            sort_text: Some("7ffffffe"),
 166            sort_key: (1, "element_type"),
 167        },
 168        SortableMatch {
 169            string_match: StringMatch {
 170                candidate_id: 0,
 171                score: 0.16363636363636364,
 172                positions: vec![],
 173                string: "simd_select".to_string(),
 174            },
 175            is_snippet: false,
 176            sort_text: Some("80000000"),
 177            sort_key: (2, "simd_select"),
 178        },
 179        SortableMatch {
 180            string_match: StringMatch {
 181                candidate_id: 0,
 182                score: 0.16,
 183                positions: vec![],
 184                string: "while let".to_string(),
 185            },
 186            is_snippet: false,
 187            sort_text: Some("7fffffff"),
 188            sort_key: (0, "while let"),
 189        },
 190    ];
 191    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 192    assert_eq!(
 193        matches[0].string_match.string.as_str(),
 194        "element_type",
 195        "Match order not expected"
 196    );
 197    assert_eq!(
 198        matches[1].string_match.string.as_str(),
 199        "ElementType",
 200        "Match order not expected"
 201    );
 202
 203    // Case 2: "eleme"
 204    let query: Option<&str> = Some("eleme");
 205    let mut matches: Vec<SortableMatch<'_>> = vec![
 206        SortableMatch {
 207            string_match: StringMatch {
 208                candidate_id: 0,
 209                score: 0.4545454545454546,
 210                positions: vec![],
 211                string: "ElementType".to_string(),
 212            },
 213            is_snippet: false,
 214            sort_text: Some("7fffffff"),
 215            sort_key: (2, "ElementType"),
 216        },
 217        SortableMatch {
 218            string_match: StringMatch {
 219                candidate_id: 0,
 220                score: 0.41666666666666663,
 221                positions: vec![],
 222                string: "element_type".to_string(),
 223            },
 224            is_snippet: false,
 225            sort_text: Some("7ffffffe"),
 226            sort_key: (1, "element_type"),
 227        },
 228        SortableMatch {
 229            string_match: StringMatch {
 230                candidate_id: 0,
 231                score: 0.04714285714285713,
 232                positions: vec![],
 233                string: "REPLACEMENT_CHARACTER".to_string(),
 234            },
 235            is_snippet: false,
 236            sort_text: Some("80000000"),
 237            sort_key: (2, "REPLACEMENT_CHARACTER"),
 238        },
 239    ];
 240    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 241    assert_eq!(
 242        matches[0].string_match.string.as_str(),
 243        "element_type",
 244        "Match order not expected"
 245    );
 246    assert_eq!(
 247        matches[1].string_match.string.as_str(),
 248        "ElementType",
 249        "Match order not expected"
 250    );
 251
 252    // Case 3: "Elem"
 253    let query: Option<&str> = Some("Elem");
 254    let mut matches: Vec<SortableMatch<'_>> = vec![
 255        SortableMatch {
 256            string_match: StringMatch {
 257                candidate_id: 0,
 258                score: 0.36363636363636365,
 259                positions: vec![],
 260                string: "ElementType".to_string(),
 261            },
 262            is_snippet: false,
 263            sort_text: Some("7fffffff"),
 264            sort_key: (2, "ElementType"),
 265        },
 266        SortableMatch {
 267            string_match: StringMatch {
 268                candidate_id: 0,
 269                score: 0.0003333333333333333,
 270                positions: vec![],
 271                string: "element_type".to_string(),
 272            },
 273            is_snippet: false,
 274            sort_text: Some("7ffffffe"),
 275            sort_key: (1, "element_type"),
 276        },
 277    ];
 278    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 279    assert_eq!(
 280        matches[0].string_match.string.as_str(),
 281        "ElementType",
 282        "Match order not expected"
 283    );
 284    assert_eq!(
 285        matches[1].string_match.string.as_str(),
 286        "element_type",
 287        "Match order not expected"
 288    );
 289}
 290
 291#[gpui::test]
 292fn test_sort_matches_for_unreachable(_cx: &mut TestAppContext) {
 293    // Case 1: "unre"
 294    let query: Option<&str> = Some("unre");
 295    let mut matches: Vec<SortableMatch<'_>> = vec![
 296        SortableMatch {
 297            string_match: StringMatch {
 298                candidate_id: 0,
 299                score: 0.36363636363636365,
 300                positions: vec![],
 301                string: "unreachable".to_string(),
 302            },
 303            is_snippet: false,
 304            sort_text: Some("80000000"),
 305            sort_key: (2, "unreachable"),
 306        },
 307        SortableMatch {
 308            string_match: StringMatch {
 309                candidate_id: 0,
 310                score: 0.26666666666666666,
 311                positions: vec![],
 312                string: "unreachable!(…)".to_string(),
 313            },
 314            is_snippet: true,
 315            sort_text: Some("7fffffff"),
 316            sort_key: (2, "unreachable!(…)"),
 317        },
 318        SortableMatch {
 319            string_match: StringMatch {
 320                candidate_id: 0,
 321                score: 0.24615384615384617,
 322                positions: vec![],
 323                string: "unchecked_rem".to_string(),
 324            },
 325            is_snippet: false,
 326            sort_text: Some("80000000"),
 327            sort_key: (2, "unchecked_rem"),
 328        },
 329        SortableMatch {
 330            string_match: StringMatch {
 331                candidate_id: 0,
 332                score: 0.19047619047619047,
 333                positions: vec![],
 334                string: "unreachable_unchecked".to_string(),
 335            },
 336            is_snippet: false,
 337            sort_text: Some("80000000"),
 338            sort_key: (2, "unreachable_unchecked"),
 339        },
 340    ];
 341    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 342    assert_eq!(
 343        matches[0].string_match.string.as_str(),
 344        "unreachable!(…)",
 345        "Match order not expected"
 346    );
 347
 348    // Case 2: "unrea"
 349    let query: Option<&str> = Some("unrea");
 350    let mut matches: Vec<SortableMatch<'_>> = vec![
 351        SortableMatch {
 352            string_match: StringMatch {
 353                candidate_id: 0,
 354                score: 0.4545454545454546,
 355                positions: vec![],
 356                string: "unreachable".to_string(),
 357            },
 358            is_snippet: true,
 359            sort_text: Some("80000000"),
 360            sort_key: (3, "unreachable"),
 361        },
 362        SortableMatch {
 363            string_match: StringMatch {
 364                candidate_id: 0,
 365                score: 0.3333333333333333,
 366                positions: vec![],
 367                string: "unreachable!(…)".to_string(),
 368            },
 369            is_snippet: true,
 370            sort_text: Some("7fffffff"),
 371            sort_key: (3, "unreachable!(…)"),
 372        },
 373        SortableMatch {
 374            string_match: StringMatch {
 375                candidate_id: 0,
 376                score: 0.23809523809523808,
 377                positions: vec![],
 378                string: "unreachable_unchecked".to_string(),
 379            },
 380            is_snippet: true,
 381            sort_text: Some("80000000"),
 382            sort_key: (3, "unreachable_unchecked"),
 383        },
 384    ];
 385    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 386    assert_eq!(
 387        matches[0].string_match.string.as_str(),
 388        "unreachable!(…)",
 389        "Match order not expected"
 390    );
 391
 392    // Case 3: "unreach"
 393    let query: Option<&str> = Some("unreach");
 394    let mut matches: Vec<SortableMatch<'_>> = vec![
 395        SortableMatch {
 396            string_match: StringMatch {
 397                candidate_id: 0,
 398                score: 0.6363636363636364,
 399                positions: vec![],
 400                string: "unreachable".to_string(),
 401            },
 402            is_snippet: false,
 403            sort_text: Some("80000000"),
 404            sort_key: (2, "unreachable"),
 405        },
 406        SortableMatch {
 407            string_match: StringMatch {
 408                candidate_id: 0,
 409                score: 0.4666666666666667,
 410                positions: vec![],
 411                string: "unreachable!(…)".to_string(),
 412            },
 413            is_snippet: true,
 414            sort_text: Some("7fffffff"),
 415            sort_key: (2, "unreachable!(…)"),
 416        },
 417        SortableMatch {
 418            string_match: StringMatch {
 419                candidate_id: 0,
 420                score: 0.3333333333333333,
 421                positions: vec![],
 422                string: "unreachable_unchecked".to_string(),
 423            },
 424            is_snippet: false,
 425            sort_text: Some("80000000"),
 426            sort_key: (2, "unreachable_unchecked"),
 427        },
 428    ];
 429    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 430    assert_eq!(
 431        matches[0].string_match.string.as_str(),
 432        "unreachable!(…)",
 433        "Match order not expected"
 434    );
 435
 436    // Case 4: "unreachabl"
 437    let query: Option<&str> = Some("unreachable");
 438    let mut matches: Vec<SortableMatch<'_>> = vec![
 439        SortableMatch {
 440            string_match: StringMatch {
 441                candidate_id: 0,
 442                score: 0.9090909090909092,
 443                positions: vec![],
 444                string: "unreachable".to_string(),
 445            },
 446            is_snippet: false,
 447            sort_text: Some("80000000"),
 448            sort_key: (3, "unreachable"),
 449        },
 450        SortableMatch {
 451            string_match: StringMatch {
 452                candidate_id: 0,
 453                score: 0.6666666666666666,
 454                positions: vec![],
 455                string: "unreachable!(…)".to_string(),
 456            },
 457            is_snippet: false,
 458            sort_text: Some("7fffffff"),
 459            sort_key: (3, "unreachable!(…)"),
 460        },
 461        SortableMatch {
 462            string_match: StringMatch {
 463                candidate_id: 0,
 464                score: 0.47619047619047616,
 465                positions: vec![],
 466                string: "unreachable_unchecked".to_string(),
 467            },
 468            is_snippet: false,
 469            sort_text: Some("80000000"),
 470            sort_key: (3, "unreachable_unchecked"),
 471        },
 472    ];
 473    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 474    assert_eq!(
 475        matches[0].string_match.string.as_str(),
 476        "unreachable!(…)",
 477        "Match order not expected"
 478    );
 479
 480    // Case 5: "unreachable"
 481    let query: Option<&str> = Some("unreachable");
 482    let mut matches: Vec<SortableMatch<'_>> = vec![
 483        SortableMatch {
 484            string_match: StringMatch {
 485                candidate_id: 0,
 486                score: 1.0,
 487                positions: vec![],
 488                string: "unreachable".to_string(),
 489            },
 490            is_snippet: false,
 491            sort_text: Some("80000000"),
 492            sort_key: (2, "unreachable"),
 493        },
 494        SortableMatch {
 495            string_match: StringMatch {
 496                candidate_id: 0,
 497                score: 0.7333333333333333,
 498                positions: vec![],
 499                string: "unreachable!(…)".to_string(),
 500            },
 501            is_snippet: false,
 502            sort_text: Some("7fffffff"),
 503            sort_key: (2, "unreachable!(…)"),
 504        },
 505        SortableMatch {
 506            string_match: StringMatch {
 507                candidate_id: 0,
 508                score: 0.5238095238095237,
 509                positions: vec![],
 510                string: "unreachable_unchecked".to_string(),
 511            },
 512            is_snippet: false,
 513            sort_text: Some("80000000"),
 514            sort_key: (2, "unreachable_unchecked"),
 515        },
 516    ];
 517    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 518    assert_eq!(
 519        matches[0].string_match.string.as_str(),
 520        "unreachable!(…)",
 521        "Match order not expected"
 522    );
 523}
 524
 525#[gpui::test]
 526fn test_sort_matches_variable_and_constants_over_function(_cx: &mut TestAppContext) {
 527    // Case 1: "var" as variable
 528    let query: Option<&str> = Some("var");
 529    let mut matches: Vec<SortableMatch<'_>> = vec![
 530        SortableMatch {
 531            string_match: StringMatch {
 532                candidate_id: 0,
 533                score: 1.0,
 534                positions: vec![],
 535                string: "var".to_string(),
 536            },
 537            is_snippet: false,
 538            sort_text: Some("7fffffff"),
 539            sort_key: (3, "var"), // function
 540        },
 541        SortableMatch {
 542            string_match: StringMatch {
 543                candidate_id: 1,
 544                score: 1.0,
 545                positions: vec![],
 546                string: "var".to_string(),
 547            },
 548            is_snippet: false,
 549            sort_text: Some("7fffffff"),
 550            sort_key: (1, "var"), // variable
 551        },
 552    ];
 553    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 554    assert_eq!(
 555        matches[0].string_match.candidate_id, 1,
 556        "Match order not expected"
 557    );
 558    assert_eq!(
 559        matches[1].string_match.candidate_id, 0,
 560        "Match order not expected"
 561    );
 562
 563    // Case 2:  "var" as constant
 564    let query: Option<&str> = Some("var");
 565    let mut matches: Vec<SortableMatch<'_>> = vec![
 566        SortableMatch {
 567            string_match: StringMatch {
 568                candidate_id: 0,
 569                score: 1.0,
 570                positions: vec![],
 571                string: "var".to_string(),
 572            },
 573            is_snippet: false,
 574            sort_text: Some("7fffffff"),
 575            sort_key: (3, "var"), // function
 576        },
 577        SortableMatch {
 578            string_match: StringMatch {
 579                candidate_id: 1,
 580                score: 1.0,
 581                positions: vec![],
 582                string: "var".to_string(),
 583            },
 584            is_snippet: false,
 585            sort_text: Some("7fffffff"),
 586            sort_key: (2, "var"), // constant
 587        },
 588    ];
 589    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 590    assert_eq!(
 591        matches[0].string_match.candidate_id, 1,
 592        "Match order not expected"
 593    );
 594    assert_eq!(
 595        matches[1].string_match.candidate_id, 0,
 596        "Match order not expected"
 597    );
 598}
 599
 600#[gpui::test]
 601fn test_sort_matches_jsx_event_handler(_cx: &mut TestAppContext) {
 602    // Case 1: "on"
 603    let query: Option<&str> = Some("on");
 604    let mut matches: Vec<SortableMatch<'_>> = vec![
 605        SortableMatch {
 606            string_match: StringMatch {
 607                candidate_id: 0,
 608                score: 0.3333333333333333,
 609                positions: vec![],
 610                string: "onCut?".to_string(),
 611            },
 612            is_snippet: false,
 613            sort_text: Some("12"),
 614            sort_key: (3, "onCut?"),
 615        },
 616        SortableMatch {
 617            string_match: StringMatch {
 618                candidate_id: 0,
 619                score: 0.2857142857142857,
 620                positions: vec![],
 621                string: "onPlay?".to_string(),
 622            },
 623            is_snippet: false,
 624            sort_text: Some("12"),
 625            sort_key: (3, "onPlay?"),
 626        },
 627        SortableMatch {
 628            string_match: StringMatch {
 629                candidate_id: 0,
 630                score: 0.25,
 631                positions: vec![],
 632                string: "color?".to_string(),
 633            },
 634            is_snippet: false,
 635            sort_text: Some("12"),
 636            sort_key: (3, "color?"),
 637        },
 638        SortableMatch {
 639            string_match: StringMatch {
 640                candidate_id: 0,
 641                score: 0.25,
 642                positions: vec![],
 643                string: "defaultValue?".to_string(),
 644            },
 645            is_snippet: false,
 646            sort_text: Some("12"),
 647            sort_key: (3, "defaultValue?"),
 648        },
 649        SortableMatch {
 650            string_match: StringMatch {
 651                candidate_id: 0,
 652                score: 0.25,
 653                positions: vec![],
 654                string: "style?".to_string(),
 655            },
 656            is_snippet: false,
 657            sort_text: Some("12"),
 658            sort_key: (3, "style?"),
 659        },
 660        SortableMatch {
 661            string_match: StringMatch {
 662                candidate_id: 0,
 663                score: 0.20,
 664                positions: vec![],
 665                string: "className?".to_string(),
 666            },
 667            is_snippet: false,
 668            sort_text: Some("12"),
 669            sort_key: (3, "className?"),
 670        },
 671    ];
 672    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 673    assert_eq!(
 674        matches[0].string_match.string, "onCut?",
 675        "Match order not expected"
 676    );
 677    assert_eq!(
 678        matches[1].string_match.string, "onPlay?",
 679        "Match order not expected"
 680    );
 681
 682    // Case 2: "ona"
 683    let query: Option<&str> = Some("ona");
 684    let mut matches: Vec<SortableMatch<'_>> = vec![
 685        SortableMatch {
 686            string_match: StringMatch {
 687                candidate_id: 0,
 688                score: 0.375,
 689                positions: vec![],
 690                string: "onAbort?".to_string(),
 691            },
 692            is_snippet: false,
 693            sort_text: Some("12"),
 694            sort_key: (3, "onAbort?"),
 695        },
 696        SortableMatch {
 697            string_match: StringMatch {
 698                candidate_id: 0,
 699                score: 0.2727272727272727,
 700                positions: vec![],
 701                string: "onAuxClick?".to_string(),
 702            },
 703            is_snippet: false,
 704            sort_text: Some("12"),
 705            sort_key: (3, "onAuxClick?"),
 706        },
 707        SortableMatch {
 708            string_match: StringMatch {
 709                candidate_id: 0,
 710                score: 0.23571428571428565,
 711                positions: vec![],
 712                string: "onPlay?".to_string(),
 713            },
 714            is_snippet: false,
 715            sort_text: Some("12"),
 716            sort_key: (3, "onPlay?"),
 717        },
 718        SortableMatch {
 719            string_match: StringMatch {
 720                candidate_id: 0,
 721                score: 0.23571428571428565,
 722                positions: vec![],
 723                string: "onLoad?".to_string(),
 724            },
 725            is_snippet: false,
 726            sort_text: Some("12"),
 727            sort_key: (3, "onLoad?"),
 728        },
 729        SortableMatch {
 730            string_match: StringMatch {
 731                candidate_id: 0,
 732                score: 0.23571428571428565,
 733                positions: vec![],
 734                string: "onDrag?".to_string(),
 735            },
 736            is_snippet: false,
 737            sort_text: Some("12"),
 738            sort_key: (3, "onDrag?"),
 739        },
 740        SortableMatch {
 741            string_match: StringMatch {
 742                candidate_id: 0,
 743                score: 0.22499999999999998,
 744                positions: vec![],
 745                string: "onPause?".to_string(),
 746            },
 747            is_snippet: false,
 748            sort_text: Some("12"),
 749            sort_key: (3, "onPause?"),
 750        },
 751        SortableMatch {
 752            string_match: StringMatch {
 753                candidate_id: 0,
 754                score: 0.22499999999999998,
 755                positions: vec![],
 756                string: "onPaste?".to_string(),
 757            },
 758            is_snippet: false,
 759            sort_text: Some("12"),
 760            sort_key: (3, "onPaste?"),
 761        },
 762        SortableMatch {
 763            string_match: StringMatch {
 764                candidate_id: 0,
 765                score: 0.2,
 766                positions: vec![],
 767                string: "onAnimationEnd?".to_string(),
 768            },
 769            is_snippet: false,
 770            sort_text: Some("12"),
 771            sort_key: (3, "onAnimationEnd?"),
 772        },
 773        SortableMatch {
 774            string_match: StringMatch {
 775                candidate_id: 0,
 776                score: 0.2,
 777                positions: vec![],
 778                string: "onAbortCapture?".to_string(),
 779            },
 780            is_snippet: false,
 781            sort_text: Some("12"),
 782            sort_key: (3, "onAbortCapture?"),
 783        },
 784        SortableMatch {
 785            string_match: StringMatch {
 786                candidate_id: 0,
 787                score: 0.1833333333333333,
 788                positions: vec![],
 789                string: "onChange?".to_string(),
 790            },
 791            is_snippet: false,
 792            sort_text: Some("12"),
 793            sort_key: (3, "onChange?"),
 794        },
 795        SortableMatch {
 796            string_match: StringMatch {
 797                candidate_id: 0,
 798                score: 0.18,
 799                positions: vec![],
 800                string: "onWaiting?".to_string(),
 801            },
 802            is_snippet: false,
 803            sort_text: Some("12"),
 804            sort_key: (3, "onWaiting?"),
 805        },
 806        SortableMatch {
 807            string_match: StringMatch {
 808                candidate_id: 0,
 809                score: 0.18,
 810                positions: vec![],
 811                string: "onCanPlay?".to_string(),
 812            },
 813            is_snippet: false,
 814            sort_text: Some("12"),
 815            sort_key: (3, "onCanPlay?"),
 816        },
 817        SortableMatch {
 818            string_match: StringMatch {
 819                candidate_id: 0,
 820                score: 0.1764705882352941,
 821                positions: vec![],
 822                string: "onAnimationStart?".to_string(),
 823            },
 824            is_snippet: false,
 825            sort_text: Some("12"),
 826            sort_key: (3, "onAnimationStart?"),
 827        },
 828        SortableMatch {
 829            string_match: StringMatch {
 830                candidate_id: 0,
 831                score: 0.16666666666666666,
 832                positions: vec![],
 833                string: "onAuxClickCapture?".to_string(),
 834            },
 835            is_snippet: false,
 836            sort_text: Some("12"),
 837            sort_key: (3, "onAuxClickCapture?"),
 838        },
 839        SortableMatch {
 840            string_match: StringMatch {
 841                candidate_id: 0,
 842                score: 0.16499999999999998,
 843                positions: vec![],
 844                string: "onStalled?".to_string(),
 845            },
 846            is_snippet: false,
 847            sort_text: Some("12"),
 848            sort_key: (3, "onStalled?"),
 849        },
 850        SortableMatch {
 851            string_match: StringMatch {
 852                candidate_id: 0,
 853                score: 0.16499999999999998,
 854                positions: vec![],
 855                string: "onPlaying?".to_string(),
 856            },
 857            is_snippet: false,
 858            sort_text: Some("12"),
 859            sort_key: (3, "onPlaying?"),
 860        },
 861        SortableMatch {
 862            string_match: StringMatch {
 863                candidate_id: 0,
 864                score: 0.16499999999999998,
 865                positions: vec![],
 866                string: "onDragEnd?".to_string(),
 867            },
 868            is_snippet: false,
 869            sort_text: Some("12"),
 870            sort_key: (3, "onDragEnd?"),
 871        },
 872        SortableMatch {
 873            string_match: StringMatch {
 874                candidate_id: 0,
 875                score: 0.15000000000000002,
 876                positions: vec![],
 877                string: "onInvalid?".to_string(),
 878            },
 879            is_snippet: false,
 880            sort_text: Some("12"),
 881            sort_key: (3, "onInvalid?"),
 882        },
 883        SortableMatch {
 884            string_match: StringMatch {
 885                candidate_id: 0,
 886                score: 0.15,
 887                positions: vec![],
 888                string: "onDragOver?".to_string(),
 889            },
 890            is_snippet: false,
 891            sort_text: Some("12"),
 892            sort_key: (3, "onDragOver?"),
 893        },
 894        SortableMatch {
 895            string_match: StringMatch {
 896                candidate_id: 0,
 897                score: 0.15,
 898                positions: vec![],
 899                string: "onDragExit?".to_string(),
 900            },
 901            is_snippet: false,
 902            sort_text: Some("12"),
 903            sort_key: (3, "onDragExit?"),
 904        },
 905        SortableMatch {
 906            string_match: StringMatch {
 907                candidate_id: 0,
 908                score: 0.14285714285714285,
 909                positions: vec![],
 910                string: "onAnimationIteration?".to_string(),
 911            },
 912            is_snippet: false,
 913            sort_text: Some("12"),
 914            sort_key: (3, "onAnimationIteration?"),
 915        },
 916        SortableMatch {
 917            string_match: StringMatch {
 918                candidate_id: 0,
 919                score: 0.13846153846153847,
 920                positions: vec![],
 921                string: "onRateChange?".to_string(),
 922            },
 923            is_snippet: false,
 924            sort_text: Some("12"),
 925            sort_key: (3, "onRateChange?"),
 926        },
 927        SortableMatch {
 928            string_match: StringMatch {
 929                candidate_id: 0,
 930                score: 0.13749999999999996,
 931                positions: vec![],
 932                string: "onLoadStart?".to_string(),
 933            },
 934            is_snippet: false,
 935            sort_text: Some("12"),
 936            sort_key: (3, "onLoadStart?"),
 937        },
 938        SortableMatch {
 939            string_match: StringMatch {
 940                candidate_id: 0,
 941                score: 0.13749999999999996,
 942                positions: vec![],
 943                string: "onDragStart?".to_string(),
 944            },
 945            is_snippet: false,
 946            sort_text: Some("12"),
 947            sort_key: (3, "onDragStart?"),
 948        },
 949        SortableMatch {
 950            string_match: StringMatch {
 951                candidate_id: 0,
 952                score: 0.13749999999999996,
 953                positions: vec![],
 954                string: "onDragLeave?".to_string(),
 955            },
 956            is_snippet: false,
 957            sort_text: Some("12"),
 958            sort_key: (3, "onDragLeave?"),
 959        },
 960        SortableMatch {
 961            string_match: StringMatch {
 962                candidate_id: 0,
 963                score: 0.13749999999999996,
 964                positions: vec![],
 965                string: "onDragEnter?".to_string(),
 966            },
 967            is_snippet: false,
 968            sort_text: Some("12"),
 969            sort_key: (3, "onDragEnter?"),
 970        },
 971        SortableMatch {
 972            string_match: StringMatch {
 973                candidate_id: 0,
 974                score: 0.13636363636363635,
 975                positions: vec![],
 976                string: "onAnimationEndCapture?".to_string(),
 977            },
 978            is_snippet: false,
 979            sort_text: Some("12"),
 980            sort_key: (3, "onAnimationEndCapture?"),
 981        },
 982        SortableMatch {
 983            string_match: StringMatch {
 984                candidate_id: 0,
 985                score: 0.12692307692307692,
 986                positions: vec![],
 987                string: "onLoadedData?".to_string(),
 988            },
 989            is_snippet: false,
 990            sort_text: Some("12"),
 991            sort_key: (3, "onLoadedData?"),
 992        },
 993    ];
 994    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::default());
 995    assert_eq!(
 996        matches
 997            .iter()
 998            .take(12)
 999            .map(|m| m.string_match.string.as_str())
1000            .collect::<Vec<&str>>(),
1001        vec![
1002            "onAbort?",
1003            "onAuxClick?",
1004            "onAbortCapture?",
1005            "onAnimationEnd?",
1006            "onAnimationStart?",
1007            "onAuxClickCapture?",
1008            "onAnimationIteration?",
1009            "onAnimationEndCapture?",
1010            "onDrag?",
1011            "onLoad?",
1012            "onPlay?",
1013            "onPaste?",
1014        ]
1015    );
1016}
1017
1018#[gpui::test]
1019fn test_sort_matches_for_snippets(_cx: &mut TestAppContext) {
1020    // Case 1: "prin"
1021    let query: Option<&str> = Some("prin");
1022    let mut matches: Vec<SortableMatch<'_>> = vec![
1023        SortableMatch {
1024            string_match: StringMatch {
1025                candidate_id: 0,
1026                score: 0.2,
1027                positions: vec![],
1028                string: "println".to_string(),
1029            },
1030            is_snippet: false,
1031            sort_text: Some("80000000"),
1032            sort_key: (2, "println"),
1033        },
1034        SortableMatch {
1035            string_match: StringMatch {
1036                candidate_id: 0,
1037                score: 0.2,
1038                positions: vec![],
1039                string: "println!(…)".to_string(),
1040            },
1041            is_snippet: true,
1042            sort_text: Some("80000000"),
1043            sort_key: (2, "println!(…)"),
1044        },
1045    ];
1046    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::Top);
1047    assert_eq!(
1048        matches[0].string_match.string.as_str(),
1049        "println!(…)",
1050        "Match order not expected"
1051    );
1052}
1053
1054#[gpui::test]
1055fn test_sort_matches_for_exact_match(_cx: &mut TestAppContext) {
1056    // Case 1: "set_text"
1057    let query: Option<&str> = Some("set_text");
1058    let mut matches: Vec<SortableMatch<'_>> = vec![
1059        SortableMatch {
1060            string_match: StringMatch {
1061                candidate_id: 0,
1062                score: 1.0,
1063                positions: vec![],
1064                string: "set_text".to_string(),
1065            },
1066            is_snippet: false,
1067            sort_text: Some("7fffffff"),
1068            sort_key: (3, "set_text"),
1069        },
1070        SortableMatch {
1071            string_match: StringMatch {
1072                candidate_id: 0,
1073                score: 0.32000000000000006,
1074                positions: vec![],
1075                string: "set_placeholder_text".to_string(),
1076            },
1077            is_snippet: false,
1078            sort_text: Some("7fffffff"),
1079            sort_key: (3, "set_placeholder_text"),
1080        },
1081        SortableMatch {
1082            string_match: StringMatch {
1083                candidate_id: 0,
1084                score: 0.32,
1085                positions: vec![],
1086                string: "set_text_style_refinement".to_string(),
1087            },
1088            is_snippet: false,
1089            sort_text: Some("7fffffff"),
1090            sort_key: (3, "set_text_style_refinement"),
1091        },
1092        SortableMatch {
1093            string_match: StringMatch {
1094                candidate_id: 0,
1095                score: 0.16666666666666666,
1096                positions: vec![],
1097                string: "set_context_menu_options".to_string(),
1098            },
1099            is_snippet: false,
1100            sort_text: Some("7fffffff"),
1101            sort_key: (3, "set_context_menu_options"),
1102        },
1103        SortableMatch {
1104            string_match: StringMatch {
1105                candidate_id: 0,
1106                score: 0.08695652173913043,
1107                positions: vec![],
1108                string: "select_to_next_word_end".to_string(),
1109            },
1110            is_snippet: false,
1111            sort_text: Some("7fffffff"),
1112            sort_key: (3, "select_to_next_word_end"),
1113        },
1114        SortableMatch {
1115            string_match: StringMatch {
1116                candidate_id: 0,
1117                score: 0.07692307692307693,
1118                positions: vec![],
1119                string: "select_to_next_subword_end".to_string(),
1120            },
1121            is_snippet: false,
1122            sort_text: Some("7fffffff"),
1123            sort_key: (3, "select_to_next_subword_end"),
1124        },
1125        SortableMatch {
1126            string_match: StringMatch {
1127                candidate_id: 0,
1128                score: 0.06956521739130435,
1129                positions: vec![],
1130                string: "set_custom_context_menu".to_string(),
1131            },
1132            is_snippet: false,
1133            sort_text: Some("7fffffff"),
1134            sort_key: (3, "set_custom_context_menu"),
1135        },
1136        SortableMatch {
1137            string_match: StringMatch {
1138                candidate_id: 0,
1139                score: 0.06,
1140                positions: vec![],
1141                string: "select_to_end_of_excerpt".to_string(),
1142            },
1143            is_snippet: false,
1144            sort_text: Some("7fffffff"),
1145            sort_key: (3, "select_to_end_of_excerpt"),
1146        },
1147        SortableMatch {
1148            string_match: StringMatch {
1149                candidate_id: 0,
1150                score: 0.055384615384615386,
1151                positions: vec![],
1152                string: "select_to_start_of_excerpt".to_string(),
1153            },
1154            is_snippet: false,
1155            sort_text: Some("7fffffff"),
1156            sort_key: (3, "select_to_start_of_excerpt"),
1157        },
1158        SortableMatch {
1159            string_match: StringMatch {
1160                candidate_id: 0,
1161                score: 0.0464516129032258,
1162                positions: vec![],
1163                string: "select_to_start_of_next_excerpt".to_string(),
1164            },
1165            is_snippet: false,
1166            sort_text: Some("7fffffff"),
1167            sort_key: (3, "select_to_start_of_next_excerpt"),
1168        },
1169        SortableMatch {
1170            string_match: StringMatch {
1171                candidate_id: 0,
1172                score: 0.04363636363636363,
1173                positions: vec![],
1174                string: "select_to_end_of_previous_excerpt".to_string(),
1175            },
1176            is_snippet: false,
1177            sort_text: Some("7fffffff"),
1178            sort_key: (3, "select_to_end_of_previous_excerpt"),
1179        },
1180    ];
1181    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::Top);
1182    assert_eq!(
1183        matches
1184            .iter()
1185            .map(|m| m.string_match.string.as_str())
1186            .collect::<Vec<&str>>(),
1187        vec![
1188            "set_text",
1189            "set_text_style_refinement",
1190            "set_placeholder_text",
1191            "set_context_menu_options",
1192            "set_custom_context_menu",
1193            "select_to_next_word_end",
1194            "select_to_next_subword_end",
1195            "select_to_end_of_excerpt",
1196            "select_to_start_of_excerpt",
1197            "select_to_start_of_next_excerpt",
1198            "select_to_end_of_previous_excerpt",
1199        ]
1200    );
1201}
1202
1203#[gpui::test]
1204fn test_sort_matches_for_prefix_matches(_cx: &mut TestAppContext) {
1205    // Case 1: "set"
1206    let query: Option<&str> = Some("set");
1207    let mut matches: Vec<SortableMatch<'_>> = vec![
1208        SortableMatch {
1209            string_match: StringMatch {
1210                candidate_id: 0,
1211                score: 0.12631578947368421,
1212                positions: vec![],
1213                string: "select_to_beginning".to_string(),
1214            },
1215            is_snippet: false,
1216            sort_text: Some("7fffffff"),
1217            sort_key: (3, "select_to_beginning"),
1218        },
1219        SortableMatch {
1220            string_match: StringMatch {
1221                candidate_id: 0,
1222                score: 0.15000000000000002,
1223                positions: vec![],
1224                string: "set_collapse_matches".to_string(),
1225            },
1226            is_snippet: false,
1227            sort_text: Some("7fffffff"),
1228            sort_key: (3, "set_collapse_matches"),
1229        },
1230        SortableMatch {
1231            string_match: StringMatch {
1232                candidate_id: 0,
1233                score: 0.21428571428571427,
1234                positions: vec![],
1235                string: "set_autoindent".to_string(),
1236            },
1237            is_snippet: false,
1238            sort_text: Some("7fffffff"),
1239            sort_key: (3, "set_autoindent"),
1240        },
1241        SortableMatch {
1242            string_match: StringMatch {
1243                candidate_id: 0,
1244                score: 0.11538461538461539,
1245                positions: vec![],
1246                string: "set_all_diagnostics_active".to_string(),
1247            },
1248            is_snippet: false,
1249            sort_text: Some("7fffffff"),
1250            sort_key: (3, "set_all_diagnostics_active"),
1251        },
1252        SortableMatch {
1253            string_match: StringMatch {
1254                candidate_id: 0,
1255                score: 0.1142857142857143,
1256                positions: vec![],
1257                string: "select_to_end_of_line".to_string(),
1258            },
1259            is_snippet: false,
1260            sort_text: Some("7fffffff"),
1261            sort_key: (3, "select_to_end_of_line"),
1262        },
1263        SortableMatch {
1264            string_match: StringMatch {
1265                candidate_id: 0,
1266                score: 0.15000000000000002,
1267                positions: vec![],
1268                string: "select_all".to_string(),
1269            },
1270            is_snippet: false,
1271            sort_text: Some("7fffffff"),
1272            sort_key: (3, "select_all"),
1273        },
1274        SortableMatch {
1275            string_match: StringMatch {
1276                candidate_id: 0,
1277                score: 0.13636363636363635,
1278                positions: vec![],
1279                string: "select_line".to_string(),
1280            },
1281            is_snippet: false,
1282            sort_text: Some("7fffffff"),
1283            sort_key: (3, "select_line"),
1284        },
1285        SortableMatch {
1286            string_match: StringMatch {
1287                candidate_id: 0,
1288                score: 0.13636363636363635,
1289                positions: vec![],
1290                string: "select_left".to_string(),
1291            },
1292            is_snippet: false,
1293            sort_text: Some("7fffffff"),
1294            sort_key: (3, "select_left"),
1295        },
1296        SortableMatch {
1297            string_match: StringMatch {
1298                candidate_id: 0,
1299                score: 0.13636363636363635,
1300                positions: vec![],
1301                string: "select_down".to_string(),
1302            },
1303            is_snippet: false,
1304            sort_text: Some("7fffffff"),
1305            sort_key: (3, "select_down"),
1306        },
1307    ];
1308    CompletionsMenu::sort_matches(&mut matches, query, SnippetSortOrder::Top);
1309    println!(
1310        "{:?}",
1311        matches
1312            .iter()
1313            .map(|m| m.string_match.string.as_str())
1314            .collect::<Vec<&str>>(),
1315    );
1316    assert_eq!(
1317        matches
1318            .iter()
1319            .map(|m| m.string_match.string.as_str())
1320            .collect::<Vec<&str>>(),
1321        vec![
1322            "set_autoindent",
1323            "set_collapse_matches",
1324            "set_all_diagnostics_active",
1325            "select_all",
1326            "select_down",
1327            "select_left",
1328            "select_line",
1329            "select_to_beginning",
1330            "select_to_end_of_line",
1331        ]
1332    );
1333}