diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e82cd30555..969a17c164 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 9.2. Last change: 2026 May 07 +*options.txt* For Vim version 9.2. Last change: 2026 May 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -3983,9 +3983,8 @@ A jump table for the options with a short description can be found at |Q_op|. |String| and is the |:find| command argument. The second argument is a |Boolean| and is set to |v:true| when the function is called to get a List of command-line completion matches for the |:find| command. - The function should return a List of strings, or, in the command-line - completion case, whatever a |:command-completion-customlist| function - may return. + The function should return a List, which is handled similarly to the + return value of a |:command-completion-customlist| function. The function is called only once per |:find| command invocation. The function can process all the directories specified in 'path'. diff --git a/src/cmdexpand.c b/src/cmdexpand.c index a763456a1f..3c660b5ea2 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -4172,22 +4172,22 @@ expand_process_user_list( // Loop over the items in the list. FOR_ALL_LIST_ITEMS(retlist, li) { + typval_T *tv = &li->li_tv; char_u *p = NULL; char_u *abbr = NULL; char_u *kind = NULL; char_u *menu = NULL; char_u *info = NULL; - if (li->li_tv.v_type == VAR_STRING) + if (tv->v_type == VAR_STRING) { - if (li->li_tv.vval.v_string == NULL) + if (tv->vval.v_string == NULL) continue; // Skip NULL strings p = vim_strsave(li->li_tv.vval.v_string); } - else if (li->li_tv.v_type == VAR_DICT - && li->li_tv.vval.v_dict != NULL) + else if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) { - dict_T *d = li->li_tv.vval.v_dict; + dict_T *d = tv->vval.v_dict; char_u *word = dict_get_string(d, "word", FALSE); if (word == NULL) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 7b31bed99a..11ea59e3b0 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7119,8 +7119,16 @@ findfunc_find_file(char_u *findarg, int findarg_len, int count) else { listitem_T *li = list_find(fname_list, count - 1); - if (li != NULL && li->li_tv.v_type == VAR_STRING) - ret_fname = vim_strsave(li->li_tv.vval.v_string); + + if (li != NULL) + { + typval_T *tv = &li->li_tv; + + if (tv->v_type == VAR_STRING && tv->vval.v_string != NULL) + ret_fname = vim_strsave(tv->vval.v_string); + else if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) + ret_fname = dict_get_string(tv->vval.v_dict, "word", TRUE); + } } } diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim index 42c3fb6431..a5f1f6fdd4 100644 --- a/src/testdir/test_findfile.vim +++ b/src/testdir/test_findfile.vim @@ -329,22 +329,22 @@ func Test_findfunc() set findfunc=FindFuncBasic find Xfindfunc3 - call assert_match('Xfindfunc3.c', @%) + call assert_match('Xfindfunc3\.c', @%) bw! 2find Xfind - call assert_match('Xfindfunc2.c', @%) + call assert_match('Xfindfunc2\.c', @%) bw! call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path') call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path') sfind Xfindfunc2.c - call assert_match('Xfindfunc2.c', @%) + call assert_match('Xfindfunc2\.c', @%) call assert_equal(2, winnr('$')) %bw! call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path') tabfind Xfindfunc3.c - call assert_match('Xfindfunc3.c', @%) + call assert_match('Xfindfunc3\.c', @%) call assert_equal(2, tabpagenr()) %bw! call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path') @@ -352,12 +352,44 @@ func Test_findfunc() " Test garbage collection call test_garbagecollect_now() find Xfindfunc2 - call assert_match('Xfindfunc2.c', @%) + call assert_match('Xfindfunc2\.c', @%) bw! delfunc FindFuncBasic call test_garbagecollect_now() call assert_fails('find Xfindfunc2', 'E117: Unknown function: FindFuncBasic') + " 'findfunc' with dicts in the returned list + func FindFuncDict(pat, cmdcomplete) + return [ + \ #{word: 'Xfindfunc1.c', abbr: 'Xff1.c'}, + \ #{word: 'Xfindfunc2.c'}, + \ 'Xfindfunc3.c', + "\ invalid values + \ #{abbr: 'XXX'}, + \ test_null_dict(), + \ test_null_string(), + \ ] + endfunc + + set findfunc=FindFuncDict + find Xfind + call assert_match('Xfindfunc1\.c', @%) + bw! + 2find Xfind + call assert_match('Xfindfunc2\.c', @%) + bw! + 3find Xfind + call assert_match('Xfindfunc3\.c', @%) + bw! + " These invalid values should not crash + 4find Xfind + 5find Xfind + 6find Xfind + call assert_fails('7find Xfind', 'E347: No more file "Xfind" found in path') + call assert_equal('', @%) + %bw! + delfunc FindFuncDict + " Buffer-local option func GlobalFindFunc(pat, cmdcomplete) return ['global'] diff --git a/src/version.c b/src/version.c index 0103f023e2..36f96c0550 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 455, /**/ 454, /**/