patch 9.1.1374: completion: 'smartcase' not respected when filtering matches
Problem: Currently, 'smartcase' is respected when completing keywords
using <C-N>, <C-P>, <C-X><C-N>, and <C-X><C-P>. However, when
a user continues typing and the completion menu is filtered
using cached matches, 'smartcase' is not applied. This leads
to poor-quality or irrelevant completion suggestions, as shown
in the example below.
Solution: When filtering cached completion items after typing additional
characters, apply case-sensitive comparison if 'smartcase' is
enabled and the typed pattern includes uppercase characters.
This ensures consistent and expected completion behavior.
(Girish Palya)
closes: #17271
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index 73565a5..6f342ae 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -4213,6 +4213,93 @@
delfunc PrintMenuWords
endfunc
+" Test normal mode (^N/^P/^X^N/^X^P) with smartcase when 1) matches are first
+" found and 2) matches are filtered (when a character is typed).
+func Test_smartcase_normal_mode()
+
+ func! PrintMenu()
+ let info = complete_info(["matches"])
+ call map(info.matches, {_, v -> v.word})
+ return info
+ endfunc
+
+ func! TestInner(key)
+ let pr = "\<c-r>=PrintMenu()\<cr>"
+
+ new
+ set completeopt=menuone,noselect ignorecase smartcase
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}{pr}"
+ call assert_equal('F{''matches'': [''Fast'', ''FAST'', ''False'',
+ \ ''FALSE'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}a{pr}"
+ call assert_equal('Fa{''matches'': [''Fast'', ''False'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}a\<bs>{pr}"
+ call assert_equal('F{''matches'': [''Fast'', ''FAST'', ''False'',
+ \ ''FALSE'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}ax{pr}"
+ call assert_equal('Fax{''matches'': []}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}ax\<bs>{pr}"
+ call assert_equal('Fa{''matches'': [''Fast'', ''False'']}', getline(1))
+
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}A{pr}"
+ call assert_equal('FA{''matches'': [''FAST'', ''FALSE'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}A\<bs>{pr}"
+ call assert_equal('F{''matches'': [''Fast'', ''FAST'', ''False'',
+ \ ''FALSE'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}AL{pr}"
+ call assert_equal('FAL{''matches'': [''FALSE'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}ALx{pr}"
+ call assert_equal('FALx{''matches'': []}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOF{a:key}ALx\<bs>{pr}"
+ call assert_equal('FAL{''matches'': [''FALSE'']}', getline(1))
+
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOf{a:key}{pr}"
+ call assert_equal('f{''matches'': [''Fast'', ''FAST'', ''False'', ''FALSE'',
+ \ ''fast'', ''false'']}', getline(1))
+ %d
+ call setline(1, ["Fast", "FAST", "False", "FALSE", "fast", "false"])
+ exe $"normal! ggOf{a:key}a{pr}"
+ call assert_equal('fa{''matches'': [''Fast'', ''FAST'', ''False'', ''FALSE'',
+ \ ''fast'', ''false'']}', getline(1))
+
+ %d
+ exe $"normal! ggOf{a:key}{pr}"
+ call assert_equal('f{''matches'': []}', getline(1))
+ exe $"normal! ggOf{a:key}a\<bs>{pr}"
+ call assert_equal('f{''matches'': []}', getline(1))
+ set ignorecase& smartcase& completeopt&
+ bw!
+ endfunc
+
+ call TestInner("\<c-n>")
+ call TestInner("\<c-p>")
+ call TestInner("\<c-x>\<c-n>")
+ call TestInner("\<c-x>\<c-p>")
+ delfunc PrintMenu
+ delfunc TestInner
+endfunc
+
" Test 'nearest' flag of 'completeopt'
func Test_nearest_cpt_option()