diff options
Diffstat (limited to 'data/vim/patches/8.1.1228')
-rw-r--r-- | data/vim/patches/8.1.1228 | 1467 |
1 files changed, 1467 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.1228 b/data/vim/patches/8.1.1228 new file mode 100644 index 000000000..b584c9e6b --- /dev/null +++ b/data/vim/patches/8.1.1228 @@ -0,0 +1,1467 @@ +To: vim_dev@googlegroups.com +Subject: Patch 8.1.1228 +Fcc: outbox +From: Bram Moolenaar <Bram@moolenaar.net> +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 8.1.1228 +Problem: Not possible to process tags with a function. +Solution: Add tagfunc() (Christian Brabandt, Andy Massimino, closes #4010) +Files: runtime/doc/options.txt, runtime/doc/tagsrch.txt, + runtime/optwin.vim, src/buffer.c, src/dict.c, src/ex_cmds.c, + src/globals.h, src/insexpand.c, src/normal.c, src/option.c, + src/option.h, src/proto/dict.pro, src/structs.h, src/tag.c, + src/testdir/Make_all.mak, src/testdir/test_alot.vim, + src/testdir/test_tagfunc.vim, src/vim.h, src/window.c + + +*** ../vim-8.1.1227/runtime/doc/options.txt 2019-04-28 16:00:05.367613425 +0200 +--- runtime/doc/options.txt 2019-04-28 16:53:38.066933372 +0200 +*************** +*** 7458,7463 **** +--- 7458,7473 ---- + NOTE: This option is set to the Vi default value when 'compatible' is + set and to the Vim default value when 'compatible' is reset. + ++ *'tagfunc'* *'tfu'* ++ 'tagfunc' 'tfu' string (default: empty) ++ local to buffer ++ {not available when compiled without the |+eval| ++ feature} ++ This option specifies a function to be used to perform tag searches. ++ The function gets the tag pattern and should return a List of matching ++ tags. See |tag-function| for an explanation of how to write the ++ function and an example. ++ + *'taglength'* *'tl'* + 'taglength' 'tl' number (default 0) + global +*** ../vim-8.1.1227/runtime/doc/tagsrch.txt 2019-03-30 21:19:16.426170240 +0100 +--- runtime/doc/tagsrch.txt 2019-04-28 17:43:27.976705157 +0200 +*************** +*** 14,19 **** +--- 14,20 ---- + 4. Tags details |tag-details| + 5. Tags file format |tags-file-format| + 6. Include file searches |include-search| ++ 7. Using 'tagfunc' |tag-function| + + ============================================================================== + 1. Jump to a tag *tag-commands* +*************** +*** 179,186 **** + 1 1 main 1 harddisk2:text/vim/test + 2 1 FuncB 59 harddisk2:text/vim/src/main.c + +! The gettagstack() function returns the tag stack of a specified window. The +! settagstack() function modifies the tag stack of a window. + + *E73* + When you try to use the tag stack while it doesn't contain anything you will +--- 180,187 ---- + 1 1 main 1 harddisk2:text/vim/test + 2 1 FuncB 59 harddisk2:text/vim/src/main.c + +! The |gettagstack()| function returns the tag stack of a specified window. The +! |settagstack()| function modifies the tag stack of a window. + + *E73* + When you try to use the tag stack while it doesn't contain anything you will +*************** +*** 570,576 **** + the bar) and ;" is used to have Vi ignore the rest of the + line. Example: + APP file.c call cursor(3, 4)|;" v +! + {field} .. A list of optional fields. Each field has the form: + + <Tab>{fieldname}:{value} +--- 571,577 ---- + the bar) and ;" is used to have Vi ignore the rest of the + line. Example: + APP file.c call cursor(3, 4)|;" v +! + {field} .. A list of optional fields. Each field has the form: + + <Tab>{fieldname}:{value} +*************** +*** 591,596 **** +--- 592,598 ---- + The only other field currently recognized by Vim is "file:" + (with an empty value). It is used for a static tag. + ++ + The first lines in the tags file can contain lines that start with + !_TAG_ + These are sorted to the first lines, only rare tags that start with "!" can +*************** +*** 870,873 **** + < For a ":djump", ":dsplit", ":dlist" and ":dsearch" command the pattern + is used as a literal string, not as a search pattern. + +! vim:tw=78:ts=8:ft=help:norl: +--- 872,941 ---- + < For a ":djump", ":dsplit", ":dlist" and ":dsearch" command the pattern + is used as a literal string, not as a search pattern. + +! ============================================================================== +! 7. Using 'tagfunc' *tag-function* +! +! It is possible to provide Vim with a function which will generate a list of +! tags used for commands like |:tag|, |:tselect| and Normal mode tag commands +! like |CTRL-]|. +! +! The function used for generating the taglist is specified by setting the +! 'tagfunc' option. The function will be called with three arguments: +! a:pattern The tag identifier used during the tag search. +! a:flags List of flags to control the function behavior. +! a:info Dict containing the following entries: +! buf_ffname Full filename which can be used for priority. +! user_data Custom data String, if stored in the tag +! stack previously by tagfunc. +! +! Currently two flags may be passed to the tag function: +! 'c' The function was invoked by a normal command being processed +! (mnemonic: the tag function may use the context around the +! cursor to perform a better job of generating the tag list.) +! 'i' In Insert mode, the user was completing a tag (with +! |i_CTRL-X_CTRL-]|). +! +! Note that when 'tagfunc' is set, the priority of the tags described in +! |tag-priority| does not apply. Instead, the priority is exactly as the +! ordering of the elements in the list returned by the function. +! *E987* +! The function should return a List of Dict entries. Each Dict must at least +! include the following entries and each value must be a string: +! name Name of the tag. +! filename Name of the file where the tag is defined. It is +! either relative to the current directory or a full path. +! cmd Ex command used to locate the tag in the file. This +! can be either an Ex search pattern or a line number. +! Note that the format is similar to that of |taglist()|, which makes it possible +! to use its output to generate the result. +! The following fields are optional: +! kind Type of the tag. +! user_data String of custom data stored in the tag stack which +! can be used to disambiguate tags between operations. +! +! If the function returns |v:null| instead of a List, a standard tag lookup will +! be performed instead. +! +! It is not allowed to change the tagstack from inside 'tagfunc'. *E986* +! +! The following is a hypothetical example of a function used for 'tagfunc'. It +! uses the output of |taglist()| to generate the result: a list of tags in the +! inverse order of file names. +! > +! function! TagFunc(pattern, flags, info) +! function! CompareFilenames(item1, item2) +! let f1 = a:item1['filename'] +! let f2 = a:item2['filename'] +! return f1 >=# f2 ? +! \ -1 : f1 <=# f2 ? 1 : 0 +! endfunction +! +! let result = taglist(a:pattern) +! call sort(result, "CompareFilenames") +! +! return result +! endfunc +! set tagfunc=TagFunc +! < +! +! vim:tw=78:ts=8:noet:ft=help:norl: +*** ../vim-8.1.1227/runtime/optwin.vim 2019-02-17 17:53:46.681219289 +0100 +--- runtime/optwin.vim 2019-04-28 16:47:48.252732139 +0200 +*************** +*** 300,305 **** +--- 300,310 ---- + call <SID>BinOptionG("tgst", &tgst) + call append("$", "showfulltag\twhen completing tags in Insert mode show more info") + call <SID>BinOptionG("sft", &sft) ++ if has("eval") ++ call append("$", "tagfunc\ta function to be used to perform tag searches") ++ call append("$", "\t(local to buffer)") ++ call <SID>OptionL("tfu") ++ endif + if has("cscope") + call append("$", "cscopeprg\tcommand for executing cscope") + call <SID>OptionG("csprg", &csprg) +*** ../vim-8.1.1227/src/buffer.c 2019-04-27 13:03:20.000715982 +0200 +--- src/buffer.c 2019-04-28 16:47:48.252732139 +0200 +*************** +*** 2219,2224 **** +--- 2219,2227 ---- + clear_string_option(&buf->b_p_path); + clear_string_option(&buf->b_p_tags); + clear_string_option(&buf->b_p_tc); ++ #ifdef FEAT_EVAL ++ clear_string_option(&buf->b_p_tfu); ++ #endif + #ifdef FEAT_INS_EXPAND + clear_string_option(&buf->b_p_dict); + clear_string_option(&buf->b_p_tsr); +*** ../vim-8.1.1227/src/dict.c 2019-04-08 18:15:36.464223229 +0200 +--- src/dict.c 2019-04-28 17:48:48.959179176 +0200 +*************** +*** 449,454 **** +--- 449,503 ---- + } + + /* ++ * Initializes "iter" for iterating over dictionary items with ++ * dict_iterate_next(). ++ * If "var" is not a Dict or an empty Dict then there will be nothing to ++ * iterate over, no error is given. ++ * NOTE: The dictionary must not change until iterating is finished! ++ */ ++ void ++ dict_iterate_start(typval_T *var, dict_iterator_T *iter) ++ { ++ if (var->v_type != VAR_DICT || var->vval.v_dict == NULL) ++ iter->dit_todo = 0; ++ else ++ { ++ dict_T *d = var->vval.v_dict; ++ ++ iter->dit_todo = d->dv_hashtab.ht_used; ++ iter->dit_hi = d->dv_hashtab.ht_array; ++ } ++ } ++ ++ /* ++ * Iterate over the items referred to by "iter". It should be initialized with ++ * dict_iterate_start(). ++ * Returns a pointer to the key. ++ * "*tv_result" is set to point to the value for that key. ++ * If there are no more items, NULL is returned. ++ */ ++ char_u * ++ dict_iterate_next(dict_iterator_T *iter, typval_T **tv_result) ++ { ++ dictitem_T *di; ++ char_u *result; ++ ++ if (iter->dit_todo == 0) ++ return NULL; ++ ++ while (HASHITEM_EMPTY(iter->dit_hi)) ++ ++iter->dit_hi; ++ ++ di = HI2DI(iter->dit_hi); ++ result = di->di_key; ++ *tv_result = &di->di_tv; ++ ++ --iter->dit_todo; ++ ++iter->dit_hi; ++ return result; ++ } ++ ++ /* + * Add a dict entry to dictionary "d". + * Returns FAIL when out of memory and when key already exists. + */ +*** ../vim-8.1.1227/src/ex_cmds.c 2019-03-30 18:46:57.344077426 +0100 +--- src/ex_cmds.c 2019-04-28 17:16:35.452393443 +0200 +*************** +*** 6813,6819 **** + + *matches = (char_u **)""; + *num_matches = 0; +! flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE; + if (keep_lang) + flags |= TAG_KEEP_LANG; + if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK +--- 6813,6819 ---- + + *matches = (char_u **)""; + *num_matches = 0; +! flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE | TAG_NO_TAGFUNC; + if (keep_lang) + flags |= TAG_KEEP_LANG; + if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK +*** ../vim-8.1.1227/src/globals.h 2019-04-20 23:38:02.189504258 +0200 +--- src/globals.h 2019-04-28 17:21:49.430854857 +0200 +*************** +*** 1067,1075 **** + EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */ + EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */ + #ifdef FEAT_QUICKFIX +! EXTERN int g_do_tagpreview INIT(= 0); /* for tag preview commands: +! height of preview window */ + #endif + EXTERN int replace_offset INIT(= 0); /* offset for replace_push() */ + + EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|"); +--- 1067,1079 ---- + EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */ + EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */ + #ifdef FEAT_QUICKFIX +! EXTERN int g_do_tagpreview INIT(= 0); // for tag preview commands: +! // height of preview window + #endif ++ EXTERN int g_tag_at_cursor INIT(= FALSE); // whether the tag command comes ++ // from the command line (0) or was ++ // invoked as a normal command (1) ++ + EXTERN int replace_offset INIT(= 0); /* offset for replace_push() */ + + EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|"); +*** ../vim-8.1.1227/src/insexpand.c 2019-04-08 18:15:36.464223229 +0200 +--- src/insexpand.c 2019-04-28 17:21:29.878951043 +0200 +*************** +*** 2654,2664 **** +--- 2654,2666 ---- + + // Find up to TAG_MANY matches. Avoids that an enormous number + // of matches is found when compl_pattern is empty ++ g_tag_at_cursor = TRUE; + if (find_tags(compl_pattern, &num_matches, &matches, + TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP + | (ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0), + TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) + ins_compl_add_matches(num_matches, matches, p_ic); ++ g_tag_at_cursor = FALSE; + p_ic = save_p_ic; + break; + +*** ../vim-8.1.1227/src/normal.c 2019-03-30 18:46:57.356077354 +0100 +--- src/normal.c 2019-04-28 17:21:37.030915863 +0200 +*************** +*** 5724,5730 **** +--- 5724,5734 ---- + (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0); + } + else ++ { ++ g_tag_at_cursor = TRUE; + do_cmdline_cmd(buf); ++ g_tag_at_cursor = FALSE; ++ } + + vim_free(buf); + } +*** ../vim-8.1.1227/src/option.c 2019-04-27 22:06:33.348200718 +0200 +--- src/option.c 2019-04-28 16:47:48.256732118 +0200 +*************** +*** 167,172 **** +--- 167,175 ---- + #endif + #define PV_SW OPT_BUF(BV_SW) + #define PV_SWF OPT_BUF(BV_SWF) ++ #ifdef FEAT_EVAL ++ # define PV_TFU OPT_BUF(BV_TFU) ++ #endif + #define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS)) + #define PV_TC OPT_BOTH(OPT_BUF(BV_TC)) + #define PV_TS OPT_BUF(BV_TS) +*************** +*** 303,308 **** +--- 306,314 ---- + static char_u *p_cfu; + static char_u *p_ofu; + #endif ++ #ifdef FEAT_EVAL ++ static char_u *p_tfu; ++ #endif + static int p_eol; + static int p_fixeol; + static int p_et; +*************** +*** 2642,2647 **** +--- 2648,2662 ---- + {"tagcase", "tc", P_STRING|P_VIM, + (char_u *)&p_tc, PV_TC, + {(char_u *)"followic", (char_u *)"followic"} SCTX_INIT}, ++ {"tagfunc", "tfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE, ++ #ifdef FEAT_EVAL ++ (char_u *)&p_tfu, PV_TFU, ++ {(char_u *)"", (char_u *)0L} ++ #else ++ (char_u *)NULL, PV_NONE, ++ {(char_u *)0L, (char_u *)0L} ++ #endif ++ SCTX_INIT}, + {"taglength", "tl", P_NUM|P_VI_DEF, + (char_u *)&p_tl, PV_NONE, + {(char_u *)0L, (char_u *)0L} SCTX_INIT}, +*************** +*** 5689,5694 **** +--- 5704,5712 ---- + check_string_option(&buf->b_p_cfu); + check_string_option(&buf->b_p_ofu); + #endif ++ #ifdef FEAT_EVAL ++ check_string_option(&buf->b_p_tfu); ++ #endif + #ifdef FEAT_KEYMAP + check_string_option(&buf->b_p_keymap); + #endif +*************** +*** 10944,10949 **** +--- 10962,10970 ---- + case PV_CFU: return (char_u *)&(curbuf->b_p_cfu); + case PV_OFU: return (char_u *)&(curbuf->b_p_ofu); + #endif ++ #ifdef FEAT_EVAL ++ case PV_TFU: return (char_u *)&(curbuf->b_p_tfu); ++ #endif + case PV_EOL: return (char_u *)&(curbuf->b_p_eol); + case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol); + case PV_ET: return (char_u *)&(curbuf->b_p_et); +*************** +*** 11332,11337 **** +--- 11353,11361 ---- + buf->b_p_cfu = vim_strsave(p_cfu); + buf->b_p_ofu = vim_strsave(p_ofu); + #endif ++ #ifdef FEAT_EVAL ++ buf->b_p_tfu = vim_strsave(p_tfu); ++ #endif + buf->b_p_sts = p_sts; + buf->b_p_sts_nopaste = p_sts_nopaste; + #ifdef FEAT_VARTABS +*** ../vim-8.1.1227/src/option.h 2019-03-02 10:13:36.796974835 +0100 +--- src/option.h 2019-04-28 16:47:48.256732118 +0200 +*************** +*** 1068,1073 **** +--- 1068,1076 ---- + #endif + , BV_SW + , BV_SWF ++ #ifdef FEAT_EVAL ++ , BV_TFU ++ #endif + , BV_TAGS + , BV_TC + , BV_TS +*** ../vim-8.1.1227/src/proto/dict.pro 2019-04-08 18:15:36.472223190 +0200 +--- src/proto/dict.pro 2019-04-28 17:11:15.121943721 +0200 +*************** +*** 18,23 **** +--- 18,25 ---- + 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); ++ 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); +*** ../vim-8.1.1227/src/structs.h 2019-04-27 20:36:52.534303564 +0200 +--- src/structs.h 2019-04-28 17:31:05.364108835 +0200 +*************** +*** 147,156 **** + */ + typedef struct taggy + { +! char_u *tagname; /* tag name */ +! fmark_T fmark; /* cursor position BEFORE ":tag" */ +! int cur_match; /* match number */ +! int cur_fnum; /* buffer number used for cur_match */ + } taggy_T; + + /* +--- 147,157 ---- + */ + typedef struct taggy + { +! char_u *tagname; // tag name +! fmark_T fmark; // cursor position BEFORE ":tag" +! int cur_match; // match number +! int cur_fnum; // buffer number used for cur_match +! char_u *user_data; // used with tagfunc + } taggy_T; + + /* +*************** +*** 1885,1890 **** +--- 1886,1901 ---- + struct list_stack_S *prev; + } list_stack_T; + ++ /* ++ * Structure used for iterating over dictionary items. ++ * Initialize with dict_iterate_start(). ++ */ ++ typedef struct ++ { ++ long_u dit_todo; ++ hashitem_T *dit_hi; ++ } dict_iterator_T; ++ + /* values for b_syn_spell: what to do with toplevel text */ + #define SYNSPL_DEFAULT 0 /* spell check if @Spell not defined */ + #define SYNSPL_TOP 1 /* spell check toplevel text */ +*************** +*** 2245,2250 **** +--- 2256,2264 ---- + char_u *b_p_cfu; /* 'completefunc' */ + char_u *b_p_ofu; /* 'omnifunc' */ + #endif ++ #ifdef FEAT_EVAL ++ char_u *b_p_tfu; /* 'tagfunc' */ ++ #endif + int b_p_eol; /* 'endofline' */ + int b_p_fixeol; /* 'fixendofline' */ + int b_p_et; /* 'expandtab' */ +*** ../vim-8.1.1227/src/tag.c 2019-04-21 00:00:07.942354840 +0200 +--- src/tag.c 2019-04-28 17:44:56.956284972 +0200 +*************** +*** 18,37 **** + */ + typedef struct tag_pointers + { +! /* filled in by parse_tag_line(): */ +! char_u *tagname; /* start of tag name (skip "file:") */ +! char_u *tagname_end; /* char after tag name */ +! char_u *fname; /* first char of file name */ +! char_u *fname_end; /* char after file name */ +! char_u *command; /* first char of command */ +! /* filled in by parse_match(): */ +! char_u *command_end; /* first char after command */ +! char_u *tag_fname; /* file name of the tags file */ + #ifdef FEAT_EMACS_TAGS +! int is_etag; /* TRUE for emacs tag */ + #endif +! char_u *tagkind; /* "kind:" value */ +! char_u *tagkind_end; /* end of tagkind */ + } tagptrs_T; + + /* +--- 18,40 ---- + */ + typedef struct tag_pointers + { +! // filled in by parse_tag_line(): +! char_u *tagname; // start of tag name (skip "file:") +! char_u *tagname_end; // char after tag name +! char_u *fname; // first char of file name +! char_u *fname_end; // char after file name +! char_u *command; // first char of command +! // filled in by parse_match(): +! char_u *command_end; // first char after command +! char_u *tag_fname; // file name of the tags file. This is used +! // when 'tr' is set. + #ifdef FEAT_EMACS_TAGS +! int is_etag; // TRUE for emacs tag + #endif +! char_u *tagkind; // "kind:" value +! char_u *tagkind_end; // end of tagkind +! char_u *user_data; // user_data string +! char_u *user_data_end; // end of user_data + } tagptrs_T; + + /* +*************** +*** 78,86 **** +--- 81,94 ---- + #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL) + static int add_llist_tags(char_u *tag, int num_matches, char_u **matches); + #endif ++ static void tagstack_clear_entry(taggy_T *item); + + static char_u *bottommsg = (char_u *)N_("E555: at bottom of tag stack"); + static char_u *topmsg = (char_u *)N_("E556: at top of tag stack"); ++ #ifdef FEAT_EVAL ++ static char_u *recurmsg = (char_u *)N_("E986: cannot modify the tag stack within tagfunc"); ++ static char_u *tfu_inv_ret_msg = (char_u *)N_("E987: invalid return value from tagfunc"); ++ #endif + + static char_u *tagmatchname = NULL; /* name of last used tag */ + +*************** +*** 89,97 **** + * Tag for preview window is remembered separately, to avoid messing up the + * normal tagstack. + */ +! static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0}; + #endif + + /* + * Jump to tag; handling of tag commands and tag stack + * +--- 97,112 ---- + * Tag for preview window is remembered separately, to avoid messing up the + * normal tagstack. + */ +! static taggy_T ptag_entry = {NULL, {{0, 0, 0}, 0}, 0, 0, NULL}; +! #endif +! +! #ifdef FEAT_EVAL +! static int tfu_in_use = FALSE; // disallow recursive call of tagfunc + #endif + ++ // Used instead of NUL to separate tag fields in the growarrays. ++ #define TAG_SEP 0x02 ++ + /* + * Jump to tag; handling of tag commands and tag stack + * +*************** +*** 144,149 **** +--- 159,165 ---- + int skip_msg = FALSE; + char_u *buf_ffname = curbuf->b_ffname; /* name to use for + priority computation */ ++ int use_tfu = 1; + + /* remember the matches for the last used tag */ + static int num_matches = 0; +*************** +*** 151,156 **** +--- 167,180 ---- + static char_u **matches = NULL; + static int flags; + ++ #ifdef FEAT_EVAL ++ if (tfu_in_use) ++ { ++ emsg(_(recurmsg)); ++ return FALSE; ++ } ++ #endif ++ + #ifdef EXITFREE + if (type == DT_FREE) + { +*************** +*** 168,173 **** +--- 192,198 ---- + { + type = DT_TAG; + no_regexp = TRUE; ++ use_tfu = 0; + } + + prev_num_matches = num_matches; +*************** +*** 187,193 **** + #if defined(FEAT_QUICKFIX) + if (g_do_tagpreview != 0) + { +! vim_free(ptag_entry.tagname); + if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) + goto end_do_tag; + } +--- 212,218 ---- + #if defined(FEAT_QUICKFIX) + if (g_do_tagpreview != 0) + { +! tagstack_clear_entry(&ptag_entry); + if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) + goto end_do_tag; + } +*************** +*** 226,232 **** + } + else + { +! vim_free(ptag_entry.tagname); + if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) + goto end_do_tag; + } +--- 251,257 ---- + } + else + { +! tagstack_clear_entry(&ptag_entry); + if ((ptag_entry.tagname = vim_strsave(tag)) == NULL) + goto end_do_tag; + } +*************** +*** 239,251 **** + * stack entries above it. + */ + while (tagstackidx < tagstacklen) +! vim_free(tagstack[--tagstacklen].tagname); + + /* if the tagstack is full: remove oldest entry */ + if (++tagstacklen > TAGSTACKSIZE) + { + tagstacklen = TAGSTACKSIZE; +! vim_free(tagstack[0].tagname); + for (i = 1; i < tagstacklen; ++i) + tagstack[i - 1] = tagstack[i]; + --tagstackidx; +--- 264,276 ---- + * stack entries above it. + */ + while (tagstackidx < tagstacklen) +! tagstack_clear_entry(&tagstack[--tagstacklen]); + + /* if the tagstack is full: remove oldest entry */ + if (++tagstacklen > TAGSTACKSIZE) + { + tagstacklen = TAGSTACKSIZE; +! tagstack_clear_entry(&tagstack[0]); + for (i = 1; i < tagstacklen; ++i) + tagstack[i - 1] = tagstack[i]; + --tagstackidx; +*************** +*** 529,534 **** +--- 554,563 ---- + #endif + if (verbose) + flags |= TAG_VERBOSE; ++ ++ if (!use_tfu) ++ flags |= TAG_NO_TAGFUNC; ++ + if (find_tags(name, &new_num_matches, &new_matches, flags, + max_num_matches, buf_ffname) == OK + && new_num_matches < max_num_matches) +*************** +*** 647,654 **** +--- 676,695 ---- + } + if (use_tagstack) + { ++ tagptrs_T tagp; ++ + tagstack[tagstackidx].cur_match = cur_match; + tagstack[tagstackidx].cur_fnum = cur_fnum; ++ ++ // store user-provided data originating from tagfunc ++ if (use_tfu && parse_match(matches[cur_match], &tagp) == OK ++ && tagp.user_data) ++ { ++ VIM_CLEAR(tagstack[tagstackidx].user_data); ++ tagstack[tagstackidx].user_data = vim_strnsave( ++ tagp.user_data, tagp.user_data_end - tagp.user_data); ++ } ++ + ++tagstackidx; + } + #if defined(FEAT_QUICKFIX) +*************** +*** 1243,1248 **** +--- 1284,1520 ---- + pats->regmatch.regprog = NULL; + } + ++ #ifdef FEAT_EVAL ++ /* ++ * Call the user-defined function to generate a list of tags used by ++ * find_tags(). ++ * ++ * Return OK if at least 1 tag has been successfully found, ++ * NOTDONE if the function returns v:null, and FAIL otherwise. ++ */ ++ static int ++ find_tagfunc_tags( ++ char_u *pat, // pattern supplied to the user-defined function ++ garray_T *ga, // the tags will be placed here ++ int *match_count, // here the number of tags found will be placed ++ int flags, // flags from find_tags (TAG_*) ++ char_u *buf_ffname) // name of buffer for priority ++ { ++ pos_T save_pos; ++ list_T *taglist; ++ listitem_T *item; ++ int ntags = 0; ++ int result = FAIL; ++ typval_T args[4]; ++ typval_T rettv; ++ char_u flagString[3]; ++ dict_T *d; ++ taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx]; ++ ++ if (*curbuf->b_p_tfu == NUL) ++ return FAIL; ++ ++ args[0].v_type = VAR_STRING; ++ args[0].vval.v_string = pat; ++ args[1].v_type = VAR_STRING; ++ args[1].vval.v_string = flagString; ++ ++ // create 'info' dict argument ++ if ((d = dict_alloc_lock(VAR_FIXED)) == NULL) ++ return FAIL; ++ if (tag->user_data != NULL) ++ dict_add_string(d, "user_data", tag->user_data); ++ if (buf_ffname != NULL) ++ dict_add_string(d, "buf_ffname", buf_ffname); ++ ++ ++d->dv_refcount; ++ args[2].v_type = VAR_DICT; ++ args[2].vval.v_dict = d; ++ ++ args[3].v_type = VAR_UNKNOWN; ++ ++ vim_snprintf((char *)flagString, sizeof(flagString), ++ "%s%s", ++ g_tag_at_cursor ? "c": "", ++ flags & TAG_INS_COMP ? "i": ""); ++ ++ save_pos = curwin->w_cursor; ++ result = call_vim_function(curbuf->b_p_tfu, 3, args, &rettv); ++ curwin->w_cursor = save_pos; // restore the cursor position ++ --d->dv_refcount; ++ ++ if (result == FAIL) ++ return FAIL; ++ if (rettv.v_type == VAR_SPECIAL && rettv.vval.v_number == VVAL_NULL) ++ { ++ clear_tv(&rettv); ++ return NOTDONE; ++ } ++ if (rettv.v_type != VAR_LIST || !rettv.vval.v_list) ++ { ++ clear_tv(&rettv); ++ emsg(_(tfu_inv_ret_msg)); ++ return FAIL; ++ } ++ taglist = rettv.vval.v_list; ++ ++ for (item = taglist->lv_first; item != NULL; item = item->li_next) ++ { ++ char_u *mfp; ++ char_u *res_name, *res_fname, *res_cmd, *res_kind; ++ int len; ++ dict_iterator_T iter; ++ char_u *dict_key; ++ typval_T *tv; ++ int has_extra = 0; ++ int name_only = flags & TAG_NAMES; ++ ++ if (item->li_tv.v_type != VAR_DICT) ++ { ++ emsg(_(tfu_inv_ret_msg)); ++ break; ++ } ++ ++ #ifdef FEAT_EMACS_TAGS ++ len = 3; ++ #else ++ len = 2; ++ #endif ++ res_name = NULL; ++ res_fname = NULL; ++ res_cmd = NULL; ++ res_kind = NULL; ++ ++ dict_iterate_start(&item->li_tv, &iter); ++ while (NULL != (dict_key = dict_iterate_next(&iter, &tv))) ++ { ++ if (tv->v_type != VAR_STRING || tv->vval.v_string == NULL) ++ continue; ++ ++ len += STRLEN(tv->vval.v_string) + 1; // Space for "\tVALUE" ++ if (!STRCMP(dict_key, "name")) ++ { ++ res_name = tv->vval.v_string; ++ continue; ++ } ++ if (!STRCMP(dict_key, "filename")) ++ { ++ res_fname = tv->vval.v_string; ++ continue; ++ } ++ if (!STRCMP(dict_key, "cmd")) ++ { ++ res_cmd = tv->vval.v_string; ++ continue; ++ } ++ has_extra = 1; ++ if (!STRCMP(dict_key, "kind")) ++ { ++ res_kind = tv->vval.v_string; ++ continue; ++ } ++ // Other elements will be stored as "\tKEY:VALUE" ++ // Allocate space for the key and the colon ++ len += STRLEN(dict_key) + 1; ++ } ++ ++ if (has_extra) ++ len += 2; // need space for ;" ++ ++ if (!res_name || !res_fname || !res_cmd) ++ { ++ emsg(_(tfu_inv_ret_msg)); ++ break; ++ } ++ ++ if (name_only) ++ mfp = vim_strsave(res_name); ++ else ++ mfp = (char_u *)alloc((int)sizeof(char_u) + len + 1); ++ ++ if (mfp == NULL) ++ continue; ++ ++ if (!name_only) ++ { ++ char_u *p = mfp; ++ ++ *p++ = MT_GL_OTH + 1; // mtt ++ *p++ = TAG_SEP; // no tag file name ++ #ifdef FEAT_EMACS_TAGS ++ *p++ = TAG_SEP; ++ #endif ++ ++ STRCPY(p, res_name); ++ p += STRLEN(p); ++ ++ *p++ = TAB; ++ STRCPY(p, res_fname); ++ p += STRLEN(p); ++ ++ *p++ = TAB; ++ STRCPY(p, res_cmd); ++ p += STRLEN(p); ++ ++ if (has_extra) ++ { ++ STRCPY(p, ";\""); ++ p += STRLEN(p); ++ ++ if (res_kind) ++ { ++ *p++ = TAB; ++ STRCPY(p, res_kind); ++ p += STRLEN(p); ++ } ++ ++ dict_iterate_start(&item->li_tv, &iter); ++ while (NULL != (dict_key = dict_iterate_next(&iter, &tv))) ++ { ++ if (tv->v_type != VAR_STRING || tv->vval.v_string == NULL) ++ continue; ++ ++ if (!STRCMP(dict_key, "name")) ++ continue; ++ if (!STRCMP(dict_key, "filename")) ++ continue; ++ if (!STRCMP(dict_key, "cmd")) ++ continue; ++ if (!STRCMP(dict_key, "kind")) ++ continue; ++ ++ *p++ = TAB; ++ STRCPY(p, dict_key); ++ p += STRLEN(p); ++ STRCPY(p, ":"); ++ p += STRLEN(p); ++ STRCPY(p, tv->vval.v_string); ++ p += STRLEN(p); ++ } ++ } ++ } ++ ++ // Add all matches because tagfunc should do filtering. ++ if (ga_grow(ga, 1) == OK) ++ { ++ ((char_u **)(ga->ga_data))[ga->ga_len++] = mfp; ++ ++ntags; ++ result = OK; ++ } ++ else ++ { ++ vim_free(mfp); ++ break; ++ } ++ } ++ ++ clear_tv(&rettv); ++ ++ *match_count = ntags; ++ return result; ++ } ++ #endif ++ + /* + * find_tags() - search for tags in tags files + * +*************** +*** 1268,1273 **** +--- 1540,1546 ---- + * TAG_NOIC don't always ignore case + * TAG_KEEP_LANG keep language + * TAG_CSCOPE use cscope results for tags ++ * TAG_NO_TAGFUNC do not call the 'tagfunc' function + */ + int + find_tags( +*************** +*** 1385,1390 **** +--- 1658,1666 ---- + int use_cscope = (flags & TAG_CSCOPE); + #endif + int verbose = (flags & TAG_VERBOSE); ++ #ifdef FEAT_EVAL ++ int use_tfu = ((flags & TAG_NO_TAGFUNC) == 0); ++ #endif + int save_p_ic = p_ic; + + /* +*************** +*** 1480,1485 **** +--- 1756,1773 ---- + vim_memset(&search_info, 0, (size_t)1); + #endif + ++ #ifdef FEAT_EVAL ++ if (*curbuf->b_p_tfu != NUL && use_tfu && !tfu_in_use) ++ { ++ tfu_in_use = TRUE; ++ retval = find_tagfunc_tags(pat, &ga_match[0], &match_count, ++ flags, buf_ffname); ++ tfu_in_use = FALSE; ++ if (retval != NOTDONE) ++ goto findtag_end; ++ } ++ #endif ++ + /* + * When finding a specified number of matches, first try with matching + * case, so binary search can be used, and try ignore-case matches in a +*************** +*** 2308,2314 **** + } + else + { +- #define TAG_SEP 0x02 + size_t tag_fname_len = STRLEN(tag_fname); + #ifdef FEAT_EMACS_TAGS + size_t ebuf_len = 0; +--- 2596,2601 ---- +*************** +*** 2577,2584 **** + tag_freematch(); + + # if defined(FEAT_QUICKFIX) +! if (ptag_entry.tagname) +! VIM_CLEAR(ptag_entry.tagname); + # endif + } + #endif +--- 2864,2870 ---- + tag_freematch(); + + # if defined(FEAT_QUICKFIX) +! tagstack_clear_entry(&ptag_entry); + # endif + } + #endif +*************** +*** 2940,2945 **** +--- 3226,3232 ---- + tagp); + + tagp->tagkind = NULL; ++ tagp->user_data = NULL; + tagp->command_end = NULL; + + if (retval == OK) +*************** +*** 2957,2973 **** + while (ASCII_ISALPHA(*p)) + { + if (STRNCMP(p, "kind:", 5) == 0) +- { + tagp->tagkind = p + 5; + break; +- } + pc = vim_strchr(p, ':'); + pt = vim_strchr(p, '\t'); + if (pc == NULL || (pt != NULL && pc > pt)) +- { + tagp->tagkind = p; +- break; +- } + if (pt == NULL) + break; + p = pt + 1; +--- 3244,3258 ---- + while (ASCII_ISALPHA(*p)) + { + if (STRNCMP(p, "kind:", 5) == 0) + tagp->tagkind = p + 5; ++ else if (STRNCMP(p, "user_data:", 10) == 0) ++ tagp->user_data = p + 10; ++ if (tagp->tagkind != NULL && tagp->user_data != NULL) + break; + pc = vim_strchr(p, ':'); + pt = vim_strchr(p, '\t'); + if (pc == NULL || (pt != NULL && pc > pt)) + tagp->tagkind = p; + if (pt == NULL) + break; + p = pt + 1; +*************** +*** 2980,2985 **** +--- 3265,3277 ---- + ; + tagp->tagkind_end = p; + } ++ if (tagp->user_data != NULL) ++ { ++ for (p = tagp->user_data; ++ *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p) ++ ; ++ tagp->user_data_end = p; ++ } + } + return retval; + } +*************** +*** 3547,3552 **** +--- 3839,3854 ---- + return FAIL; + } + ++ /* ++ * Free a single entry in a tag stack ++ */ ++ static void ++ tagstack_clear_entry(taggy_T *item) ++ { ++ VIM_CLEAR(item->tagname); ++ VIM_CLEAR(item->user_data); ++ } ++ + #if defined(FEAT_CMDL_COMPL) || defined(PROTO) + int + expand_tags( +*************** +*** 3568,3578 **** + tagnmflag = 0; + if (pat[0] == '/') + ret = find_tags(pat + 1, num_file, file, +! TAG_REGEXP | tagnmflag | TAG_VERBOSE, + TAG_MANY, curbuf->b_ffname); + else + ret = find_tags(pat, num_file, file, +! TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NOIC, + TAG_MANY, curbuf->b_ffname); + if (ret == OK && !tagnames) + { +--- 3870,3880 ---- + tagnmflag = 0; + if (pat[0] == '/') + ret = find_tags(pat + 1, num_file, file, +! TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NO_TAGFUNC, + TAG_MANY, curbuf->b_ffname); + else + ret = find_tags(pat, num_file, file, +! TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NO_TAGFUNC | TAG_NOIC, + TAG_MANY, curbuf->b_ffname); + if (ret == OK && !tagnames) + { +*************** +*** 3753,3758 **** +--- 4055,4062 ---- + dict_add_string(retdict, "tagname", tag->tagname); + dict_add_number(retdict, "matchnr", tag->cur_match + 1); + dict_add_number(retdict, "bufnr", tag->cur_fnum); ++ if (tag->user_data) ++ dict_add_string(retdict, "user_data", tag->user_data); + + if ((pos = list_alloc_id(aid_tagstack_from)) == NULL) + return; +*************** +*** 3805,3811 **** + + // Free the current tag stack + for (i = 0; i < wp->w_tagstacklen; ++i) +! vim_free(wp->w_tagstack[i].tagname); + wp->w_tagstacklen = 0; + wp->w_tagstackidx = 0; + } +--- 4109,4115 ---- + + // Free the current tag stack + for (i = 0; i < wp->w_tagstacklen; ++i) +! tagstack_clear_entry(&wp->w_tagstack[i]); + wp->w_tagstacklen = 0; + wp->w_tagstackidx = 0; + } +*************** +*** 3820,3826 **** + taggy_T *tagstack = wp->w_tagstack; + int i; + +! vim_free(tagstack[0].tagname); + for (i = 1; i < wp->w_tagstacklen; ++i) + tagstack[i - 1] = tagstack[i]; + wp->w_tagstacklen--; +--- 4124,4130 ---- + taggy_T *tagstack = wp->w_tagstack; + int i; + +! tagstack_clear_entry(&tagstack[0]); + for (i = 1; i < wp->w_tagstacklen; ++i) + tagstack[i - 1] = tagstack[i]; + wp->w_tagstacklen--; +*************** +*** 3836,3842 **** + int cur_fnum, + int cur_match, + pos_T mark, +! int fnum) + { + taggy_T *tagstack = wp->w_tagstack; + int idx = wp->w_tagstacklen; // top of the stack +--- 4140,4147 ---- + int cur_fnum, + int cur_match, + pos_T mark, +! int fnum, +! char_u *user_data) + { + taggy_T *tagstack = wp->w_tagstack; + int idx = wp->w_tagstacklen; // top of the stack +*************** +*** 3856,3861 **** +--- 4161,4167 ---- + tagstack[idx].cur_match = 0; + tagstack[idx].fmark.mark = mark; + tagstack[idx].fmark.fnum = fnum; ++ tagstack[idx].user_data = user_data; + } + + /* +*************** +*** 3892,3898 **** + tagstack_push_item(wp, tagname, + (int)dict_get_number(itemdict, (char_u *)"bufnr"), + (int)dict_get_number(itemdict, (char_u *)"matchnr") - 1, +! mark, fnum); + } + } + +--- 4198,4205 ---- + tagstack_push_item(wp, tagname, + (int)dict_get_number(itemdict, (char_u *)"bufnr"), + (int)dict_get_number(itemdict, (char_u *)"matchnr") - 1, +! mark, fnum, +! dict_get_string(itemdict, (char_u *)"user_data", TRUE)); + } + } + +*************** +*** 3920,3925 **** +--- 4227,4241 ---- + dictitem_T *di; + list_T *l; + ++ #ifdef FEAT_EVAL ++ // not allowed to alter the tag stack entries from inside tagfunc ++ if (tfu_in_use) ++ { ++ emsg(_(recurmsg)); ++ return FAIL; ++ } ++ #endif ++ + if ((di = dict_find(d, (char_u *)"items", -1)) != NULL) + { + if (di->di_tv.v_type != VAR_LIST) +*** ../vim-8.1.1227/src/testdir/Make_all.mak 2019-04-27 18:00:29.851064563 +0200 +--- src/testdir/Make_all.mak 2019-04-28 16:47:48.260732097 +0200 +*************** +*** 244,249 **** +--- 244,250 ---- + test_tabline \ + test_tabpage \ + test_tagcase \ ++ test_tagfunc \ + test_tagjump \ + test_taglist \ + test_tcl \ +*** ../vim-8.1.1227/src/testdir/test_alot.vim 2019-03-02 06:41:34.345330494 +0100 +--- src/testdir/test_alot.vim 2019-04-28 16:47:48.260732097 +0200 +*************** +*** 60,65 **** +--- 60,66 ---- + source test_tabline.vim + source test_tabpage.vim + source test_tagcase.vim ++ source test_tagfunc.vim + source test_tagjump.vim + source test_taglist.vim + source test_timers.vim +*** ../vim-8.1.1227/src/testdir/test_tagfunc.vim 2019-04-28 18:02:57.627069396 +0200 +--- src/testdir/test_tagfunc.vim 2019-04-28 17:48:10.655362588 +0200 +*************** +*** 0 **** +--- 1,84 ---- ++ " Test 'tagfunc' ++ ++ func TagFunc(pat, flag, info) ++ let g:tagfunc_args = [a:pat, a:flag, a:info] ++ let tags = [] ++ for num in range(1,10) ++ let tags += [{ ++ \ 'cmd': '2', 'name': 'nothing'.num, 'kind': 'm', ++ \ 'filename': 'Xfile1', 'user_data': 'somedata'.num, ++ \}] ++ endfor ++ return tags ++ endfunc ++ ++ func Test_tagfunc() ++ set tagfunc=TagFunc ++ new Xfile1 ++ call setline(1, ['empty', 'one()', 'empty']) ++ write ++ ++ call assert_equal({'cmd': '2', 'static': 0, ++ \ 'name': 'nothing2', 'user_data': 'somedata2', ++ \ 'kind': 'm', 'filename': 'Xfile1'}, taglist('.')[1]) ++ ++ call settagstack(win_getid(), {'items': []}) ++ ++ tag arbitrary ++ call assert_equal('arbitrary', g:tagfunc_args[0]) ++ call assert_equal('', g:tagfunc_args[1]) ++ call assert_equal('somedata1', gettagstack().items[0].user_data) ++ 5tag arbitrary ++ call assert_equal('arbitrary', g:tagfunc_args[0]) ++ call assert_equal('', g:tagfunc_args[1]) ++ call assert_equal('somedata5', gettagstack().items[1].user_data) ++ pop ++ tag ++ call assert_equal('arbitrary', g:tagfunc_args[0]) ++ call assert_equal('', g:tagfunc_args[1]) ++ call assert_equal('somedata5', gettagstack().items[1].user_data) ++ ++ let g:tagfunc_args=[] ++ execute "normal! \<c-]>" ++ call assert_equal('one', g:tagfunc_args[0]) ++ call assert_equal('c', g:tagfunc_args[1]) ++ ++ set cpt=t ++ let g:tagfunc_args=[] ++ execute "normal! i\<c-n>\<c-y>" ++ call assert_equal('ci', g:tagfunc_args[1]) ++ call assert_equal('nothing1', getline('.')[0:7]) ++ ++ func BadTagFunc1(...) ++ return 0 ++ endfunc ++ func BadTagFunc2(...) ++ return [1] ++ endfunc ++ func BadTagFunc3(...) ++ return [{'name': 'foo'}] ++ endfunc ++ ++ for &tagfunc in ['BadTagFunc1', 'BadTagFunc2', 'BadTagFunc3'] ++ try ++ tag nothing ++ call assert_false(1, 'tag command should have failed') ++ catch ++ call assert_exception('E987:') ++ endtry ++ exe 'delf' &tagfunc ++ endfor ++ ++ func NullTagFunc(...) ++ return v:null ++ endfunc ++ set tags= tfu=NullTagFunc ++ call assert_fails('tag nothing', 'E426') ++ delf NullTagFunc ++ ++ bwipe! ++ set tags& tfu& cpt& ++ call delete('Xfile1') ++ endfunc ++ ++ " vim: shiftwidth=2 sts=2 expandtab +*** ../vim-8.1.1227/src/vim.h 2019-04-08 18:15:36.472223190 +0200 +--- src/vim.h 2019-04-28 17:18:43.131769441 +0200 +*************** +*** 1133,1151 **** + /* + * flags for find_tags(). + */ +! #define TAG_HELP 1 /* only search for help tags */ +! #define TAG_NAMES 2 /* only return name of tag */ +! #define TAG_REGEXP 4 /* use tag pattern as regexp */ +! #define TAG_NOIC 8 /* don't always ignore case */ + #ifdef FEAT_CSCOPE +! # define TAG_CSCOPE 16 /* cscope tag */ + #endif +! #define TAG_VERBOSE 32 /* message verbosity */ +! #define TAG_INS_COMP 64 /* Currently doing insert completion */ +! #define TAG_KEEP_LANG 128 /* keep current language */ + +! #define TAG_MANY 300 /* When finding many tags (for completion), +! find up to this many tags */ + + /* + * Types of dialogs passed to do_vim_dialog(). +--- 1133,1152 ---- + /* + * flags for find_tags(). + */ +! #define TAG_HELP 1 // only search for help tags +! #define TAG_NAMES 2 // only return name of tag +! #define TAG_REGEXP 4 // use tag pattern as regexp +! #define TAG_NOIC 8 // don't always ignore case + #ifdef FEAT_CSCOPE +! # define TAG_CSCOPE 16 // cscope tag + #endif +! #define TAG_VERBOSE 32 // message verbosity +! #define TAG_INS_COMP 64 // Currently doing insert completion +! #define TAG_KEEP_LANG 128 // keep current language +! #define TAG_NO_TAGFUNC 256 // do not use 'tagfunc' + +! #define TAG_MANY 300 // When finding many tags (for completion), +! // find up to this many tags + + /* + * Types of dialogs passed to do_vim_dialog(). +*** ../vim-8.1.1227/src/window.c 2019-04-27 20:36:52.534303564 +0200 +--- src/window.c 2019-04-28 16:47:48.260732097 +0200 +*************** +*** 1326,1335 **** + /* copy tagstack and folds */ + for (i = 0; i < oldp->w_tagstacklen; i++) + { +! newp->w_tagstack[i] = oldp->w_tagstack[i]; +! if (newp->w_tagstack[i].tagname != NULL) +! newp->w_tagstack[i].tagname = +! vim_strsave(newp->w_tagstack[i].tagname); + } + newp->w_tagstackidx = oldp->w_tagstackidx; + newp->w_tagstacklen = oldp->w_tagstacklen; +--- 1326,1337 ---- + /* copy tagstack and folds */ + for (i = 0; i < oldp->w_tagstacklen; i++) + { +! taggy_T *tag = &newp->w_tagstack[i]; +! *tag = oldp->w_tagstack[i]; +! if (tag->tagname != NULL) +! tag->tagname = vim_strsave(tag->tagname); +! if (tag->user_data != NULL) +! tag->user_data = vim_strsave(tag->user_data); + } + newp->w_tagstackidx = oldp->w_tagstackidx; + newp->w_tagstacklen = oldp->w_tagstacklen; +*** ../vim-8.1.1227/src/version.c 2019-04-28 16:08:26.813234002 +0200 +--- src/version.c 2019-04-28 18:03:04.703034923 +0200 +*************** +*** 769,770 **** +--- 769,772 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 1228, + /**/ + +-- +Courtroom Quote #19: +Q: Doctor, how many autopsies have you performed on dead people? +A: All my autopsies have been performed on dead people. + + /// 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 /// |