mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	vim-patch:8.2.0084: complete item "user_data" can only be a string
Problem:    Complete item "user_data" can only be a string.
Solution:   Accept any type of variable. (closes vim/vim#5412)
0892832bb6
			
			
This commit is contained in:
		@@ -1083,7 +1083,8 @@ items:
 | 
			
		||||
	empty		when non-zero this match will be added even when it is
 | 
			
		||||
			an empty string
 | 
			
		||||
	user_data 	custom data which is associated with the item and
 | 
			
		||||
			available in |v:completed_item|
 | 
			
		||||
			available in |v:completed_item|; it can be any type;
 | 
			
		||||
			defaults to an empty string
 | 
			
		||||
 | 
			
		||||
All of these except "icase", "equal", "dup" and "empty" must be a string.  If
 | 
			
		||||
an item does not meet these requirements then an error message is given and
 | 
			
		||||
 
 | 
			
		||||
@@ -143,6 +143,7 @@ struct compl_S {
 | 
			
		||||
  compl_T     *cp_prev;
 | 
			
		||||
  char_u      *cp_str;          // matched text
 | 
			
		||||
  char_u      *(cp_text[CPT_COUNT]);    // text for the menu
 | 
			
		||||
  typval_T    cp_user_data;
 | 
			
		||||
  char_u      *cp_fname;        // file containing the match, allocated when
 | 
			
		||||
                                // cp_flags has CP_FREE_FNAME
 | 
			
		||||
  int cp_flags;                 // CP_ values
 | 
			
		||||
@@ -2291,7 +2292,7 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
 | 
			
		||||
    flags |= CP_ICASE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ins_compl_add(str, len, fname, NULL, false, dir, flags, false);
 | 
			
		||||
  return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Add a match to the list of matches
 | 
			
		||||
@@ -2315,6 +2316,7 @@ static int ins_compl_add(char_u *const str, int len,
 | 
			
		||||
                         char_u *const fname,
 | 
			
		||||
                         char_u *const *const cptext,
 | 
			
		||||
                         const bool cptext_allocated,
 | 
			
		||||
                         typval_T *user_data,
 | 
			
		||||
                         const Direction cdir, int flags_arg, const bool adup)
 | 
			
		||||
  FUNC_ATTR_NONNULL_ARG(1)
 | 
			
		||||
{
 | 
			
		||||
@@ -2403,6 +2405,10 @@ static int ins_compl_add(char_u *const str, int len,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (user_data != NULL) {
 | 
			
		||||
    match->cp_user_data = *user_data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * Link the new match structure in the list of matches.
 | 
			
		||||
   */
 | 
			
		||||
@@ -2521,7 +2527,7 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
 | 
			
		||||
  int dir = compl_direction;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < num_matches && add_r != FAIL; i++) {
 | 
			
		||||
    if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, dir,
 | 
			
		||||
    if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
 | 
			
		||||
                               icase ? CP_ICASE : 0, false)) == OK) {
 | 
			
		||||
      // If dir was BACKWARD then honor it just once.
 | 
			
		||||
      dir = FORWARD;
 | 
			
		||||
@@ -2596,7 +2602,7 @@ void set_completion(colnr_T startcol, list_T *list)
 | 
			
		||||
  if (p_ic) {
 | 
			
		||||
    flags |= CP_ICASE;
 | 
			
		||||
  }
 | 
			
		||||
  if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
 | 
			
		||||
  if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
 | 
			
		||||
                    flags, false) != OK) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@@ -3120,6 +3126,7 @@ static void ins_compl_free(void)
 | 
			
		||||
    for (int i = 0; i < CPT_COUNT; i++) {
 | 
			
		||||
      xfree(match->cp_text[i]);
 | 
			
		||||
    }
 | 
			
		||||
    tv_clear(&match->cp_user_data);
 | 
			
		||||
    xfree(match);
 | 
			
		||||
  } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
 | 
			
		||||
  compl_first_match = compl_curr_match = NULL;
 | 
			
		||||
