]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0469: Cannot have buffer-local value for 'completeopt' v9.1.0469
authorzeertzjq <zeertzjq@outlook.com>
Wed, 5 Jun 2024 18:27:06 +0000 (20:27 +0200)
committerChristian Brabandt <cb@256bit.org>
Wed, 5 Jun 2024 18:27:06 +0000 (20:27 +0200)
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>
14 files changed:
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

index 57fefa2237ab7e271d4d52c2ae9fb5d5e697ba71..655fd6c52424581ef20f59c9d26a1f0dd415074f 100644 (file)
@@ -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 short description can be found at |Q_op|.
 
                                                *'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:
 
index 07c416ae28b2ea33e2ad35e4c259e2ffd28b0f82..6edb8891bcb6bf36b2e174e6f27a4264dacfeebc 100644 (file)
@@ -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 ~
index d3e1605ed062f46a19b24fa27b52ac8d4d74a101..f218ffba20667d342727e669f54a8dcc0593d28a 100644 (file)
@@ -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)
index 58e9718e3d414aab8d553e42cb4059db6ad855b3..cbec9b980c6b8d29e0c37a82f47c69b84b8eb2e7 100644 (file)
@@ -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);
index 552c679579cb40b34e334bb5f3c914e9971ec4ba..7066be8f38b9b000a7428c476ff9c23cdfaa2764 100644 (file)
@@ -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 *list)
     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 in_compl_func)
            }
        }
     }
-    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;
 
index 2acc0d475ffc6f26ca2b6f4f4aca4291e498f55c..8521c6ed17b70ba6e3313b4ba2be257f0010dd41 100644 (file)
@@ -6224,6 +6224,10 @@ unset_global_local_option(char_u *name, void *from)
            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 scope)
            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
index bf889e47de3488f03e68abce57ce419418514ba8..91d8d95c5bf379508d63935ccd02bf2b8c11df8e 100644 (file)
@@ -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
index 50472e3f603fc6ae1857a0e04edb78069f87447f..7b58f6b3330d5946c8244fbeea1aec1b34d12d79 100644 (file)
@@ -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,
index 6b59b68085671b06f86dd9a06e0ffb0bc07e26fa..d72298194ac850bff213a24c0e0f5f7468872a66 100644 (file)
@@ -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, int *numMatches, char_u ***matches)
     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;
+
+    if (opt_strings_flags(cot, p_cot_values, flags, TRUE) != OK)
        return e_invalid_argument;
 
-    completeopt_was_set();
     return NULL;
 }
 
index 741980660fcc1e084a8ee8ff9cbd8c8a4c3db4b3..01b6ab1e95b14c6f7a30cd75d8b4853a63983643 100644 (file)
@@ -760,6 +760,7 @@ pum_set_selected(int n, int repeat UNUSED)
     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 UNUSED)
        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 UNUSED)
 # 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;
index 51f5db0f8f2739320c8b88ec33b33a1740af07d4..3d8c0428e8b9016ca950165ee660cb9e03ea2ad9 100644 (file)
@@ -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);
index bd6977ef80ccea054624d37ea797f49e62af2ad0..f1bbf1735db3e4da7334c239b1bb323ae08490a1 100644 (file)
@@ -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'
index 947b0bb646f1a353b09f2a186ade821cfc9b283f..ad9f4978e74fd1367a1440677264fd79e42af3a4 100644 (file)
@@ -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()
index 92106bc3a40e53713d10d1f64ff3de9e0389d10a..e805e2c5427156627b0548de68c4db2d5ec5579d 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    469,
 /**/
     468,
 /**/