Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Matchfuzzy matching position is inconsistent against plain string entries vs objects when text_cb is involved. #19540

@asmodeus812

Description

@asmodeus812

Steps to reproduce

 set nocompatible

 function! s:Dump(label, res, items, pattern, TextCb) abort
   let l:strings = a:res[0]
   let l:positions = a:res[1]
   let l:scores = a:res[2]

   echom '--- ' .. a:label .. ' ---'
   echom 'items=' .. string(a:items)
   echom 'pattern=' .. string(a:pattern)
   echom 'text_cb(items[0])=' .. string(call(a:TextCb, [a:items[0]]))
   echom 'strings=' .. string(l:strings)
   echom 'positions=' .. string(l:positions)
   echom 'scores=' .. string(l:scores)

   if len(l:strings) > 0
     let l:pos = l:positions[0]
     echom 'pos[0]=' .. string(l:pos)
   endif
 endfunction

 function! s:Run() abort
   let l:pattern = 'config'

   " Case 1: list of strings (text_cb shortens)
   let l:items1 = ['/home/user/.config/nvim/.git/config', '/tmp/other']
   function! s:TextCbStr(s) abort
     return fnamemodify(a:s, ':t')
   endfunction
   let l:res1 = matchfuzzypos(l:items1, l:pattern, { 'text_cb': function('s:TextCbStr') })
   call s:Dump('string list (text_cb basename)', l:res1, l:items1, l:pattern, function('s:TextCbStr'))

   " Case 2: list of dicts (text_cb uses different field)
   let l:items2 = [
         \ {'text': '/home/user/.config/nvim/.git/config', 'label': 'config', 'id': 1},
         \ {'text': '/tmp/other', 'label': 'other', 'id': 2},
         \ ]
   function! s:TextCbDict(d) abort
     return a:d.label
   endfunction
   let l:res2 = matchfuzzypos(l:items2, l:pattern, { 'text_cb': function('s:TextCbDict') })
   call s:Dump('dict list (text_cb label)', l:res2, l:items2, l:pattern, function('s:TextCbDict'))

   qa!
 endfunction

 call s:Run()

Expected behaviour

When using matchfuzzypos({list}, {pattern}, {dict}) with text_cb, matching is performed against the text_cb text, but the returned positions are still based on the original list item. Actually it is even worse because when {str} is an array of objects, and text_cb works on a sub property of that then the match pos works differently and reports matches on the actual propery text_cb returned. which leads to inconsistent behavior This makes the positions inconsistent with the string actually used for matching, because text_cb specifically mentioned that this is the string against the fuzzy matching is performed stands to reason the actual positions also must be reported for that same string.

Expected
If text_cb is provided, positions should be reported relative to the transformed text returned by text_cb, since that is the string used to match {pattern}.

Actual
Positions are reported relative to the original list item, regardless of text_cb.

Version of Vim

Vi IMproved 9.1

Environment

Ubuntu, alacritty

Logs and stack traces

VIM - Vi IMproved 9.1 (2024 Jan 02, compiled Jan 20 2026 19:40:35)
Included patches: 1-2100
Compiled by Homebrew
Huge version without GUI.  Features included (+) or not (-):
+acl
+arabic
+autocmd
+autochdir
-autoservername
-balloon_eval
+balloon_eval_term
-browse
++builtin_terms
+byte_offset
+channel
+cindent
+clientserver
-clipboard
+clipboard_provider
+cmdline_compl
+cmdline_hist
+cmdline_info
+comments
+conceal
+cryptv
+cscope
+cursorbind
+cursorshape
+dialog_con
+diff
+digraphs
-dnd
-ebcdic
+emacs_tags
+eval
+ex_extra
+extra_search
-farsi
+file_in_path
+find_in_path
+float
+folding
-footer
+fork()
+gettext
-hangul_input
+iconv
+insert_expand
+ipv6
+job
+jumplist
+keymap
+lambda
+langmap
+libcall
+linebreak
+lispindent
+listcmds
+localmap
+lua
+menu
+mksession
+modify_fname
+mouse
-mouseshape
+mouse_dec
-mouse_gpm
-mouse_jsbterm
+mouse_netterm
+mouse_sgr
-mouse_sysmouse
+mouse_urxvt
+mouse_xterm
+multi_byte
+multi_lang
-mzscheme
+netbeans_intg
+num64
+packages
+path_extra
+perl
+persistent_undo
+popupwin
+postscript
+printer
+profile
-python
+python3
+quickfix
+reltime
+rightleft
+ruby
+scrollbind
+signs
+smartindent
+socketserver
+sodium
-sound
+spell
+startuptime
+statusline
-sun_workshop
+syntax
+tabpanel
+tag_binary
-tag_old_static
-tag_any_white
-tcl
+termguicolors
+terminal
+terminfo
+termresponse
+textobjects
+textprop
+timers
+title
-toolbar
+user_commands
+vartabs
+vertsplit
+vim9script
+viminfo
+virtualedit
+visual
+visualextra
+vreplace
-wayland
-wayland_clipboard
-wayland_focus_steal
+wildignore
+wildmenu
+windows
+writebackup
-X11
+xattr
-xfontset
-xim
-xpm
-xsmp
-xterm_clipboard
-xterm_save
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
 3rd user vimrc file: "~/.config/vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/home/linuxbrew/.linuxbrew/share/vim"
Compilation: gcc-12 -c -I. -Iproto -DHAVE_CONFIG_H -g -O2 -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 
Linking: gcc-12 -Wl,-E -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/perl/lib/perl5/5.42/x86_64-linux-thread-multi/CORE -L/usr/local/lib -Wl,--as-needed -o vim -lm -lncurses -lsodium -lacl -L/home/lin
uxbrew/.linuxbrew/opt/lua/lib -llua5.4 -Wl,-E -Wl,-rpath,/home/linuxbrew/.linuxbrew/opt/perl/lib/perl5/5.42/x86_64-linux-thread-multi/CORE -fstack-protector-strong -L/usr/local/lib -L/home/linuxbr
ew/.linuxbrew/opt/perl/lib/perl5/5.42/x86_64-linux-thread-multi/CORE -lperl -lpthread -ldl -lm -lcrypt -lutil -lc -L/home/linuxbrew/.linuxbrew/opt/[email protected]/lib/python3.14/config-3.14-x86_64-lin
ux-gnu -lpython3.14 -ldl -lm -Wl,-rpath,/home/linuxbrew/.linuxbrew/Cellar/ruby/4.0.1/lib -L/home/linuxbrew/.linuxbrew/Cellar/ruby/4.0.1/lib -lruby -lm -lpthread

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions