fix(completion): preselect ignores completeopt flag #39030

Problem: compl_preselect_match is set even when completeopt doesn't
include preselect.

Solution: Check kOptCotFlagPreselect in ins_compl_add before setting
compl_preselect_match.
This commit is contained in:
glepnir
2026-04-14 14:30:16 +08:00
committed by GitHub
parent 7bb8231577
commit aa7cba995d
2 changed files with 14 additions and 2 deletions

View File

@@ -971,7 +971,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match->cp_number = flags & CP_ORIGINAL_TEXT ? 0 : -1;
match->cp_str = cbuf_to_string(str, (size_t)len);
match->cp_preselect = preselect;
if (preselect && compl_preselect_match == NULL) {
if (preselect && compl_preselect_match == NULL
&& (get_cot_flags() & kOptCotFlagPreselect)) {
compl_preselect_match = match;
}
@@ -3452,7 +3453,7 @@ static void set_completion(colnr_T startcol, list_T *list)
compl_curr_match = compl_first_match;
bool no_select = compl_no_select || compl_longest;
if ((get_cot_flags() & kOptCotFlagPreselect) && compl_preselect_match && !no_select) {
if (compl_preselect_match && !no_select) {
compl_curr_match = compl_preselect_match->cp_prev;
ins_complete(Ctrl_N, false);
} else if (compl_no_insert || no_select) {
@@ -6511,6 +6512,11 @@ static void remove_old_matches(void)
shown_match_removed = true;
}
// Avoid dangling pointer when preselect match is removed.
if (to_delete == compl_preselect_match) {
compl_preselect_match = NULL;
}
current = current->cp_next;
if (to_delete == compl_first_match) { // node to remove is at head

View File

@@ -328,6 +328,12 @@ describe('completion', function()
{1:~ }|*2
{5:-- INSERT --} |
]])
-- without "preselect" in completeopt, preselect attribute is ignored
feed('<Esc>S')
command('set completeopt-=preselect')
feed('<C-r>=TestComplete()<CR><C-N><C-Y>')
eq('aaa', api.nvim_get_current_line())
end)
end)
end)