]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0455: 'findfunc' only allows extra info for cmdline completion v9.2.0455
authorzeertzjq <zeertzjq@outlook.com>
Fri, 8 May 2026 21:09:48 +0000 (21:09 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 8 May 2026 21:09:48 +0000 (21:09 +0000)
Problem:  'findfunc' only allows extra info for cmdline completion, not
          for actually finding files (Maxim Kim, after 9.2.0451).
Solution: Handle returning a list of dicts when actually finding files.
          Also fix crash on NULL string (zeertzjq).

fixes:  #20163
closes: #20164

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/options.txt
src/cmdexpand.c
src/ex_docmd.c
src/testdir/test_findfile.vim
src/version.c

index e82cd3055571a165efadec9420c5b79d505d64e5..969a17c1649134fcf02f0174b5d7e4aa04ce3fa2 100644 (file)
@@ -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'.
index a763456a1f9044e6468a7dafd7aac02cbb5b1724..3c660b5ea25a1e2eaa9d838238922a421e7e7e9a 100644 (file)
@@ -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)
index 7b31bed99a20bf6911f291eaba0df207d6106ef2..11ea59e3b06f7c36e328bbc31a08db614a23c72f 100644 (file)
@@ -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);
+           }
        }
     }
 
index 42c3fb64315861f29a811e11cfd894f1fc189cd0..a5f1f6fdd42569513810643620dd3789619fc34e 100644 (file)
@@ -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']
index 0103f023e2eb62673b9484d2bc105c873207a6e4..36f96c0550195079992bbc8f548983325ad53edb 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    455,
 /**/
     454,
 /**/