From 162edf7b30dd4a98b85fa490d0dfd1a73db23b88 Mon Sep 17 00:00:00 2001 From: glepnir Date: Tue, 18 Mar 2025 15:44:45 +0800 Subject: vim-patch:9.1.1214: matchfuzzy() can be improved for camel case matches Problem: When searching for "Cur", CamelCase matches like "lCursor" score higher than exact prefix matches like Cursor, which is counter-intuitive (Maxim Kim). Solution: Add a 'camelcase' option to matchfuzzy() that lets users disable CamelCase bonuses when needed, making prefix matches rank higher. (glepnir) fixes: vim/vim#16504 closes: vim/vim#16797 https://github.com/vim/vim/commit/28e40a7b55ce471656cccc2260c11a29d5da447e Co-authored-by: glepnir --- runtime/doc/builtin.txt | 3 +++ runtime/lua/vim/_meta/vimfn.lua | 3 +++ src/nvim/eval.lua | 3 +++ src/nvim/quickfix.c | 2 +- src/nvim/search.c | 34 ++++++++++++++++++++++------------ test/old/testdir/test_matchfuzzy.vim | 13 +++++++++++++ 6 files changed, 45 insertions(+), 13 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 04d24e7a92..a4adfb3a63 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -6410,6 +6410,9 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* given sequence. limit Maximum number of matches in {list} to be returned. Zero means no limit. + camelcase Use enhanced camel case scoring making results + better suited for completion related to + programming languages. Default is v:true If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 2b4f1a32b0..69e739225f 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -5815,6 +5815,9 @@ function vim.fn.matchend(expr, pat, start, count) end --- given sequence. --- limit Maximum number of matches in {list} to be --- returned. Zero means no limit. +--- camelcase Use enhanced camel case scoring making results +--- better suited for completion related to +--- programming languages. Default is v:true --- --- If {list} is a list of dictionaries, then the optional {dict} --- argument supports the following additional items: diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 8ca1868ff1..f02f5179c7 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -7150,6 +7150,9 @@ M.funcs = { given sequence. limit Maximum number of matches in {list} to be returned. Zero means no limit. + camelcase Use enhanced camel case scoring making results + better suited for completion related to + programming languages. Default is v:true If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 44b66c4f73..5f197bc84f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -5356,7 +5356,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp // Fuzzy string match CLEAR_FIELD(matches); - while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz) > 0) { + while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz, true) > 0) { // Pass the buffer number so that it gets used even for a // dummy buffer, unless duplicate_name is set, then the // buffer will be wiped out below. diff --git a/src/nvim/search.c b/src/nvim/search.c index b38296ac5c..fed8867315 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -2996,7 +2996,7 @@ typedef struct { /// are in "matches". static int fuzzy_match_compute_score(const char *const fuzpat, const char *const str, const int strSz, const uint32_t *const matches, - const int numMatches) + const int numMatches, bool camelcase) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE { assert(numMatches > 0); // suppress clang "result of operation is garbage" @@ -3055,7 +3055,7 @@ static int fuzzy_match_compute_score(const char *const fuzpat, const char *const curr = utf_ptr2char(p); // Enhanced camel case scoring - if (mb_islower(neighbor) && mb_isupper(curr)) { + if (camelcase && mb_islower(neighbor) && mb_isupper(curr)) { score += CAMEL_BONUS * 2; // Double the camel case bonus is_camel = true; consecutive_camel++; @@ -3114,7 +3114,8 @@ static int fuzzy_match_compute_score(const char *const fuzpat, const char *const static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t strIdx, int *const outScore, const char *const strBegin, const int strLen, const uint32_t *const srcMatches, uint32_t *const matches, - const int maxMatches, int nextMatch, int *const recursionCount) + const int maxMatches, int nextMatch, int *const recursionCount, + bool camelcase) FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5, 8, 11) FUNC_ATTR_WARN_UNUSED_RESULT { // Recursion params @@ -3161,7 +3162,7 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s if (fuzzy_match_recursive(fuzpat, next_char, strIdx + 1, &recursiveScore, strBegin, strLen, matches, recursiveMatches, sizeof(recursiveMatches) / sizeof(recursiveMatches[0]), nextMatch, - recursionCount)) { + recursionCount, camelcase)) { // Pick best recursive score if (!recursiveMatch || recursiveScore > bestRecursiveScore) { memcpy(bestRecursiveMatches, recursiveMatches, @@ -3184,7 +3185,7 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s // Calculate score if (matched) { - *outScore = fuzzy_match_compute_score(fuzpat, strBegin, strLen, matches, nextMatch); + *outScore = fuzzy_match_compute_score(fuzpat, strBegin, strLen, matches, nextMatch, camelcase); } // Return best result @@ -3213,7 +3214,7 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s /// @return true if "pat_arg" matches "str". Also returns the match score in /// "outScore" and the matching character positions in "matches". bool fuzzy_match(char *const str, const char *const pat_arg, const bool matchseq, - int *const outScore, uint32_t *const matches, const int maxMatches) + int *const outScore, uint32_t *const matches, const int maxMatches, bool camelcase) FUNC_ATTR_NONNULL_ALL { const int len = mb_charlen(str); @@ -3251,7 +3252,7 @@ bool fuzzy_match(char *const str, const char *const pat_arg, const bool matchseq const int matchCount = fuzzy_match_recursive(pat, str, 0, &score, str, len, NULL, matches + numMatches, - maxMatches - numMatches, 0, &recursionCount); + maxMatches - numMatches, 0, &recursionCount, camelcase); if (matchCount == 0) { numMatches = 0; break; @@ -3301,7 +3302,7 @@ static int fuzzy_match_item_compare(const void *const s1, const void *const s2) static void fuzzy_match_in_list(list_T *const l, char *const str, const bool matchseq, const char *const key, Callback *const item_cb, const bool retmatchpos, list_T *const fmatchlist, - const int max_matches) + const int max_matches, bool camelcase) FUNC_ATTR_NONNULL_ARG(2, 5, 7) { int len = tv_list_len(l); @@ -3352,7 +3353,7 @@ static void fuzzy_match_in_list(list_T *const l, char *const str, const bool mat int score; if (itemstr != NULL && fuzzy_match(itemstr, str, matchseq, &score, matches, - MAX_FUZZY_MATCHES)) { + MAX_FUZZY_MATCHES, camelcase)) { items[match_count].idx = (int)match_count; items[match_count].item = li; items[match_count].score = score; @@ -3452,6 +3453,7 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, const char *key = NULL; bool matchseq = false; int max_matches = 0; + bool camelcase = true; if (argvars[2].v_type != VAR_UNKNOWN) { if (tv_check_for_nonnull_dict_arg(argvars, 2) == FAIL) { return; @@ -3481,6 +3483,14 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, max_matches = (int)tv_get_number_chk(&di->di_tv, NULL); } + if ((di = tv_dict_find(d, "camelcase", -1)) != NULL) { + if (di->di_tv.v_type != VAR_BOOL) { + semsg(_(e_invarg2), "camelcase"); + return; + } + camelcase = tv_get_bool_chk(&di->di_tv, NULL); + } + if (tv_dict_find(d, "matchseq", -1) != NULL) { matchseq = true; } @@ -3500,7 +3510,7 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, fuzzy_match_in_list(argvars[0].vval.v_list, (char *)tv_get_string(&argvars[1]), matchseq, key, - &cb, retmatchpos, rettv->vval.v_list, max_matches); + &cb, retmatchpos, rettv->vval.v_list, max_matches, camelcase); callback_free(&cb); } @@ -3584,7 +3594,7 @@ int fuzzy_match_str(char *const str, const char *const pat) int score = 0; uint32_t matchpos[MAX_FUZZY_MATCHES]; - fuzzy_match(str, pat, true, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0])); + fuzzy_match(str, pat, true, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0]), true); return score; } @@ -3602,7 +3612,7 @@ garray_T *fuzzy_match_str_with_pos(char *const str, const char *const pat) unsigned matches[MAX_FUZZY_MATCHES]; int score = 0; - if (!fuzzy_match(str, pat, false, &score, matches, MAX_FUZZY_MATCHES) + if (!fuzzy_match(str, pat, false, &score, matches, MAX_FUZZY_MATCHES, true) || score == 0) { ga_clear(match_positions); xfree(match_positions); diff --git a/test/old/testdir/test_matchfuzzy.vim b/test/old/testdir/test_matchfuzzy.vim index 0c982c19f1..a11ef3a86f 100644 --- a/test/old/testdir/test_matchfuzzy.vim +++ b/test/old/testdir/test_matchfuzzy.vim @@ -90,6 +90,10 @@ func Test_matchfuzzy() let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}] call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : 'name'})", 'E730:') + " camcelcase + call assert_equal(['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) + call assert_equal(['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) + " Test in latin1 encoding let save_enc = &encoding " Nvim supports utf-8 encoding only @@ -175,6 +179,15 @@ func Test_matchfuzzypos() let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}] call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : 'name'})", 'E730:') + + "camelcase + call assert_equal([['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], [[1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8], [0, 1, 2], [0, 1, 2], [0, 1, 2]], [318, 311, 308, 303, 267, 264, 263]], + \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) + + call assert_equal([['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], [[0, 1, 2], [0, 1, 2], [0, 1, 2], [1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8]], [267, 264, 263, 246, 239, 236, 231]], + \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) + call assert_equal([['things', 'sThings', 'thisThings'], [[0, 1, 2, 3], [1, 2, 3, 4], [0, 1, 2, 7]], [333, 287, 279]], + \ matchfuzzypos(['things','sThings', 'thisThings'], 'thin', {'camelcase': v:false})) endfunc " Test for matchfuzzy() with multibyte characters -- cgit From f9280cde0ae12bcd68e069c3849b20f4fcfbd41a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 27 Mar 2025 08:20:01 +0800 Subject: vim-patch:9.1.1217: tests: typos in test_matchfuzzy.vim Problem: tests: typos in test_matchfuzzy.vim (after 9.1.1214). Solution: Fix the typos. Consistently put the function call on the second line in assertions for camelcase (zeertzjq). closes: vim/vim#16907 https://github.com/vim/vim/commit/85627732e0f5f4e31137fc12bcb809418a4f683f --- test/old/testdir/test_matchfuzzy.vim | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/old/testdir/test_matchfuzzy.vim b/test/old/testdir/test_matchfuzzy.vim index a11ef3a86f..214862e9a0 100644 --- a/test/old/testdir/test_matchfuzzy.vim +++ b/test/old/testdir/test_matchfuzzy.vim @@ -90,9 +90,11 @@ func Test_matchfuzzy() let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}] call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : 'name'})", 'E730:') - " camcelcase - call assert_equal(['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) - call assert_equal(['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) + " camelcase + call assert_equal(['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], + \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) + call assert_equal(['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], + \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) " Test in latin1 encoding let save_enc = &encoding @@ -180,9 +182,9 @@ func Test_matchfuzzypos() let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}] call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : 'name'})", 'E730:') - "camelcase + " camelcase call assert_equal([['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], [[1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8], [0, 1, 2], [0, 1, 2], [0, 1, 2]], [318, 311, 308, 303, 267, 264, 263]], - \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) + \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) call assert_equal([['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], [[0, 1, 2], [0, 1, 2], [0, 1, 2], [1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8]], [267, 264, 263, 246, 239, 236, 231]], \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) -- cgit From 797195e0ea554f2e546ced9104e8fbfa376f283f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 27 Mar 2025 08:21:08 +0800 Subject: vim-patch:9.1.1219: Strange error with wrong type for matchfuzzy() "camelcase" Problem: Strange error with type for matchfuzzy() "camelcase". Solution: Show the error "Invalid value for argument camelcase" instead of "Invalid argument: camelcase" (zeertzjq). Note that using tv_get_string() will lead to confusion, as when the value cannot be converted to a string tv_get_string() will also give an error about that, but "camelcase" takes a boolean, not a string. Also don't use tv_get_string() for the "limit" argument above. closes: vim/vim#16926 https://github.com/vim/vim/commit/c4815c157b27923001e44bfd241fb540bf1fb518 --- runtime/doc/builtin.txt | 2 +- runtime/lua/vim/_meta/vimfn.lua | 2 +- src/nvim/eval.lua | 2 +- src/nvim/search.c | 6 +++--- test/old/testdir/test_matchfuzzy.vim | 16 +++++++++++++--- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index a4adfb3a63..3ad5d83ac2 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -6412,7 +6412,7 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* returned. Zero means no limit. camelcase Use enhanced camel case scoring making results better suited for completion related to - programming languages. Default is v:true + programming languages. Defaults to v:true. If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 69e739225f..813a89898e 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -5817,7 +5817,7 @@ function vim.fn.matchend(expr, pat, start, count) end --- returned. Zero means no limit. --- camelcase Use enhanced camel case scoring making results --- better suited for completion related to ---- programming languages. Default is v:true +--- programming languages. Defaults to v:true. --- --- If {list} is a list of dictionaries, then the optional {dict} --- argument supports the following additional items: diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f02f5179c7..ffdbacb2b4 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -7152,7 +7152,7 @@ M.funcs = { returned. Zero means no limit. camelcase Use enhanced camel case scoring making results better suited for completion related to - programming languages. Default is v:true + programming languages. Defaults to v:true. If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: diff --git a/src/nvim/search.c b/src/nvim/search.c index fed8867315..fe8e54fed4 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3466,7 +3466,7 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, if ((di = tv_dict_find(d, "key", -1)) != NULL) { if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL || *di->di_tv.vval.v_string == NUL) { - semsg(_(e_invarg2), tv_get_string(&di->di_tv)); + semsg(_(e_invargNval), "key", tv_get_string(&di->di_tv)); return; } key = tv_get_string(&di->di_tv); @@ -3477,7 +3477,7 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, if ((di = tv_dict_find(d, "limit", -1)) != NULL) { if (di->di_tv.v_type != VAR_NUMBER) { - semsg(_(e_invarg2), tv_get_string(&di->di_tv)); + semsg(_(e_invargval), "limit"); return; } max_matches = (int)tv_get_number_chk(&di->di_tv, NULL); @@ -3485,7 +3485,7 @@ static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv, if ((di = tv_dict_find(d, "camelcase", -1)) != NULL) { if (di->di_tv.v_type != VAR_BOOL) { - semsg(_(e_invarg2), "camelcase"); + semsg(_(e_invargval), "camelcase"); return; } camelcase = tv_get_bool_chk(&di->di_tv, NULL); diff --git a/test/old/testdir/test_matchfuzzy.vim b/test/old/testdir/test_matchfuzzy.vim index 214862e9a0..10480f446d 100644 --- a/test/old/testdir/test_matchfuzzy.vim +++ b/test/old/testdir/test_matchfuzzy.vim @@ -78,6 +78,7 @@ func Test_matchfuzzy() " Nvim's callback implementation is different, so E6000 is expected instead, " call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E921:') call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E6000:') + call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : 123})", 'E475: Invalid value for argument key: 123') call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E730:') call assert_fails("let x = matchfuzzy(l, 'cam', v:_null_dict)", 'E1297:') call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : v:_null_string})", 'E475:') @@ -91,10 +92,15 @@ func Test_matchfuzzy() call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : 'name'})", 'E730:') " camelcase - call assert_equal(['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], - \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) call assert_equal(['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) + call assert_equal(['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], + \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:true})) + call assert_equal(['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], + \ matchfuzzy(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) + call assert_equal(['things', 'sThings', 'thisThings'], + \ matchfuzzy(['things','sThings', 'thisThings'], 'thin', {'camelcase': v:false})) + call assert_fails("let x = matchfuzzy([], 'foo', {'camelcase': []})", 'E475: Invalid value for argument camelcase') " Test in latin1 encoding let save_enc = &encoding @@ -161,6 +167,7 @@ func Test_matchfuzzypos() " Nvim's callback implementation is different, so E6000 is expected instead, " call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E921:') call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E6000:') + call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : 123})", 'E475: Invalid value for argument key: 123') call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E730:') call assert_fails("let x = matchfuzzypos(l, 'cam', v:_null_dict)", 'E1297:') call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : v:_null_string})", 'E475:') @@ -185,11 +192,13 @@ func Test_matchfuzzypos() " camelcase call assert_equal([['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], [[1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8], [0, 1, 2], [0, 1, 2], [0, 1, 2]], [318, 311, 308, 303, 267, 264, 263]], \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur')) - + call assert_equal([['lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'Cursor', 'CurSearch', 'CursorLine'], [[1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8], [0, 1, 2], [0, 1, 2], [0, 1, 2]], [318, 311, 308, 303, 267, 264, 263]], + \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:true})) call assert_equal([['Cursor', 'CurSearch', 'CursorLine', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor'], [[0, 1, 2], [0, 1, 2], [0, 1, 2], [1, 2, 3], [2, 3, 4], [2, 3, 4], [6, 7, 8]], [267, 264, 263, 246, 239, 236, 231]], \ matchfuzzypos(['Cursor', 'lCursor', 'shCurlyIn', 'shCurlyError', 'TracesCursor', 'CurSearch', 'CursorLine'], 'Cur', {"camelcase": v:false})) call assert_equal([['things', 'sThings', 'thisThings'], [[0, 1, 2, 3], [1, 2, 3, 4], [0, 1, 2, 7]], [333, 287, 279]], \ matchfuzzypos(['things','sThings', 'thisThings'], 'thin', {'camelcase': v:false})) + call assert_fails("let x = matchfuzzypos([], 'foo', {'camelcase': []})", 'E475: Invalid value for argument camelcase') endfunc " Test for matchfuzzy() with multibyte characters @@ -280,6 +289,7 @@ func Test_matchfuzzy_limit() call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 2})) call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 3})) call assert_fails("call matchfuzzy(x, '2', #{limit: '2'})", 'E475:') + call assert_fails("call matchfuzzy(x, '2', #{limit: []})", 'E475:') let l = [{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}] call assert_equal([{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}], l->matchfuzzy('c', #{text_cb: {v -> v.val}})) -- cgit