diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 43ed28dee6..30503959c5 100644 --- 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 index a17a33ab38..e5d9a37d19 100644 --- 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 index b161824bca..86a1387770 100644 --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -1,7 +1,7 @@ " These commands create the option window. " " Maintainer: The Vim Project -" Last Change: 2025 Aug 23 +" Last Change: 2025 Sep 20 " Former Maintainer: Bram Moolenaar " 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 OptionL("cpt") call AddOption("autocomplete", gettext("automatic completion in insert mode")) + call append("$", "\t" .. s:global_or_local) call BinOptionG("ac", &ac) call 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 index 02d2d53e79..e6288b4dca 100644 --- 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 index b8a35d9c84..3e3f147e37 100644 --- 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 index 09e0bb3905..7759220df9 100644 --- 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 index 56748eb645..5374fa184b 100644 --- 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 index 560dfc7a4e..238558097b 100644 --- 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 index d59ada79d2..f7607a2c7f 100644 --- 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 index 453b0c483e..a7d06d47c8 100644 --- 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 index af1ab51c18..f06f640647 100644 --- 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 let b:matches = complete_info(["matches"]).matches - set autocomplete + setlocal autocomplete setlocal complete=.,Fcompl#Func call feedkeys("im\\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})