commit a70997442e0cbc380abf8b82eac3aa18b40b4df1
parent 6b7fc9d37f92d46d46769874748a0dd483585577
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sun, 21 Sep 2025 08:56:38 +0800
vim-patch:9.1.1779: completion: 'autocomplete' cannot be enabled per buffer (#35853)
Problem: completion: 'autocomplete' cannot be enabled per buffer
(Tomasz N)
Solution: Make 'autocomplete' global or local to buffer (Girish Palya)
fixes: vim/vim#18320
closes: vim/vim#18333
https://github.com/vim/vim/commit/0208b3e80a080740ff77a5661d0f65090e317d90
Co-authored-by: Girish Palya <girishji@gmail.com>
Diffstat:
11 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
@@ -743,7 +743,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'autocomplete'* *'ac'* *'noautocomplete'* *'noac'*
'autocomplete' 'ac' boolean (default off)
- global
+ global or local to buffer |global-local|
When on, Vim shows a completion menu as you type, similar to using
|i_CTRL-N|, but triggered automatically. See |ins-autocompletion|.
diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua
@@ -117,6 +117,8 @@ vim.go.acd = vim.go.autochdir
--- @type boolean
vim.o.autocomplete = false
vim.o.ac = vim.o.autocomplete
+vim.bo.autocomplete = vim.o.autocomplete
+vim.bo.ac = vim.bo.autocomplete
vim.go.autocomplete = vim.o.autocomplete
vim.go.ac = vim.go.autocomplete
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: The Vim Project <https://github.com/vim/vim>
-" Last Change: 2025 Aug 23
+" Last Change: 2025 Sep 20
" Former Maintainer: Bram Moolenaar <Bram@vim.org>
" If there already is an option window, jump to that one.
@@ -736,6 +736,7 @@ if has("insert_expand")
call append("$", "\t" .. s:local_to_buffer)
call <SID>OptionL("cpt")
call <SID>AddOption("autocomplete", gettext("automatic completion in insert mode"))
+ call append("$", "\t" .. s:global_or_local)
call <SID>BinOptionG("ac", &ac)
call <SID>AddOption("autocompletetimeout", gettext("initial decay timeout for 'autocomplete' algorithm"))
call append("$", " \tset act=" . &act)
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
@@ -2122,6 +2122,7 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
clear_string_option(&buf->b_p_dia);
clear_string_option(&buf->b_p_tsr);
clear_string_option(&buf->b_p_qe);
+ buf->b_p_ac = -1;
buf->b_p_ar = -1;
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
clear_string_option(&buf->b_p_lw);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
@@ -514,6 +514,7 @@ struct file_buffer {
sctx_T b_p_script_ctx[kBufOptCount]; // SCTXs for buffer-local options
+ int b_p_ac; ///< 'autocomplete'
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
char *b_p_bkc; ///< 'backupco
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
@@ -605,7 +605,7 @@ static int insert_execute(VimState *state, int key)
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
&& stop_arrow() == OK) {
ins_compl_delete(false);
- if (ins_compl_has_preinsert() && ins_compl_has_autocomplete()) {
+ if (ins_compl_has_preinsert() && ins_compl_autocomplete_enabled()) {
(void)ins_compl_insert(false, true);
} else {
(void)ins_compl_insert(false, false);
@@ -851,7 +851,8 @@ static int insert_handle_key(InsertState *s)
case Ctrl_H:
s->did_backspace = ins_bs(s->c, BACKSPACE_CHAR, &s->inserted_space);
auto_format(false, true);
- if (s->did_backspace && p_ac && !char_avail() && curwin->w_cursor.col > 0) {
+ if (s->did_backspace && ins_compl_has_autocomplete() && !char_avail()
+ && curwin->w_cursor.col > 0) {
s->c = char_before_cursor();
if (vim_isprintc(s->c)) {
redraw_later(curwin, UPD_VALID);
@@ -1238,7 +1239,7 @@ normalchar:
// closed fold.
foldOpenCursor();
// Trigger autocompletion
- if (p_ac && !char_avail() && vim_isprintc(s->c)) {
+ if (ins_compl_has_autocomplete() && !char_avail() && vim_isprintc(s->c)) {
redraw_later(curwin, UPD_VALID);
update_screen(); // Show character immediately
ui_flush();
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
@@ -2151,7 +2151,7 @@ bool ins_compl_preinsert_effect(void)
}
/// Returns true if autocompletion is active.
-bool ins_compl_has_autocomplete(void)
+bool ins_compl_autocomplete_enabled(void)
{
return compl_autocomplete;
}
@@ -2227,6 +2227,13 @@ static bool ins_compl_need_restart(void)
return compl_was_interrupted || ins_compl_refresh_always();
}
+/// Return true if 'autocomplete' option is set
+bool ins_compl_has_autocomplete(void)
+{
+ // Use buffer-local setting if defined (>= 0), otherwise use global
+ return curbuf->b_p_ac >= 0 ? curbuf->b_p_ac : p_ac;
+}
+
/// Called after changing "compl_leader".
/// Show the popup menu with a different set of matches.
/// May also search for matches again if the previous search was interrupted.
@@ -2256,9 +2263,7 @@ static void ins_compl_new_leader(void)
// Matches were cleared, need to search for them now.
// Set "compl_restarting" to avoid that the first match is inserted.
compl_restarting = true;
- if (p_ac) {
- compl_autocomplete = true;
- }
+ compl_autocomplete = ins_compl_has_autocomplete();
if (ins_complete(Ctrl_N, true) == FAIL) {
compl_cont_status = 0;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
@@ -384,6 +384,7 @@ void set_init_1(bool clean_arg)
set_options_default(0);
curbuf->b_p_initialized = true;
+ curbuf->b_p_ac = -1;
curbuf->b_p_ar = -1; // no local 'autoread' value
curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL;
check_buf_options(curbuf);
@@ -3368,6 +3369,7 @@ static OptVal get_option_unset_value(OptIndex opt_idx)
}
switch (opt_idx) {
+ case kOptAutocomplete:
case kOptAutoread:
return BOOLEAN_OPTVAL(kNone);
case kOptScrolloff:
@@ -4421,6 +4423,8 @@ void *get_varp_scope_from(vimoption_T *p, int opt_flags, buf_T *buf, win_T *win)
return &(buf->b_p_kp);
case kOptPath:
return &(buf->b_p_path);
+ case kOptAutocomplete:
+ return &(buf->b_p_ac);
case kOptAutoread:
return &(buf->b_p_ar);
case kOptTags:
@@ -4508,6 +4512,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var;
case kOptPath:
return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var;
+ case kOptAutocomplete:
+ return buf->b_p_ac >= 0 ? &(buf->b_p_ac) : p->var;
case kOptAutoread:
return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var;
case kOptTags:
@@ -5204,6 +5210,7 @@ void buf_copy_options(buf_T *buf, int flags)
// options that are normally global but also have a local value
// are not copied, start using the global value
+ buf->b_p_ac = -1;
buf->b_p_ar = -1;
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
buf->b_p_bkc = empty_string_option;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
@@ -236,7 +236,7 @@ local options = {
|i_CTRL-N|, but triggered automatically. See |ins-autocompletion|.
]=],
full_name = 'autocomplete',
- scope = { 'global' },
+ scope = { 'global', 'buf' },
short_desc = N_('automatic completion in insert mode'),
type = 'boolean',
varname = 'p_ac',
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
@@ -1416,7 +1416,7 @@ describe('completion', function()
screen:try_resize(60, 10)
source([[
call setline(1, ['foo', 'foobar', 'foobarbaz'])
- set autocomplete
+ setlocal autocomplete
]])
screen:expect([[
^foo |
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
@@ -5566,7 +5566,7 @@ func Test_scriptlocal_autoload_func()
call Ntest_override("char_avail", 1)
new
inoremap <buffer> <F2> <Cmd>let b:matches = complete_info(["matches"]).matches<CR>
- set autocomplete
+ setlocal autocomplete
setlocal complete=.,Fcompl#Func
call feedkeys("im\<F2>\<Esc>0", 'xt!')
@@ -5577,7 +5577,6 @@ func Test_scriptlocal_autoload_func()
call assert_equal(['foo', 'foobar'], b:matches->mapnew('v:val.word'))
setlocal complete&
- set autocomplete&
bwipe!
call Ntest_override("char_avail", 0)
let &rtp = save_rtp
@@ -5676,7 +5675,7 @@ func Test_autocompletedelay()
let lines =<< trim [SCRIPT]
call setline(1, ['foo', 'foobar', 'foobarbaz'])
- set autocomplete
+ setlocal autocomplete
[SCRIPT]
call writefile(lines, 'XTest_autocomplete_delay', 'D')
let buf = RunVimInTerminal('-S XTest_autocomplete_delay', {'rows': 10})