@@ -3215,8 +3222,11 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
 | 
			
		||||
                          (char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
 | 
			
		||||
          tv_dict_add_str(di, S_LEN("info"),
 | 
			
		||||
                          (char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
 | 
			
		||||
          tv_dict_add_str(di, S_LEN("user_data"),
 | 
			
		||||
                          (char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
 | 
			
		||||
          if (match->cp_user_data.v_type == VAR_UNKNOWN) {
 | 
			
		||||
              tv_dict_add_str(di, S_LEN("user_data"), "");
 | 
			
		||||
          } else {
 | 
			
		||||
              tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        match = match->cp_next;
 | 
			
		||||
      } while (match != NULL && match != compl_first_match);
 | 
			
		||||
@@ -3930,15 +3940,16 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
 | 
			
		||||
  bool empty = false;
 | 
			
		||||
  int flags = 0;
 | 
			
		||||
  char *(cptext[CPT_COUNT]);
 | 
			
		||||
  typval_T user_data;
 | 
			
		||||
 | 
			
		||||
  user_data.v_type = VAR_UNKNOWN;
 | 
			
		||||
  if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
 | 
			
		||||
    word = tv_dict_get_string(tv->vval.v_dict, "word", false);
 | 
			
		||||
    cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
 | 
			
		||||
    cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
 | 
			
		||||
    cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
 | 
			
		||||
    cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
 | 
			
		||||
    cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict,
 | 
			
		||||
                                               "user_data", true);
 | 
			
		||||
    tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
 | 
			
		||||
 | 
			
		||||
    if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
 | 
			
		||||
      flags |= CP_ICASE;
 | 
			
		||||
@@ -3960,7 +3971,7 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
 | 
			
		||||
    return FAIL;
 | 
			
		||||
  }
 | 
			
		||||
  return ins_compl_add((char_u *)word, -1, NULL,
 | 
			
		||||
                       (char_u **)cptext, true, dir, flags, dup);
 | 
			
		||||
                       (char_u **)cptext, true, &user_data, dir, flags, dup);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get the next expansion(s), using "compl_pattern".
 | 
			
		||||
@@ -4450,9 +4461,11 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
 | 
			
		||||
  tv_dict_add_str(
 | 
			
		||||
      dict, S_LEN("info"),
 | 
			
		||||
      (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
 | 
			
		||||
  tv_dict_add_str(
 | 
			
		||||
      dict, S_LEN("user_data"),
 | 
			
		||||
      (const char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
 | 
			
		||||
  if (match->cp_user_data.v_type == VAR_UNKNOWN) {
 | 
			
		||||
    tv_dict_add_str(dict, S_LEN("user_data"), "");
 | 
			
		||||
  } else {
 | 
			
		||||
    tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data);
 | 
			
		||||
  }
 | 
			
		||||
  return dict;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -5155,7 +5168,7 @@ static int ins_complete(int c, bool enable_pum)
 | 
			
		||||
    if (p_ic) {
 | 
			
		||||
      flags |= CP_ICASE;
 | 
			
		||||
    }
 | 
			
		||||
    if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
 | 
			
		||||
    if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
 | 
			
		||||
                      flags, false) != OK) {
 | 
			
		||||
      XFREE_CLEAR(compl_pattern);
 | 
			
		||||
      XFREE_CLEAR(compl_orig_text);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,7 @@
 | 
			
		||||
#define CPT_MENU        1   // "menu"
 | 
			
		||||
#define CPT_KIND        2   // "kind"
 | 
			
		||||
#define CPT_INFO        3   // "info"
 | 
			
		||||
#define CPT_USER_DATA   4   // "user data"
 | 
			
		||||
#define CPT_COUNT       5   // Number of entries
 | 
			
		||||
#define CPT_COUNT       4   // Number of entries
 | 
			
		||||
 | 
			
		||||
// values for cp_flags
 | 
			
		||||
typedef enum {
 | 
			
		||||
 
 | 
			
		||||
@@ -1429,6 +1429,23 @@ dictitem_T *tv_dict_find(const dict_T *const d, const char *const key,
 | 
			
		||||
  return TV_DICT_HI2DI(hi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a typval item from a dictionary and copy it into "rettv".
 | 
			
		||||
///
 | 
			
		||||
/// @param[in]  d  Dictionary to check.
 | 
			
		||||
/// @param[in]  key  Dictionary key.
 | 
			
		||||
/// @param[in]  rettv  Return value.
 | 
			
		||||
/// @return OK in case of success or FAIL if nothing was found.
 | 
			
		||||
int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
 | 
			
		||||
{
 | 
			
		||||
  dictitem_T *const di = tv_dict_find(d, key, -1);
 | 
			
		||||
  if (di == NULL) {
 | 
			
		||||
    return FAIL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  tv_copy(&di->di_tv, rettv);
 | 
			
		||||
  return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get a number item from a dictionary
 | 
			
		||||
///
 | 
			
		||||
/// Returns 0 if the entry does not exist.
 | 
			
		||||
@@ -1588,6 +1605,26 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
 | 
			
		||||
  return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Add a typval entry to dictionary.
 | 
			
		||||
///
 | 
			
		||||
/// @param[out]  d  Dictionary to add entry to.
 | 
			
		||||
/// @param[in]  key  Key to add.
 | 
			
		||||
/// @param[in]  key_len  Key length.
 | 
			
		||||
///
 | 
			
		||||
/// @return FAIL if out of memory or key already exists.
 | 
			
		||||
int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len,
 | 
			
		||||
                   typval_T *tv)
 | 
			
		||||
{
 | 
			
		||||
  dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
 | 
			
		||||
 | 
			
		||||
  tv_copy(tv, &item->di_tv);
 | 
			
		||||
  if (tv_dict_add(d, item) == FAIL) {
 | 
			
		||||
      tv_dict_item_free(item);
 | 
			
		||||
      return FAIL;
 | 
			
		||||
  }
 | 
			
		||||
  return OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Add a dictionary entry to dictionary
 | 
			
		||||
///
 | 
			
		||||
/// @param[out]  d  Dictionary to add entry to.
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@ function! s:CompleteDone_CompleteFuncDict( findstart, base )
 | 
			
		||||
              \ 'menu': 'extra text',
 | 
			
		||||
              \ 'info': 'words are cool',
 | 
			
		||||
              \ 'kind': 'W',
 | 
			
		||||
              \ 'user_data': 'test'
 | 
			
		||||
              \ 'user_data': ['one', 'two']
 | 
			
		||||
            \ }
 | 
			
		||||
          \ ]
 | 
			
		||||
        \ }
 | 
			
		||||
@@ -136,7 +136,7 @@ func s:CompleteDone_CheckCompletedItemDict(pre)
 | 
			
		||||
  call assert_equal( 'extra text',     v:completed_item[ 'menu' ] )
 | 
			
		||||
  call assert_equal( 'words are cool', v:completed_item[ 'info' ] )
 | 
			
		||||
  call assert_equal( 'W',              v:completed_item[ 'kind' ] )
 | 
			
		||||
  call assert_equal( 'test',           v:completed_item[ 'user_data' ] )
 | 
			
		||||
  call assert_equal( ['one', 'two'],   v:completed_item[ 'user_data' ] )
 | 
			
		||||
 | 
			
		||||
  if a:pre
 | 
			
		||||
    call assert_equal('function', complete_info().mode)
 | 
			
		||||
@@ -170,7 +170,7 @@ func Test_CompleteDoneDict()
 | 
			
		||||
  execute "normal a\<C-X>\<C-U>\<C-Y>"
 | 
			
		||||
  set completefunc&
 | 
			
		||||
 | 
			
		||||
  call assert_equal('test', v:completed_item[ 'user_data' ])
 | 
			
		||||
  call assert_equal(['one', 'two'], v:completed_item[ 'user_data' ])
 | 
			
		||||
  call assert_true(s:called_completedone)
 | 
			
		||||
 | 
			
		||||
  let s:called_completedone = 0
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user