I've narrowed it down as much as I can for the moment, but I'm not yet sure there's a bug. It goes like this:
Put the following text in clean.vim:
" load with vim --clean -u <this-file>
if &compatible
set nocompatible
endif
set completeopt+=fuzzy,longest
inoremap <C-a> <C-r>=complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item'])<enter>
Run vim --clean -u clean.vim, then i<C-a>. With this reproduction, I get a "0" inserted in the buffer and no completion.
In my actual use case (see also mapping), I just get nothing inserted and no completion.
My current version is below
VIM - Vi IMproved 9.1 (2024 Jan 02, compilé Dec 20 2025 21:43:43)
Rustines incluses : 1-2001
Modifié par Gentoo-9999 (RIP Bram)
Compilé par benknoble@localhost
Énorme version sans interface graphique. Fonctionnalités incluses (+) ou non (-) :
+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_interact
+xterm_clipboard
-xterm_save
fichier vimrc système : "/etc/vim/vimrc"
fichier vimrc utilisateur : "$HOME/.vimrc"
2e fichier vimrc utilisateur : "~/.vim/vimrc"
3e fichier vimrc utilisateur : "~/.config/vim/vimrc"
fichier exrc utilisateur : "$HOME/.exrc"
fichier de valeurs par défaut : "$VIMRUNTIME/defaults.vim"
$VIM par défaut : "/usr/share/vim"
Compilation : x86_64-pc-linux-gnu-gcc -c -I. -Iproto -DHAVE_CONFIG_H -march=native -O2 -pipe -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Édition de liens : x86_64-pc-linux-gnu-gcc -Wl,-O1 -Wl,--as-needed -Wl,-z,pack-relative-relocs -L/usr/local/lib -o vim -lSM -lICE -lXpm -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lcanberra -lsodium -lacl -lattr -lgpm
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
A few other symptoms:
This tells me it's either
🤔
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
On yet a third (macOS x86_64) machine, version 9.1.1775, I also don't see this issue; I also have the C-a -> 0 -> item0 from the reproducer, and repeated completion and line completion behave as expected.
That doesn't really rule out my hypotheses above, but it makes me more convinced that one of the 3 is at stake.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Ok, a fresh build on this machine (just make, nothing special) in a checkout of 2e4c98b (runtime(vim): Update base syntax, match Vim9 :unlet command, 2026-02-01) exhibits the same problem as the OP says:
With this reproduction, I get a "0" inserted in the buffer and no completion.
Might be a runtime difference? I'm going to try to run Vim under a debugger on multiple systems and see what I get, but I'm not really sure how to narrow down the issue at this point.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Interesting. On 9.1.1775 on the problem machine, I get the following via the reproducer:
i<C-a> inserts 0; a second press inserts item before the 0. cci<C-a> inserts item0 (not item?).I'm still not sure what's going on with the 0 in item0, but it seems I should now be bisecting instead (still strange that this only affected my linux machine).
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Function complete() returns a number, where 0 is probably a some kind of "success" or no error.
Your repro steps could be simplified to
vim --cleaninoremap <C-a> <C-r>=complete(col('.') - 1, ['item'])<enter>i<C-a> or itext<C-a>If you check examples of the complete function, they all return empty string
inoremap <F5> <C-R>=ListMonths()<CR>
func ListMonths()
call complete(col('.'), ['January', 'February', 'March',
\ 'April', 'May', 'June', 'July', 'August',
\ 'September', 'October', 'November', 'December'])
return ''
endfunc
In your case, not to see 0 I would add falsy op to return '' (assuming we'll always get 0 from complete() which is probably not true):
inoremap <C-a> <C-r>=complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item'])??''<enter>
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I would suggest to use <cmd> instead of <C-r>= as in
inoremap <C-a> <cmd>call complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item'])<enter>
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
PS, I have checked your usecase and you're returning
''there. So now I am not sure what the issue is, do you see0instead of completions or smth else?
Yeah, sorry for the mess. This has been tricky…
The main issue is that completion seems to be broken on one of my machines on newer versions in 2 cases:
On my at least one other machine I don't see any issues, though it's on an older version.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Ok, cot+=fuzzy definitely has an impact on the "keep completing lines" thing, too, so perhaps a better summary is
cot+=fuzzy changes insert completion when only a single item is available
Instead of inserting the match directly, for line completion (for example) the match is buried behind an additional press of <C-L>. For manual complete(), it never appears at all.
For example, load the reproducer and then do
ifoo<enter>bar<enter>fo<C-X><C-L><C-X><C-L>
You'll have to press <C-L> again to see the second bar; if you repeat the experiment with cot-=fuzzy, it appears immediately on the first C-xC-l repeat.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
For the original issue, it doesn't matter if fuzzy is enabled or not (for me) -- if you return empty string, all works as it should. There is no 0 inserted, I can see expected result. If you could show exactly what is wrong...
For the line completion, again all works fine (windows gvim and debian vim) provided you have only added fuzzy not fuzzy,longest.
@girishji do you know if this is expected? Combination of fuzzy and longest:
foo and bar linesfo<c-x><c-l><c-x><c-l>https://asciinema.org/a/UPk6DiSmULw6PQqf
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@benknoble for the original issue, I am able to reproduce it and here again fuzzy + longest doesn't complete:
set completeopt+=fuzzy,longest
inoremap <C-a> <cmd>call complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item'])<enter>
To be honest I am not sure what longest means in fuzzy context.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Yep, looks like you reproduced both issues. Glad I'm not the only one!
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Ok, I did a kind of poor-man's bisect, only looking at commits 9.1.1775 and later that touch fuzzy stuff and building them all in separate worktrees:
git log --oneline v9.1.1775.. --grep fuzzy | grep patch >to-test
awk '{print $1}' <to-test | xargs -n1 sh -ec 'git worktree add w/$0 $0'
awk '{print $1}' <to-test | xargs -n1 sh -ec 'cd w/$0; nohup make -j2 & disown'
nl test-w
1 #! /bin/bash
2 while read -u 3 sha; do
3 worktree=w/$sha
4 VIMRUNTIME="$worktree"/runtime "$worktree"/src/vim --clean -u repro.vim
5 >>notes printf '%s: ' "$sha"
6 vim notes
7 done 3< <(awk '{print $1}' <to-test)
./test-w
6e9694df1: bad
d4f9de889: bad
a3925d783: bad
057ea1232: bad
33fbfe003: bad
0e1ab0adb: good
6aac70623: good
6437997d8: good
10aa04e3d: good
e19a882ff: good
That points to 33fbfe0 (patch 9.1.1930: completion: 'completefuzzycollect' is too obscure, 2025-11-26) as being the culprit. @girishji was that change intended to affect completion as demonstrated in this issue? At least, it looks to me like it broke interaction with longest:
At least for now I know I can fix my workflows by removing fuzzy from 'completeopt', even though it's very convenient for file completion.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I am confused. It seems you've manufactured a problem. :h complete() says:
This isn't very useful, but it shows how it works. Note that
an empty string is returned to avoid a zero being inserted.
Return type: |Number|
Since that function returns 0, you have to change your keymap to something like this (so as not to insert a literal 0 at the end):
function! s:DoComplete()
call complete(
\ col('.') - matchstr(getline('.'), '\<\f\+\%'.col('.').'c')->strlen(),
\ ['item']
\ )
return ''
endfunction
inoremap <C-a> <C-r>=<SID>DoComplete()<CR>
Secondly, this problem has got not nothing to do with either fuzzy or longest -- both are working correctly. When your prefix is an empty string, the menu items are removed due to fuzzy not matching, and thus longest has nothing to insert. Remove fuzzy (or longest) and start with a prefix (like i or it) you'll see your item inserted.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@girishji writes:
I am confused. It seems you've manufactured a problem.
:h complete()says:This isn't very useful, but it shows how it works. Note that an empty string is returned to avoid a zero being inserted. Return type: |Number|Since that function returns
0, you have to change your keymap to something like this (so as not to insert a literal0at the end):
function! s:DoComplete() call complete( \ col('.') - matchstr(getline('.'), '\<\f\+\%'.col('.').'c')->strlen(), \ ['item'] \ ) return '' endfunction inoremap <C-a> <C-r>=<SID>DoComplete()<CR>
I know this is a long and confusing thread, so please read me as patient when I say that we've already covered that ;)
Secondly, this problem has got nothing to do with either
fuzzyorlongest-- both are working correctly. When your prefix is an empty string, the menu items are removed due tofuzzynot matching, and thuslongesthas nothing to insert. Removefuzzy(orlongest) and start with a prefix (likeiorit) you'll see your item inserted.
That doesn't explain why whole line completion breaks with fuzzy and longest, nor why with a fixed reproduction (e.g., below), i<C-a> doesn't insert anything (I wouldn't think that's an "empty prefix")?
" load with vim --clean -u <this-file>
if &compatible
set nocompatible
endif
set completeopt+=fuzzy,longest
inoremap <C-a> <C-r>=[complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item']), ''][1]<enter>
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
set completeopt+=longest
inoremap <C-a> <C-r>=[complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item']), ''][1]<enter>
It doesn't work without fuzzy too. So the longest is at fault here. Additionally,
{matches} must be a |List|. Each |List| item is one match.
See |complete-items| for the kind of items that are possible.
"longest" in 'completeopt' is ignored.
It should be ignored but, looks like it isn't.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
set completeopt+=longest inoremap <C-a> <C-r>=[complete(col('.') - getline('.')->matchstr('\<\f\+\%'.col('.').'c')->strlen(), ['item']), ''][1]<enter>It doesn't work without fuzzy too. So the
longestis at fault here. Additionally,{matches} must be a |List|. Each |List| item is one match. See |complete-items| for the kind of items that are possible. "longest" in 'completeopt' is ignored.It should be ignored but, looks like it isn't.
Interesting. In my actual config, I have longest set and a somewhat similar completion (linked earlier in thread). It works just fine. I'll have to try this reproducer and see if I can figure out why my version works.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()