To: vim_dev@googlegroups.com Subject: Patch 8.2.0084 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0084 Problem: Complete item "user_data" can only be a string. Solution: Accept any type of variable. (closes #5412) Files: src/testdir/test_ins_complete.vim, src/insexpand.c, src/dict.c, src/proto/dict.pro, src/eval.c, runtime/doc/insert.txt *** ../vim-8.2.0083/src/testdir/test_ins_complete.vim 2019-12-15 14:54:17.609139105 +0100 --- src/testdir/test_ins_complete.vim 2020-01-04 14:31:05.710982360 +0100 *************** *** 158,174 **** endif return { ! \ 'words': [ ! \ { ! \ 'word': 'aword', ! \ 'abbr': 'wrd', ! \ 'menu': 'extra text', ! \ 'info': 'words are cool', ! \ 'kind': 'W', ! \ 'user_data': 'test' ! \ } ! \ ] ! \ } endfunc func s:CompleteDone_CheckCompletedItemNone() --- 158,174 ---- endif return { ! \ 'words': [ ! \ { ! \ 'word': 'aword', ! \ 'abbr': 'wrd', ! \ 'menu': 'extra text', ! \ 'info': 'words are cool', ! \ 'kind': 'W', ! \ 'user_data': 'test' ! \ } ! \ ] ! \ } endfunc func s:CompleteDone_CheckCompletedItemNone() *************** *** 222,237 **** endif return { ! \ 'words': [ ! \ { ! \ 'word': 'aword', ! \ 'abbr': 'wrd', ! \ 'menu': 'extra text', ! \ 'info': 'words are cool', ! \ 'kind': 'W' ! \ } ! \ ] ! \ } endfunc func s:CompleteDone_CheckCompletedItemDictNoUserData() --- 222,238 ---- endif return { ! \ 'words': [ ! \ { ! \ 'word': 'aword', ! \ 'abbr': 'wrd', ! \ 'menu': 'extra text', ! \ 'info': 'words are cool', ! \ 'kind': 'W', ! \ 'user_data': ['one', 'two'], ! \ } ! \ ] ! \ } endfunc func s:CompleteDone_CheckCompletedItemDictNoUserData() *************** *** 240,246 **** 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( '', v:completed_item[ 'user_data' ] ) let s:called_completedone = 1 endfunc --- 241,247 ---- 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( ['one', 'two'], v:completed_item[ 'user_data' ] ) let s:called_completedone = 1 endfunc *************** *** 252,258 **** execute "normal a\\\" set completefunc& ! call assert_equal('', v:completed_item[ 'user_data' ]) call assert_true(s:called_completedone) let s:called_completedone = 0 --- 253,259 ---- execute "normal a\\\" set completefunc& ! call assert_equal(['one', 'two'], v:completed_item[ 'user_data' ]) call assert_true(s:called_completedone) let s:called_completedone = 0 *** ../vim-8.2.0083/src/insexpand.c 2019-12-21 18:47:05.128754192 +0100 --- src/insexpand.c 2020-01-04 14:25:01.127855687 +0100 *************** *** 91,98 **** #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 /* * Structure used to store one match for insert completion. --- 91,97 ---- #define CPT_MENU 1 // "menu" #define CPT_KIND 2 // "kind" #define CPT_INFO 3 // "info" ! #define CPT_COUNT 4 // Number of entries /* * Structure used to store one match for insert completion. *************** *** 104,109 **** --- 103,109 ---- 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 *************** *** 187,193 **** static int compl_opt_refresh_always = FALSE; static int compl_opt_suppress_empty = FALSE; ! static int ins_compl_add(char_u *str, int len, char_u *fname, char_u **cptext, int cdir, int flags, int adup); static void ins_compl_longest_match(compl_T *match); static void ins_compl_del_pum(void); static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir); --- 187,193 ---- static int compl_opt_refresh_always = FALSE; static int compl_opt_suppress_empty = FALSE; ! static int ins_compl_add(char_u *str, int len, char_u *fname, char_u **cptext, typval_T *user_data, int cdir, int flags, int adup); static void ins_compl_longest_match(compl_T *match); static void ins_compl_del_pum(void); static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir); *************** *** 560,566 **** if (icase) flags |= CP_ICASE; ! return ins_compl_add(str, len, fname, NULL, dir, flags, FALSE); } /* --- 560,566 ---- if (icase) flags |= CP_ICASE; ! return ins_compl_add(str, len, fname, NULL, NULL, dir, flags, FALSE); } /* *************** *** 574,583 **** char_u *str, int len, char_u *fname, ! char_u **cptext, // extra text for popup menu or NULL int cdir, int flags_arg, ! int adup) // accept duplicate match { compl_T *match; int dir = (cdir == 0 ? compl_direction : cdir); --- 574,584 ---- char_u *str, int len, char_u *fname, ! char_u **cptext, // extra text for popup menu or NULL ! typval_T *user_data, // "user_data" entry or NULL int cdir, int flags_arg, ! int adup) // accept duplicate match { compl_T *match; int dir = (cdir == 0 ? compl_direction : cdir); *************** *** 646,651 **** --- 647,654 ---- if (cptext[i] != NULL && *cptext[i] != NUL) match->cp_text[i] = vim_strsave(cptext[i]); } + if (user_data != NULL) + match->cp_user_data = *user_data; // Link the new match structure in the list of matches. if (compl_first_match == NULL) *************** *** 783,789 **** int dir = compl_direction; for (i = 0; i < num_matches && add_r != FAIL; i++) ! if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, dir, icase ? CP_ICASE : 0, FALSE)) == OK) // if dir was BACKWARD then honor it just once dir = FORWARD; --- 786,792 ---- int dir = compl_direction; for (i = 0; i < num_matches && add_r != FAIL; i++) ! if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, NULL, dir, icase ? CP_ICASE : 0, FALSE)) == OK) // if dir was BACKWARD then honor it just once dir = FORWARD; *************** *** 952,958 **** dict_add_string(dict, "menu", match->cp_text[CPT_MENU]); dict_add_string(dict, "kind", match->cp_text[CPT_KIND]); dict_add_string(dict, "info", match->cp_text[CPT_INFO]); ! dict_add_string(dict, "user_data", match->cp_text[CPT_USER_DATA]); } return dict; } --- 955,964 ---- dict_add_string(dict, "menu", match->cp_text[CPT_MENU]); dict_add_string(dict, "kind", match->cp_text[CPT_KIND]); dict_add_string(dict, "info", match->cp_text[CPT_INFO]); ! if (match->cp_user_data.v_type == VAR_UNKNOWN) ! dict_add_string(dict, "user_data", (char_u *)""); ! else ! dict_add_tv(dict, "user_data", &match->cp_user_data); } return dict; } *************** *** 1453,1458 **** --- 1459,1465 ---- vim_free(match->cp_fname); for (i = 0; i < CPT_COUNT; ++i) vim_free(match->cp_text[i]); + clear_tv(&match->cp_user_data); vim_free(match); } while (compl_curr_match != NULL && compl_curr_match != compl_first_match); compl_first_match = compl_curr_match = NULL; *************** *** 2264,2270 **** --- 2271,2279 ---- int empty = FALSE; int flags = 0; char_u *(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 = dict_get_string(tv->vval.v_dict, (char_u *)"word", FALSE); *************** *** 2276,2283 **** (char_u *)"kind", FALSE); cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict, (char_u *)"info", FALSE); ! cptext[CPT_USER_DATA] = dict_get_string(tv->vval.v_dict, ! (char_u *)"user_data", FALSE); if (dict_get_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL && dict_get_number(tv->vval.v_dict, (char_u *)"icase")) flags |= CP_ICASE; --- 2285,2291 ---- (char_u *)"kind", FALSE); cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict, (char_u *)"info", FALSE); ! dict_get_tv(tv->vval.v_dict, (char_u *)"user_data", &user_data); if (dict_get_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL && dict_get_number(tv->vval.v_dict, (char_u *)"icase")) flags |= CP_ICASE; *************** *** 2296,2302 **** } if (word == NULL || (!empty && *word == NUL)) return FAIL; ! return ins_compl_add(word, -1, NULL, cptext, dir, flags, dup); } /* --- 2304,2310 ---- } if (word == NULL || (!empty && *word == NUL)) return FAIL; ! return ins_compl_add(word, -1, NULL, cptext, &user_data, dir, flags, dup); } /* *************** *** 2373,2379 **** if (p_ic) flags |= CP_ICASE; if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, ! -1, NULL, NULL, 0, flags, FALSE) != OK) return; ctrl_x_mode = CTRL_X_EVAL; --- 2381,2387 ---- if (p_ic) flags |= CP_ICASE; if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, ! -1, NULL, NULL, NULL, 0, flags, FALSE) != OK) return; ctrl_x_mode = CTRL_X_EVAL; *************** *** 2541,2548 **** dict_add_string(di, "menu", match->cp_text[CPT_MENU]); dict_add_string(di, "kind", match->cp_text[CPT_KIND]); dict_add_string(di, "info", match->cp_text[CPT_INFO]); ! dict_add_string(di, "user_data", ! match->cp_text[CPT_USER_DATA]); } match = match->cp_next; } --- 2549,2559 ---- dict_add_string(di, "menu", match->cp_text[CPT_MENU]); dict_add_string(di, "kind", match->cp_text[CPT_KIND]); dict_add_string(di, "info", match->cp_text[CPT_INFO]); ! if (match->cp_user_data.v_type == VAR_UNKNOWN) ! // Add an empty string for backwards compatibility ! dict_add_string(di, "user_data", (char_u *)""); ! else ! dict_add_tv(di, "user_data", &match->cp_user_data); } match = match->cp_next; } *************** *** 3893,3899 **** if (p_ic) flags |= CP_ICASE; if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, ! -1, NULL, NULL, 0, flags, FALSE) != OK) { VIM_CLEAR(compl_pattern); VIM_CLEAR(compl_orig_text); --- 3904,3910 ---- if (p_ic) flags |= CP_ICASE; if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, ! -1, NULL, NULL, NULL, 0, flags, FALSE) != OK) { VIM_CLEAR(compl_pattern); VIM_CLEAR(compl_orig_text); *** ../vim-8.2.0083/src/dict.c 2019-12-01 20:48:29.000000000 +0100 --- src/dict.c 2020-01-04 14:13:18.474544574 +0100 *************** *** 448,453 **** --- 448,474 ---- } /* + * Add a typval_T entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ + int + dict_add_tv(dict_T *d, char *key, typval_T *tv) + { + dictitem_T *item; + + item = dictitem_alloc((char_u *)key); + if (item == NULL) + return FAIL; + copy_tv(tv, &item->di_tv); + if (dict_add(d, item) == FAIL) + { + dictitem_free(item); + return FAIL; + } + return OK; + } + + /* * Add a callback to dictionary "d". * Returns FAIL when out of memory and when key already exists. */ *************** *** 590,595 **** --- 611,633 ---- } /* + * Get a typval_T item from a dictionary and copy it into "rettv". + * Returns FAIL if the entry doesn't exist or out of memory. + */ + int + dict_get_tv(dict_T *d, char_u *key, typval_T *rettv) + { + dictitem_T *di; + char_u *s; + + di = dict_find(d, key, -1); + if (di == NULL) + return FAIL; + copy_tv(&di->di_tv, rettv); + return OK; + } + + /* * Get a string item from a dictionary. * When "save" is TRUE allocate memory for it. * When FALSE a shared buffer is used, can only be used once! *************** *** 745,751 **** * Return OK or FAIL. Returns NOTDONE for {expr}. */ int ! dict_get_tv(char_u **arg, typval_T *rettv, int evaluate, int literal) { dict_T *d = NULL; typval_T tvkey; --- 783,789 ---- * Return OK or FAIL. Returns NOTDONE for {expr}. */ int ! eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) { dict_T *d = NULL; typval_T tvkey; *** ../vim-8.2.0083/src/proto/dict.pro 2019-12-12 12:55:17.000000000 +0100 --- src/proto/dict.pro 2020-01-04 14:18:50.185166239 +0100 *************** *** 18,35 **** int dict_add_string(dict_T *d, char *key, char_u *str); int dict_add_string_len(dict_T *d, char *key, char_u *str, int len); int dict_add_list(dict_T *d, char *key, list_T *list); int dict_add_callback(dict_T *d, char *key, callback_T *cb); void dict_iterate_start(typval_T *var, dict_iterator_T *iter); char_u *dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result); int dict_add_dict(dict_T *d, char *key, dict_T *dict); long dict_len(dict_T *d); dictitem_T *dict_find(dict_T *d, char_u *key, int len); char_u *dict_get_string(dict_T *d, char_u *key, int save); varnumber_T dict_get_number(dict_T *d, char_u *key); varnumber_T dict_get_number_def(dict_T *d, char_u *key, int def); varnumber_T dict_get_number_check(dict_T *d, char_u *key); char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); ! int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate, int literal); void dict_extend(dict_T *d1, dict_T *d2, char_u *action); dictitem_T *dict_lookup(hashitem_T *hi); int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); --- 18,37 ---- int dict_add_string(dict_T *d, char *key, char_u *str); int dict_add_string_len(dict_T *d, char *key, char_u *str, int len); int dict_add_list(dict_T *d, char *key, list_T *list); + int dict_add_tv(dict_T *d, char *key, typval_T *tv); int dict_add_callback(dict_T *d, char *key, callback_T *cb); void dict_iterate_start(typval_T *var, dict_iterator_T *iter); char_u *dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result); int dict_add_dict(dict_T *d, char *key, dict_T *dict); long dict_len(dict_T *d); dictitem_T *dict_find(dict_T *d, char_u *key, int len); + int dict_get_tv(dict_T *d, char_u *key, typval_T *rettv); char_u *dict_get_string(dict_T *d, char_u *key, int save); varnumber_T dict_get_number(dict_T *d, char_u *key); varnumber_T dict_get_number_def(dict_T *d, char_u *key, int def); varnumber_T dict_get_number_check(dict_T *d, char_u *key); char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); ! int eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal); void dict_extend(dict_T *d1, dict_T *d2, char_u *action); dictitem_T *dict_lookup(hashitem_T *hi); int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive); *** ../vim-8.2.0083/src/eval.c 2019-12-31 22:36:14.561918852 +0100 --- src/eval.c 2020-01-04 14:09:52.211397473 +0100 *************** *** 2656,2662 **** case '#': if ((*arg)[1] == '{') { ++*arg; ! ret = dict_get_tv(arg, rettv, evaluate, TRUE); } else ret = NOTDONE; --- 2656,2662 ---- case '#': if ((*arg)[1] == '{') { ++*arg; ! ret = eval_dict(arg, rettv, evaluate, TRUE); } else ret = NOTDONE; *************** *** 2668,2674 **** */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) ! ret = dict_get_tv(arg, rettv, evaluate, FALSE); break; /* --- 2668,2674 ---- */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) ! ret = eval_dict(arg, rettv, evaluate, FALSE); break; /* *** ../vim-8.2.0083/runtime/doc/insert.txt 2019-12-17 21:27:14.686319918 +0100 --- runtime/doc/insert.txt 2020-01-04 14:25:55.927750843 +0100 *************** *** 1108,1114 **** 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| 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 --- 1108,1115 ---- 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|; 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 *************** *** 2008,2017 **** changed, the detected format is only used while reading the file. A similar thing happens with 'fileencodings'. ! On non-MS-DOS and Win32 systems the message "[dos format]" is shown if a file ! is read in DOS format, to remind you that something unusual is done. On ! Macintosh and Win32 the message "[unix format]" is shown if a file is read in ! Unix format. On non-Macintosh systems, the message "[Mac format]" is shown if a file is read in Mac format. --- 2009,2018 ---- changed, the detected format is only used while reading the file. A similar thing happens with 'fileencodings'. ! The message "[dos format]" is shown if a file is read in DOS format, to remind ! you that something unusual is done. ! On Macintosh and Win32 the message "[unix format]" is shown if a file is read ! in Unix format. On non-Macintosh systems, the message "[Mac format]" is shown if a file is read in Mac format. *** ../vim-8.2.0083/src/version.c 2020-01-03 21:25:55.325995770 +0100 --- src/version.c 2020-01-04 14:01:58.017331255 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 84, /**/ -- MONK: ... and the Lord spake, saying, "First shalt thou take out the Holy Pin, then shalt thou count to three, no more, no less. Three shalt be the number thou shalt count, and the number of the counting shalt be three. Four shalt thou not count, neither count thou two, excepting that thou then proceed to three. Five is right out. Once the number three, being the third number, be reached, then lobbest thou thy Holy Hand Grenade of Antioch towards thou foe, who being naughty in my sight, shall snuff it. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///