Mercurial > vim
changeset 35340:5c4e1b16db10 v9.1.0469
patch 9.1.0469: Cannot have buffer-local value for 'completeopt'
Commit: https://github.com/vim/vim/commit/529b9ad62a0e843ee56ef609aef7e51b7dc8a4c8
Author: zeertzjq <zeertzjq@outlook.com>
Date: Wed Jun 5 20:27:06 2024 +0200
patch 9.1.0469: Cannot have buffer-local value for 'completeopt'
Problem: Cannot have buffer-local value for 'completeopt'
(Nick Jensen).
Solution: Make 'completeopt' global-local (zeertzjq).
Also for some reason test Test_ColonEight_MultiByte seems to be failing
sporadically now. Let's mark it as flaky.
fixes: #5487
closes: #14922
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Wed, 05 Jun 2024 20:45:03 +0200 |
parents | 7a406eaacba4 |
children | fb5e8ec02d00 |
files | runtime/doc/options.txt runtime/doc/version9.txt runtime/optwin.vim src/buffer.c src/insexpand.c src/option.c src/option.h src/optiondefs.h src/optionstr.c src/popupmenu.c src/proto/insexpand.pro src/structs.h src/testdir/test_ins_complete.vim src/version.c |
diffstat | 14 files changed, 146 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 9.1. Last change: 2024 Jun 04 +*options.txt* For Vim version 9.1. Last change: 2024 Jun 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2101,7 +2101,7 @@ A jump table for the options with a shor *'completeopt'* *'cot'* 'completeopt' 'cot' string (default: "menu,preview") - global + global or local to buffer |global-local| A comma-separated list of options for Insert mode completion |ins-completion|. The supported values are:
--- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2024 Jun 03 +*version9.txt* For Vim version 9.1. Last change: 2024 Jun 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41567,6 +41567,7 @@ Changed~ - use 'smoothscroll' logic for CTRL-D and CTRL-U for half-pagewise scrolling - the default for 'commentstring' contains whitespace padding to have automatic comments look nicer |comment-install| +- 'completeopt' is now a |global-local| option. *added-9.2* Added ~
--- 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: 2023 Aug 31 +" Last Change: 2024 Jun 05 " Former Maintainer: Bram Moolenaar <Bram@vim.org> " If there already is an option window, jump to that one. @@ -846,7 +846,7 @@ if has("insert_expand") call append("$", "\t" .. s:local_to_buffer) call <SID>OptionL("cpt") call <SID>AddOption("completeopt", gettext("whether to use a popup menu for Insert mode completion")) - call <SID>OptionG("cot", &cot) + call <SID>OptionL("cot") if exists("+completepopup") call <SID>AddOption("completepopup", gettext("options for the Insert mode completion info popup")) call <SID>OptionG("cpp", &cpp)
--- a/src/buffer.c +++ b/src/buffer.c @@ -2429,6 +2429,7 @@ free_buf_options( clear_string_option(&buf->b_p_lop); clear_string_option(&buf->b_p_cinsd); clear_string_option(&buf->b_p_cinw); + clear_string_option(&buf->b_p_cot); clear_string_option(&buf->b_p_cpt); #ifdef FEAT_COMPL_FUNC clear_string_option(&buf->b_p_cfu);
--- a/src/insexpand.c +++ b/src/insexpand.c @@ -148,14 +148,6 @@ static char_u *compl_leader = NULL; static int compl_get_longest = FALSE; // put longest common string // in compl_leader -static int compl_no_insert = FALSE; // FALSE: select & insert - // TRUE: noinsert -static int compl_no_select = FALSE; // FALSE: select & insert - // TRUE: noselect -static int compl_longest = FALSE; // FALSE: insert full match - // TRUE: insert longest prefix -static int compl_fuzzy_match = FALSE; // True: fuzzy match enabled - // Selected one of the matches. When FALSE the match was edited or using the // longest common string. static int compl_used_match; @@ -1054,24 +1046,12 @@ ins_compl_long_shown_match(void) } /* - * Set variables that store noselect and noinsert behavior from the - * 'completeopt' value. + * Get the local or global value of 'completeopt' flags. */ - void -completeopt_was_set(void) + unsigned int +get_cot_flags(void) { - compl_no_insert = FALSE; - compl_no_select = FALSE; - compl_longest = FALSE; - compl_fuzzy_match = FALSE; - if (strstr((char *)p_cot, "noselect") != NULL) - compl_no_select = TRUE; - if (strstr((char *)p_cot, "noinsert") != NULL) - compl_no_insert = TRUE; - if (strstr((char *)p_cot, "longest") != NULL) - compl_longest = TRUE; - if (strstr((char *)p_cot, "fuzzy") != NULL) - compl_fuzzy_match = TRUE; + return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags; } @@ -1118,7 +1098,7 @@ ins_compl_del_pum(void) pum_wanted(void) { // 'completeopt' must contain "menu" or "menuone" - if (vim_strchr(p_cot, 'm') == NULL) + if ((get_cot_flags() & COT_ANY_MENU) == 0) return FALSE; // The display looks bad on a B&W display. @@ -1152,7 +1132,7 @@ pum_enough_matches(void) compl = compl->cp_next; } while (!is_first_match(compl)); - if (strstr((char *)p_cot, "menuone") != NULL) + if (get_cot_flags() & COT_MENUONE) return (i >= 1); return (i >= 2); } @@ -1246,6 +1226,9 @@ ins_compl_build_pum(void) int cur = -1; int lead_len = 0; int max_fuzzy_score = 0; + int cur_cot_flags = get_cot_flags(); + int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; + int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; // Need to build the popup menu list. compl_match_arraysize = 0; @@ -2469,9 +2452,8 @@ ins_compl_prep(int c) if (ctrl_x_mode_not_defined_yet() || (ctrl_x_mode_normal() && !compl_started)) { - compl_get_longest = compl_longest; + compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0; compl_used_match = TRUE; - } if (ctrl_x_mode_not_defined_yet()) @@ -2943,6 +2925,10 @@ set_completion(colnr_T startcol, list_T int save_w_wrow = curwin->w_wrow; int save_w_leftcol = curwin->w_leftcol; int flags = CP_ORIGINAL_TEXT; + int cur_cot_flags = get_cot_flags(); + int compl_longest = (cur_cot_flags & COT_LONGEST) != 0; + int compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; // If already doing completions stop it. if (ctrl_x_mode_not_default()) @@ -4140,6 +4126,9 @@ find_next_completion_match( { int found_end = FALSE; compl_T *found_compl = NULL; + int cur_cot_flags = get_cot_flags(); + int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; + int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; while (--todo >= 0) { @@ -4257,6 +4246,9 @@ ins_compl_next( int advance; int started = compl_started; buf_T *orig_curbuf = curbuf; + int cur_cot_flags = get_cot_flags(); + int compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0; + int compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0; // When user complete function return -1 for findstart which is next // time of 'always', compl_shown_match become NULL. @@ -4411,7 +4403,7 @@ ins_compl_check_keys(int frequency, int } } } - if (compl_pending != 0 && !got_int && !compl_no_insert) + if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) { int todo = compl_pending > 0 ? compl_pending : -compl_pending;
--- a/src/option.c +++ b/src/option.c @@ -6224,6 +6224,10 @@ unset_global_local_option(char_u *name, clear_string_option(&buf->b_p_inc); break; # endif + case PV_COT: + clear_string_option(&buf->b_p_cot); + buf->b_cot_flags = 0; + break; case PV_DICT: clear_string_option(&buf->b_p_dict); break; @@ -6333,6 +6337,7 @@ get_varp_scope(struct vimoption *p, int case PV_DEF: return (char_u *)&(curbuf->b_p_def); case PV_INC: return (char_u *)&(curbuf->b_p_inc); #endif + case PV_COT: return (char_u *)&(curbuf->b_p_cot); case PV_DICT: return (char_u *)&(curbuf->b_p_dict); case PV_TSR: return (char_u *)&(curbuf->b_p_tsr); #ifdef FEAT_COMPL_FUNC @@ -6413,6 +6418,8 @@ get_varp(struct vimoption *p) case PV_INC: return *curbuf->b_p_inc != NUL ? (char_u *)&(curbuf->b_p_inc) : p->var; #endif + case PV_COT: return *curbuf->b_p_cot != NUL + ? (char_u *)&(curbuf->b_p_cot) : p->var; case PV_DICT: return *curbuf->b_p_dict != NUL ? (char_u *)&(curbuf->b_p_dict) : p->var; case PV_TSR: return *curbuf->b_p_tsr != NUL @@ -7205,6 +7212,8 @@ buf_copy_options(buf_T *buf, int flags) COPY_OPT_SCTX(buf, BV_INEX); # endif #endif + buf->b_p_cot = empty_option; + buf->b_cot_flags = 0; buf->b_p_dict = empty_option; buf->b_p_tsr = empty_option; #ifdef FEAT_COMPL_FUNC
--- a/src/option.h +++ b/src/option.h @@ -513,6 +513,20 @@ EXTERN int p_confirm; // 'confirm' #endif EXTERN int p_cp; // 'compatible' EXTERN char_u *p_cot; // 'completeopt' +EXTERN unsigned cot_flags; // flags from 'completeopt' +// Keep in sync with p_cot_values in optionstr.c +#define COT_MENU 0x001 +#define COT_MENUONE 0x002 +#define COT_ANY_MENU 0x003 // combination of menu flags +#define COT_LONGEST 0x004 // FALSE: insert full match, + // TRUE: insert longest prefix +#define COT_PREVIEW 0x008 +#define COT_POPUP 0x010 +#define COT_POPUPHIDDEN 0x020 +#define COT_ANY_PREVIEW 0x038 // combination of preview flags +#define COT_NOINSERT 0x040 // FALSE: select & insert, TRUE: noinsert +#define COT_NOSELECT 0x080 // FALSE: select & insert, TRUE: noselect +#define COT_FUZZY 0x100 // TRUE: fuzzy match enabled #ifdef BACKSLASH_IN_FILENAME EXTERN char_u *p_csl; // 'completeslash' #endif @@ -1127,6 +1141,7 @@ enum , BV_CMS #endif , BV_COM + , BV_COT , BV_CPT , BV_DICT , BV_TSR
--- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -50,6 +50,7 @@ # define PV_CMS OPT_BUF(BV_CMS) #endif #define PV_COM OPT_BUF(BV_COM) +#define PV_COT OPT_BOTH(OPT_BUF(BV_COT)) #define PV_CPT OPT_BUF(BV_CPT) #define PV_DICT OPT_BOTH(OPT_BUF(BV_DICT)) #define PV_TSR OPT_BOTH(OPT_BUF(BV_TSR)) @@ -654,7 +655,7 @@ static struct vimoption options[] = #endif SCTX_INIT}, {"completeopt", "cot", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, - (char_u *)&p_cot, PV_NONE, did_set_completeopt, expand_set_completeopt, + (char_u *)&p_cot, PV_COT, did_set_completeopt, expand_set_completeopt, {(char_u *)"menu,preview", (char_u *)0L} SCTX_INIT}, {"completepopup", "cpp", P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_COLON,
--- a/src/optionstr.c +++ b/src/optionstr.c @@ -144,6 +144,7 @@ didset_string_options(void) (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE); (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, TRUE); (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, TRUE); + (void)opt_strings_flags(p_cot, p_cot_values, &cot_flags, TRUE); #ifdef FEAT_SESSION (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE); (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, TRUE); @@ -301,6 +302,7 @@ check_buf_options(buf_T *buf) check_string_option(&buf->b_p_lop); check_string_option(&buf->b_p_ft); check_string_option(&buf->b_p_cinw); + check_string_option(&buf->b_p_cot); check_string_option(&buf->b_p_cpt); #ifdef FEAT_COMPL_FUNC check_string_option(&buf->b_p_cfu); @@ -1601,10 +1603,21 @@ expand_set_complete(optexpand_T *args, i char * did_set_completeopt(optset_T *args UNUSED) { - if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK) + char_u *cot = p_cot; + unsigned *flags = &cot_flags; + + if (args->os_flags & OPT_LOCAL) + { + cot = curbuf->b_p_cot; + flags = &curbuf->b_cot_flags; + } + + if (check_opt_strings(cot, p_cot_values, TRUE) != OK) return e_invalid_argument; - completeopt_was_set(); + if (opt_strings_flags(cot, p_cot_values, flags, TRUE) != OK) + return e_invalid_argument; + return NULL; }
--- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -760,6 +760,7 @@ pum_set_selected(int n, int repeat UNUSE int context = pum_height / 2; #ifdef FEAT_QUICKFIX int prev_selected = pum_selected; + unsigned cur_cot_flags = get_cot_flags(); #endif #if defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX) int has_info = FALSE; @@ -831,7 +832,7 @@ pum_set_selected(int n, int repeat UNUSE if (pum_array[pum_selected].pum_info != NULL && Rows > 10 && repeat <= 1 - && vim_strchr(p_cot, 'p') != NULL) + && (cur_cot_flags & COT_ANY_PREVIEW)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; @@ -842,9 +843,9 @@ pum_set_selected(int n, int repeat UNUSE # endif # ifdef FEAT_PROP_POPUP has_info = TRUE; - if (strstr((char *)p_cot, "popuphidden") != NULL) + if (cur_cot_flags & COT_POPUPHIDDEN) use_popup = USEPOPUP_HIDDEN; - else if (strstr((char *)p_cot, "popup") != NULL) + else if (cur_cot_flags & COT_POPUP) use_popup = USEPOPUP_NORMAL; else use_popup = USEPOPUP_NONE;
--- a/src/proto/insexpand.pro +++ b/src/proto/insexpand.pro @@ -27,7 +27,7 @@ int ins_compl_accept_char(int c); int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname, int dir, int cont_s_ipos); int ins_compl_has_shown_match(void); int ins_compl_long_shown_match(void); -void completeopt_was_set(void); +unsigned get_cot_flags(void); int pum_wanted(void); void ins_compl_show_pum(void); char_u *find_word_start(char_u *ptr);
--- a/src/structs.h +++ b/src/structs.h @@ -3222,6 +3222,8 @@ struct file_buffer #ifdef FEAT_FOLDING char_u *b_p_cms; // 'commentstring' #endif + char_u *b_p_cot; // 'completeopt' local value + unsigned b_cot_flags; // flags for 'completeopt' char_u *b_p_cpt; // 'complete' #ifdef BACKSLASH_IN_FILENAME char_u *b_p_csl; // 'completeslash'
--- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -809,6 +809,74 @@ func Test_complete_with_longest() bwipe! endfunc +" Test for buffer-local value of 'completeopt' +func Test_completeopt_buffer_local() + set completeopt=menu + new + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + setlocal bufhidden=hide + enew + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + setlocal completeopt+=fuzzy,noinsert + call assert_equal('menu,fuzzy,noinsert', &l:completeopt) + call assert_equal('menu,fuzzy,noinsert', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix') + call assert_equal('foobaz', getline('.')) + + setlocal completeopt= + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix') + call assert_equal('foofoo', getline('.')) + + setlocal completeopt+=longest + call assert_equal('menu,longest', &l:completeopt) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + + setlocal bufhidden=hide + buffer # + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-Y>", 'tnix') + call assert_equal('foofoo', getline('.')) + + setlocal completeopt+=fuzzy,noinsert + call assert_equal('menu,fuzzy,noinsert', &l:completeopt) + call assert_equal('menu,fuzzy,noinsert', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix') + call assert_equal('foobaz', getline('.')) + + buffer # + call assert_equal('menu,longest', &l:completeopt) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + + setlocal bufhidden=wipe + buffer! # + bwipe! + call assert_equal('', &l:completeopt) + call assert_equal('menu', &completeopt) + call assert_equal('menu', &g:completeopt) + + set completeopt& +endfunc " Test for completing words following a completed word in a line func Test_complete_wrapscan()