On 28-Apr-2010 Robert Webb <[email protected]> wrote:
>
> > - left a FIXME in the code stating that duplicate tags should be removed
> > from the list returned by the user-defined function. Not quite sure,
> > though, whether it wouldn't be better to leave it to the user.
>
> I don't think there's any point keeping them. They can never be of use if
> all
> details match (name, file, search command). Currently I have a function
> called
> UniqList() which does it. It's very inefficient (N^2). Would be more
> efficiently handled in C. Maybe a uniq() function would be handy in
> general,
> to remove multiple copies in a list.
>
> Maybe a flag to taglist() requesting that duplicate entries be removed?
What I meant is: if the user's function used in 'tagfunc' returns a list
of tags, should I verify that there are no duplicates in the list? I'd
say: no - leave it to the user to take care of what is returned.
Another issue is whether taglist() should remove duplicates. It might be
good to handle this but for now I'd rather stick to 'tagfunc' to get it
done well.
> > - maybe it would make some sense to let taglist() return a result
> > returned by the 'tagfunc' function? taglist() could take an optional
> > argument which would state whether recursion is allowed and an upper
> > limit on the recursion level could be set. I can at least imagine
> > a use case for such a feature (admittedly, awkward a bit).
>
> I don't know that an extra option is required. I think taglist() should
> always
> make use of 'tagfunc', unless called recursively from within the tag
> function
> itself. I guess an extra optional arg might be useful to allow the user to
> avoid calling tagfunc if they wish.
>
> Hmm, I suppose taglist() won't know whether the 'c' flag should be used when
> calling 'tagfunc'. Maybe we need to be able to pass this flag to taglist()
> too so it can pass it through?
OK, I'll think about this later.
> Hmm, another small difference. My script presumes the tag name is complete,
> whereas taglist() just searches, eg taglist("blah") will find tags for
> "blabbyblahblab". Is this an issue?
I have no problem with that.
> Some other thoughts:
>
> - Another thing I need is a way to do more than one search in the tag command.
[...]
> - Gets a little trickier than above too, because I want to have access to
> all
> of vim's search capabilities in that tag command. The format of a search
[...]
> - Vim doesn't load all tags when it does a tag search. It looks at one file
[...]
It would be great to have all of them, but I consider them improvements
to the basic functionality offered by 'tagfunc'. Once 'tagfunc' is
implemented properly these can be considered.
> - By the way, in TagFunc2() you should use "taglist('^' . pattern . '$')"
> rather than "taglist('\<' . pattern . '\>')". The latter may miss some
> non-alphabetic tags like operators. Not that it matters for a proof of
> concept like this, but thought I'd mention it. Oh, I see this example is
> in
> the docs too, so all the more reason to do it the "proper" way. Not sure
> it's the best example though, since not many tags will use line numbers
> (for
> me none of them do although not sure why).
OK, I changed the example totally so this is a non-issue.
> The script shouldn't be hard to convert for use with 'tagfunc'. Something
> like
> this:
After my small adjustments works for me almost perfectly:
function! SmartTagFunc(pattern, flags)
if a:flags =~? 'c'
let tags = []
let id = GetNiceTagList(tags, 'nk')
return tags
else
return taglist(a:pattern)
endif
endfunc
I am having some problems with the code that I am working on.
Unfortunately, I cannot share it so I will try to tackle the thing
myself.
Some news about 'tagfunc':
I discovered that the 'tagfunc' implementation prevented omni completion
for C from working when 'tagfunc' was set to the SmartTagFunc() function
defined a few lines above. This was due to the fact that - as mentioned
by the documentation - in each of the dictionaries returned by
SmartTagFunc() only the entries 'name', 'filename' and 'cmd' are
considered relevant. Without thinking too much I simply discarded all
the other entries effectively filtering out the data essential to omni
completion. The latest patch fixes the problem. Find it attached.
--
Cheers,
Lech
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e178613..98a65a4 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6691,6 +6691,22 @@ A jump table for the options with a short description
can be found at |Q_op|.
command-line completion and ":help").
{Vi: always uses binary search in some versions}
+ *'tagfunc'* *'tfu'*
+'tagfunc' 'tfu' string (default: empty)
+ local to buffer
+ {not in Vi}
+ {not available when compiled without the +eval
+ or +insert_expand feature}
+ This option specifies a function to be used to perform tag searches.
+ The function should take two parameters, the first of which is the
+ pattern to be searched, while the second is a set of flags which may
+ be used by the function to decide on its behaviour. Currently the only
+ flag that may appear here is 'c', which indicates that the context
+ around the cursor position can be used to generate more accurate
+ results.
+ See |tag-function| for an explanation of what the function should
+ return and an example of such a function.
+
*'taglength'* *'tl'*
'taglength' 'tl' number (default 0)
global
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index 15ebbd4..f7847c3 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -14,6 +14,7 @@ See section |29.1| of the user manual for an introduction.
4. Tags details |tag-details|
5. Tags file format |tags-file-format|
6. Include file searches |include-search|
+7. Programmable tag search |tag-function|
==============================================================================
1. Jump to a tag *tag-commands*
@@ -834,4 +835,58 @@ Common arguments for the commands above:
< For a ":djump", ":dsplit", ":dlist" and ":dsearch" command the pattern
is used as a literal string, not as a search pattern.
+==============================================================================
+7. Programmable tag search *tag-function*
+
+It is possible to provide Vim with a script which will generate a list of tags
+used for commands like |:tag|, |:tselect| and normal mode commands like
+|CTRL-]|. The Vim script function used for generating the taglist is specified
+by setting the 'tagfunc' option. The function will be called with two
+arguments:
+ a:pattern - the tag identifier used during the tag search,
+ a:flags - a list of flags to control the function behaviour.
+
+Currently the only flag that may be passed to the tag function is 'c' which
+indicates that the function was invoked due to 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.
+
+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.
+
+The function should return a list of dictionaries. Each of the dictionaries
+must at least include the following entries:
+ 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, a line number or
+ a line number followed by a byte number.
+Note that the format of the result is similar to that of |taglist()|,
+which makes it possible to use its output to generate the result.
+
+
+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)
+ 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:ft=help:norl:
diff --git a/src/buffer.c b/src/buffer.c
index 0569f16..e86899e 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1801,6 +1801,7 @@ free_buf_options(buf, free_p_ff)
#ifdef FEAT_COMPL_FUNC
clear_string_option(&buf->b_p_cfu);
clear_string_option(&buf->b_p_ofu);
+ clear_string_option(&buf->b_p_tfu);
#endif
#ifdef FEAT_QUICKFIX
clear_string_option(&buf->b_p_gp);
diff --git a/src/edit.c b/src/edit.c
index 33e580f..8cb7bc0 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -4050,6 +4050,7 @@ ins_compl_get_exp(ini)
/* Find up to TAG_MANY matches. Avoids that an enormous number
* of matches is found when compl_pattern is empty */
+ g_tag_at_cursor = 1;
if (find_tags(compl_pattern, &num_matches, &matches,
TAG_REGEXP | TAG_NAMES | TAG_NOIC |
TAG_INS_COMP | (ctrl_x_mode ? TAG_VERBOSE : 0),
@@ -4057,6 +4058,7 @@ ins_compl_get_exp(ini)
{
ins_compl_add_matches(num_matches, matches, p_ic);
}
+ g_tag_at_cursor = 0;
p_ic = save_p_ic;
break;
diff --git a/src/eval.c b/src/eval.c
index ad127b5..f50cc94 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -6991,6 +6991,62 @@ dict_add_nr_str(d, key, nr, str)
return OK;
}
+/* Initializes a data structure used for iterating over dictionary items in
+ * dict_iterate_next().
+ */
+ void
+dict_iterate_start(argvars, iter)
+ typval_T *argvars;
+ struct dict_iterator_S *iter;
+{
+ dict_T *d;
+
+ if (argvars[0].v_type != VAR_DICT)
+ {
+ iter->items = 0;
+ return;
+ }
+
+ if ((d = argvars[0].vval.v_dict) == NULL)
+ {
+ iter->items = 0;
+ return;
+ }
+
+ iter->items = (int)d->dv_hashtab.ht_used;
+ iter->hi = d->dv_hashtab.ht_array;
+}
+
+/* Allows iterating over the items stored in a dictionary.
+ * Returns the 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.
+ * iter should be initialized with dict_iterate_start() before calling this
+ * function for the first time.
+ */
+ char_u*
+dict_iterate_next(iter, tv_result)
+ struct dict_iterator_S *iter;
+ typval_T **tv_result;
+{
+ dictitem_T *di;
+ char_u *result;
+
+ if (iter->items <= 0)
+ return NULL;
+
+ while (HASHITEM_EMPTY(iter->hi))
+ ++iter->hi;
+
+ di = HI2DI(iter->hi);
+ result = di->di_key;
+ *tv_result = &di->di_tv;
+
+ --iter->items;
+ ++iter->hi;
+ return result;
+}
+
/*
* Get the number of items in a Dictionary.
*/
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 2296c33..b847fd5 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -5926,7 +5926,7 @@ find_help_tags(arg, num_matches, matches, keep_lang)
*matches = (char_u **)"";
*num_matches = 0;
- flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE;
+ flags = TAG_HELP | TAG_REGEXP | TAG_NAMES | TAG_VERBOSE | TAG_DONT_USE_TFU;
if (keep_lang)
flags |= TAG_KEEP_LANG;
if (find_tags(IObuff, num_matches, matches, flags, (int)MAXCOL, NULL) == OK
diff --git a/src/globals.h b/src/globals.h
index bfe48ca..d137d73 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1066,6 +1066,9 @@ EXTERN int g_do_tagpreview INIT(= 0); /* for tag
preview commands:
height of preview window */
# endif
#endif
+EXTERN int g_tag_at_cursor INIT(= 0); /* 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\\\"|");
diff --git a/src/normal.c b/src/normal.c
index 8b9fea7..5eb19c2 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -5616,7 +5616,11 @@ nv_ident(cap)
normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0);
}
else
+ {
+ g_tag_at_cursor = 1;
do_cmdline_cmd(buf);
+ g_tag_at_cursor = 0;
+ }
vim_free(buf);
}
diff --git a/src/option.c b/src/option.c
index ba17c11..cfa2383 100644
--- a/src/option.c
+++ b/src/option.c
@@ -172,6 +172,9 @@
#endif
#define PV_SW OPT_BUF(BV_SW)
#define PV_SWF OPT_BUF(BV_SWF)
+#ifdef FEAT_COMPL_FUNC
+# define PV_TFU OPT_BUF(BV_TFU)
+#endif
#define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS))
#define PV_TS OPT_BUF(BV_TS)
#define PV_TW OPT_BUF(BV_TW)
@@ -288,6 +291,7 @@ static char_u *p_cpt;
#ifdef FEAT_COMPL_FUNC
static char_u *p_cfu;
static char_u *p_ofu;
+static char_u *p_tfu;
#endif
static int p_eol;
static int p_et;
@@ -2432,6 +2436,15 @@ static struct vimoption
{(char_u *)TRUE, (char_u *)0L}
#endif
SCRIPTID_INIT},
+ {"tagfunc", "tfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE,
+#ifdef FEAT_COMPL_FUNC
+ (char_u *)&p_tfu, PV_TFU,
+ {(char_u *)"", (char_u *)0L}
+#else
+ (char_u *)NULL, PV_NONE,
+ {(char_u *)0L, (char_u *)0L}
+#endif
+ SCRIPTID_INIT},
{"taglength", "tl", P_NUM|P_VI_DEF,
(char_u *)&p_tl, PV_NONE,
{(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
@@ -5174,6 +5187,7 @@ check_buf_options(buf)
#ifdef FEAT_COMPL_FUNC
check_string_option(&buf->b_p_cfu);
check_string_option(&buf->b_p_ofu);
+ check_string_option(&buf->b_p_tfu);
#endif
#ifdef FEAT_KEYMAP
check_string_option(&buf->b_p_keymap);
@@ -9265,6 +9279,7 @@ get_varp(p)
#ifdef FEAT_COMPL_FUNC
case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
+ case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
#endif
case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
case PV_ET: return (char_u *)&(curbuf->b_p_et);
@@ -9604,6 +9619,7 @@ buf_copy_options(buf, flags)
#ifdef FEAT_COMPL_FUNC
buf->b_p_cfu = vim_strsave(p_cfu);
buf->b_p_ofu = vim_strsave(p_ofu);
+ buf->b_p_tfu = vim_strsave(p_tfu);
#endif
buf->b_p_sts = p_sts;
buf->b_p_sts_nopaste = p_sts_nopaste;
diff --git a/src/option.h b/src/option.h
index cfa7692..793febc 100644
--- a/src/option.h
+++ b/src/option.h
@@ -999,6 +999,9 @@ enum
#endif
, BV_SW
, BV_SWF
+#ifdef FEAT_COMPL_FUNC
+ , BV_TFU
+#endif
, BV_TAGS
, BV_TS
, BV_TW
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
index e817769..6474cdd 100644
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -56,6 +56,8 @@ dictitem_T *dictitem_alloc __ARGS((char_u *key));
void dictitem_free __ARGS((dictitem_T *item));
int dict_add __ARGS((dict_T *d, dictitem_T *item));
int dict_add_nr_str __ARGS((dict_T *d, char *key, long nr, char_u *str));
+void dict_iterate_start __ARGS((typval_T *argvars, struct dict_iterator_S
*iter));
+char_u *dict_iterate_next __ARGS((struct dict_iterator_S *iter, typval_T
**tv_result));
char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save));
long get_dict_number __ARGS((dict_T *d, char_u *key));
char_u *get_function_name __ARGS((expand_T *xp, int idx));
diff --git a/src/structs.h b/src/structs.h
index 99afecf..44d552c 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1120,6 +1120,16 @@ struct dictvar_S
dict_T *dv_used_prev; /* previous dict in used dicts list */
};
+/*
+ * Structure used for iterating over dictionary items.
+ * Initialize with dict_iterate_start().
+ */
+struct dict_iterator_S
+{
+ int items;
+ hashitem_T *hi;
+};
+
/* 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 */
@@ -1359,6 +1369,7 @@ struct file_buffer
#ifdef FEAT_COMPL_FUNC
char_u *b_p_cfu; /* 'completefunc' */
char_u *b_p_ofu; /* 'omnifunc' */
+ char_u *b_p_tfu; /* 'tagfunc' */
#endif
int b_p_eol; /* 'endofline' */
int b_p_et; /* 'expandtab' */
diff --git a/src/tag.c b/src/tag.c
index ba36de7..f949ff9 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -30,7 +30,8 @@ typedef struct tag_pointers
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 */
+ 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
@@ -164,6 +165,7 @@ do_tag(tag, type, count, forceit, verbose)
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;
@@ -188,6 +190,7 @@ do_tag(tag, type, count, forceit, verbose)
{
type = DT_TAG;
no_regexp = TRUE;
+ use_tfu = 0;
}
prev_num_matches = num_matches;
@@ -542,6 +545,9 @@ do_tag(tag, type, count, forceit, verbose)
#endif
if (verbose)
flags |= TAG_VERBOSE;
+ if (!use_tfu)
+ flags |= TAG_DONT_USE_TFU;
+
if (find_tags(name, &new_num_matches, &new_matches, flags,
max_num_matches, buf_ffname) == OK
&& new_num_matches < max_num_matches)
@@ -1233,6 +1239,187 @@ prepare_pats(pats, has_re)
pats->regmatch.regprog = NULL;
}
+struct match_found
+{
+ int len; /* nr of chars of match[] to be
compared */
+ char_u match[1]; /* actually longer */
+};
+
+/*
+ * find_tfu_tags() - 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, FAIL otherwise.
+ * pat - used as the pattern supplied to the user-defined function,
+ * ga - the tags will be placed here,
+ * match_count - here the number of tags found will be placed.
+ */
+ static int
+find_tfu_tags(char_u *pat, garray_T *ga, int *match_count)
+{
+ pos_T pos;
+ list_T *taglist;
+ listitem_T *item;
+ int ntags = 0;
+ int result = FAIL;
+ char_u *args[2];
+
+ args[0] = pat;
+ args[1] = (char_u *) (g_tag_at_cursor? "c": "");
+
+ if (*curbuf->b_p_tfu == NUL)
+ goto done;
+
+ pos = curwin->w_cursor;
+ taglist = call_func_retlist(curbuf->b_p_tfu, 2, args, FALSE);
+ curwin->w_cursor = pos; /* restore the cursor position */
+
+ if (taglist == NULL)
+ goto done;
+
+ for (item = taglist->lv_first; item != NULL; item = item->li_next)
+ {
+ struct match_found *mfp;
+ char_u *res_name, *res_fname, *res_cmd, *res_kind;
+ int len;
+ struct dict_iterator_S iter;
+ char_u *dict_key;
+ typval_T *tv;
+ int has_extra = 0;
+
+ if (item->li_tv.v_type != VAR_DICT)
+ continue;
+
+#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)
+ 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;
+ }
+ len += STRLEN(dict_key) + 1; /* Other elements will be stored as
"\tKEY:VALUE".
+ * Allocate space for the key and the
colon. */
+ }
+
+ if (has_extra)
+ len += 2; /* need space for ;" */
+
+ if (!res_name || !res_fname || !res_cmd)
+ continue;
+
+ mfp = (struct match_found *)alloc(
+ (int)sizeof(struct match_found) + len);
+ if (mfp != NULL)
+ {
+ char_u *p;
+ mfp->len = len;
+ p = mfp->match;
+ p[0] = 0; /* mtt */
+ p[1] = NUL; /* no tag file name */
+ p = p + 2;
+#ifdef FEAT_EMACS_TAGS
+ *p = NUL;
+ ++p;
+#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)
+ 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);
+ }
+ }
+
+ /* FIXME:2010-04-24:llorens: Don't add identical matches. */
+ if (ga_grow(ga, 1) == OK)
+ {
+ ((struct match_found **)(ga->ga_data)) [ga->ga_len++] = mfp;
+ ++ntags;
+ result = OK;
+ }
+ else
+ vim_free(mfp);
+ }
+ }
+
+ list_free(taglist, TRUE);
+done:
+ *match_count = ntags;
+ return result;
+}
+
/*
* find_tags() - search for tags in tags files
*
@@ -1252,11 +1439,12 @@ prepare_pats(pats, has_re)
* Tags in an emacs-style tags file are always global.
*
* flags:
- * TAG_HELP only search for help tags
- * TAG_NAMES only return name of tag
- * TAG_REGEXP use "pat" as a regexp
- * TAG_NOIC don't always ignore case
- * TAG_KEEP_LANG keep language
+ * TAG_HELP only search for help tags
+ * TAG_NAMES only return name of tag
+ * TAG_REGEXP use "pat" as a regexp
+ * TAG_NOIC don't always ignore case
+ * TAG_KEEP_LANG keep language
+ * TAG_DONT_USE_TFU do not invoke the 'tagfunc' command
*/
int
find_tags(pat, num_matches, matchesp, flags, mincount, buf_ffname)
@@ -1335,11 +1523,7 @@ find_tags(pat, num_matches, matchesp, flags, mincount,
buf_ffname)
int is_etag; /* current file is emaces style
*/
#endif
- struct match_found
- {
- int len; /* nr of chars of match[] to be compared */
- char_u match[1]; /* actually longer */
- } *mfp, *mfp2;
+ struct match_found *mfp, *mfp2;
garray_T ga_match[MT_COUNT];
int match_count = 0; /* number of matches
found */
char_u **matches;
@@ -1380,6 +1564,8 @@ find_tags(pat, num_matches, matchesp, flags, mincount,
buf_ffname)
int use_cscope = (flags & TAG_CSCOPE);
#endif
int verbose = (flags & TAG_VERBOSE);
+ int use_tfu = ((flags & TAG_DONT_USE_TFU) == 0);
+ static int tfu_call_level = 0;
help_save = curbuf->b_help;
orgpat.pat = pat;
@@ -1448,6 +1634,14 @@ find_tags(pat, num_matches, matchesp, flags, mincount,
buf_ffname)
vim_memset(&search_info, 0, (size_t)1);
#endif
+ if (*curbuf->b_p_tfu != NUL && use_tfu && tfu_call_level == 0)
+ {
+ ++tfu_call_level;
+ retval = find_tfu_tags(pat, &ga_match[0], &match_count);
+ --tfu_call_level;
+ goto findtag_end;
+ }
+
/*
* 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
@@ -3738,11 +3932,11 @@ expand_tags(tagnames, pat, num_file, file)
tagnmflag = 0;
if (pat[0] == '/')
ret = find_tags(pat + 1, num_file, file,
- TAG_REGEXP | tagnmflag | TAG_VERBOSE,
+ TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_DONT_USE_TFU,
TAG_MANY, curbuf->b_ffname);
else
ret = find_tags(pat, num_file, file,
- TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NOIC,
+ TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_DONT_USE_TFU |
TAG_NOIC,
TAG_MANY, curbuf->b_ffname);
if (ret == OK && !tagnames)
{
diff --git a/src/vim.h b/src/vim.h
index 9a36b9b..6882e91 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1045,19 +1045,20 @@ extern char *(*dyn_libintl_textdomain)(const char
*domainname);
/*
* 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 */
+#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 */
+# 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_VERBOSE 32 /* message verbosity */
+#define TAG_INS_COMP 64 /* Currently doing insert completion */
+#define TAG_KEEP_LANG 128 /* keep current language */
+#define TAG_DONT_USE_TFU 256 /* whether 'tagfunc' should be
evaluated */
-#define TAG_MANY 300 /* When finding many tags (for completion),
- find up to this many tags */
+#define TAG_MANY 300 /* When finding many tags (for
completion),
+ find up to this many tags */
/*
* Types of dialogs passed to do_vim_dialog().