mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
vim-patch:8.2.4494: the find_tags() function is much too long
Problem: The find_tags() function is much too long.
Solution: Refactor the function. (Yegappan Lakshmanan, closes vim/vim#9869)
2f87a99b6e
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -4308,10 +4308,17 @@ void ex_make(exarg_T *eap)
|
|||||||
|
|
||||||
incr_quickfix_busy();
|
incr_quickfix_busy();
|
||||||
|
|
||||||
int res = qf_init(wp, fname, (eap->cmdidx != CMD_make
|
char *errorformat = p_efm;
|
||||||
&& eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
|
bool newlist = true;
|
||||||
(eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd),
|
|
||||||
qf_cmdtitle(*eap->cmdlinep), enc);
|
if (eap->cmdidx != CMD_make && eap->cmdidx != CMD_lmake) {
|
||||||
|
errorformat = p_gefm;
|
||||||
|
}
|
||||||
|
if (eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) {
|
||||||
|
newlist = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = qf_init(wp, fname, errorformat, newlist, qf_cmdtitle(*eap->cmdlinep), enc);
|
||||||
|
|
||||||
qf_info_T *qi = &ql_info;
|
qf_info_T *qi = &ql_info;
|
||||||
if (wp != NULL) {
|
if (wp != NULL) {
|
||||||
|
637
src/nvim/tag.c
637
src/nvim/tag.c
@@ -110,6 +110,23 @@ static char *mt_names[MT_COUNT/2] =
|
|||||||
#define NOTAGFILE 99 // return value for jumpto_tag
|
#define NOTAGFILE 99 // return value for jumpto_tag
|
||||||
static char *nofile_fname = NULL; // fname for NOTAGFILE error
|
static char *nofile_fname = NULL; // fname for NOTAGFILE error
|
||||||
|
|
||||||
|
/// State information used during a tag search
|
||||||
|
typedef struct {
|
||||||
|
pat_T orgpat; ///< holds unconverted pattern info
|
||||||
|
char *help_lang_find; ///< lang to be found
|
||||||
|
bool is_txt; ///< flag of file extension
|
||||||
|
bool did_open; ///< did open a tag file
|
||||||
|
int mincount; ///< MAXCOL: find all matches
|
||||||
|
///< other: minimal number of matches
|
||||||
|
bool linear; ///< do a linear search
|
||||||
|
char *lbuf; ///< line buffer
|
||||||
|
int lbuf_size; ///< length of lbuf
|
||||||
|
int match_count; ///< number of matches found
|
||||||
|
garray_T ga_match[MT_COUNT]; ///< stores matches in sequence
|
||||||
|
hashtab_T ht_match[MT_COUNT]; ///< stores matches by key
|
||||||
|
bool stop_searching; ///< stop when match found or error
|
||||||
|
} findtags_state_T;
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "tag.c.generated.h"
|
# include "tag.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -1355,56 +1372,52 @@ static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int fl
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// find_tags() - search for tags in tags files
|
/// Initialize the state used by find_tags()
|
||||||
///
|
static void findtags_state_init(findtags_state_T *st, char *pat, int mincount)
|
||||||
/// Return FAIL if search completely failed (*num_matches will be 0, *matchesp
|
{
|
||||||
/// will be NULL), OK otherwise.
|
st->orgpat.pat = (char_u *)pat;
|
||||||
///
|
st->orgpat.len = (int)strlen(pat);
|
||||||
/// There is a priority in which type of tag is recognized.
|
st->orgpat.regmatch.regprog = NULL;
|
||||||
///
|
st->help_lang_find = NULL;
|
||||||
/// 6. A static or global tag with a full matching tag for the current file.
|
st->is_txt = false;
|
||||||
/// 5. A global tag with a full matching tag for another file.
|
st->did_open = false;
|
||||||
/// 4. A static tag with a full matching tag for another file.
|
st->mincount = mincount;
|
||||||
/// 3. A static or global tag with an ignore-case matching tag for the
|
st->lbuf_size = LSIZE;
|
||||||
/// current file.
|
st->lbuf = xmalloc((size_t)st->lbuf_size);
|
||||||
/// 2. A global tag with an ignore-case matching tag for another file.
|
st->match_count = 0;
|
||||||
/// 1. A static tag with an ignore-case matching tag for another file.
|
st->stop_searching = false;
|
||||||
///
|
|
||||||
/// Tags in an emacs-style tags file are always global.
|
for (int mtt = 0; mtt < MT_COUNT; mtt++) {
|
||||||
///
|
ga_init(&st->ga_match[mtt], sizeof(char *), 100);
|
||||||
/// flags:
|
hash_init(&st->ht_match[mtt]);
|
||||||
/// 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
|
/// Search for tags in the "tag_fname" tags file.
|
||||||
/// TAG_KEEP_LANG keep language
|
/// Information needed to search for the tags is in the "st" state structure.
|
||||||
/// TAG_NO_TAGFUNC do not call the 'tagfunc' function
|
/// The matching tags are returned in "st".
|
||||||
///
|
static void find_tags_in_file(char *tag_fname, findtags_state_T *st, int flags, char *buf_ffname)
|
||||||
/// @param pat pattern to search for
|
|
||||||
/// @param num_matches return: number of matches found
|
|
||||||
/// @param matchesp return: array of matches found
|
|
||||||
/// @param mincount MAXCOL: find all matches other: minimal number of matches */
|
|
||||||
/// @param buf_ffname name of buffer for priority
|
|
||||||
int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int mincount,
|
|
||||||
char *buf_ffname)
|
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *lbuf; // line buffer
|
|
||||||
int lbuf_size = LSIZE; // length of lbuf
|
|
||||||
char *tag_fname; // name of tag file
|
|
||||||
tagname_T tn; // info for get_tagfname()
|
|
||||||
int first_file; // trying first tag file
|
|
||||||
tagptrs_T tagp;
|
tagptrs_T tagp;
|
||||||
bool did_open = false; // did open a tag file
|
|
||||||
bool stop_searching = false; // stop when match found or error
|
|
||||||
int retval = FAIL; // return value
|
|
||||||
int is_static; // current tag line is static
|
int is_static; // current tag line is static
|
||||||
int is_current; // file name matches
|
int is_current; // file name matches
|
||||||
bool eof = false; // found end-of-file
|
bool eof = false; // found end-of-file
|
||||||
char *p;
|
char *p;
|
||||||
char_u *s;
|
char_u *s;
|
||||||
int i;
|
int i;
|
||||||
|
int help_pri = 0;
|
||||||
|
char_u help_lang[3]; // lang of current tags file
|
||||||
int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
|
int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
|
||||||
|
int tagcmp;
|
||||||
|
off_T offset;
|
||||||
|
enum {
|
||||||
|
TS_START, ///< at start of file
|
||||||
|
TS_LINEAR, ///< linear searching forward, till EOF
|
||||||
|
TS_BINARY, ///< binary searching
|
||||||
|
TS_SKIP_BACK, ///< skipping backwards
|
||||||
|
TS_STEP_FORWARD, ///< stepping forwards
|
||||||
|
} state; // Current search state
|
||||||
struct tag_search_info { // Binary search file offsets
|
struct tag_search_info { // Binary search file offsets
|
||||||
off_T low_offset; // offset for first char of first line that
|
off_T low_offset; // offset for first char of first line that
|
||||||
// could match
|
// could match
|
||||||
@@ -1416,165 +1429,38 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
int low_char; // first char at low_offset
|
int low_char; // first char at low_offset
|
||||||
int high_char; // first char at high_offset
|
int high_char; // first char at high_offset
|
||||||
} search_info;
|
} search_info;
|
||||||
int tagcmp;
|
|
||||||
off_T offset;
|
|
||||||
int round;
|
|
||||||
enum {
|
|
||||||
TS_START, // at start of file
|
|
||||||
TS_LINEAR, // linear searching forward, till EOF
|
|
||||||
TS_BINARY, // binary searching
|
|
||||||
TS_SKIP_BACK, // skipping backwards
|
|
||||||
TS_STEP_FORWARD, // stepping forwards
|
|
||||||
} state; // Current search state
|
|
||||||
|
|
||||||
int cmplen;
|
int cmplen;
|
||||||
int match; // matches
|
int match; // matches
|
||||||
int match_no_ic = 0; // matches with rm_ic == false
|
int match_no_ic = 0; // matches with rm_ic == false
|
||||||
int match_re; // match with regexp
|
int match_re; // match with regexp
|
||||||
int matchoff = 0;
|
int matchoff = 0;
|
||||||
int save_emsg_off;
|
|
||||||
|
|
||||||
char *mfp;
|
char *mfp;
|
||||||
garray_T ga_match[MT_COUNT]; // stores matches in sequence
|
|
||||||
hashtab_T ht_match[MT_COUNT]; // stores matches by key
|
|
||||||
hash_T hash = 0;
|
|
||||||
int match_count = 0; // number of matches found
|
|
||||||
char **matches;
|
|
||||||
int mtt;
|
int mtt;
|
||||||
int help_save;
|
hash_T hash = 0;
|
||||||
int help_pri = 0;
|
|
||||||
char_u *help_lang_find = NULL; // lang to be found
|
|
||||||
char_u help_lang[3]; // lang of current tags file
|
|
||||||
char *saved_pat = NULL; // copy of pat[]
|
|
||||||
bool is_txt = false;
|
|
||||||
|
|
||||||
pat_T orgpat; // holds unconverted pattern info
|
|
||||||
vimconv_T vimconv;
|
|
||||||
|
|
||||||
int findall = (mincount == MAXCOL || mincount == TAG_MANY);
|
|
||||||
// find all matching tags
|
|
||||||
bool sort_error = false; // tags file not sorted
|
bool sort_error = false; // tags file not sorted
|
||||||
int linear; // do a linear search
|
|
||||||
bool sortic = false; // tag file sorted in nocase
|
bool sortic = false; // tag file sorted in nocase
|
||||||
|
int noic = (flags & TAG_NOIC);
|
||||||
bool line_error = false; // syntax error
|
bool line_error = false; // syntax error
|
||||||
int has_re = (flags & TAG_REGEXP); // regexp used
|
int has_re = (flags & TAG_REGEXP); // regexp used
|
||||||
int help_only = (flags & TAG_HELP);
|
int help_only = (flags & TAG_HELP);
|
||||||
int name_only = (flags & TAG_NAMES);
|
int name_only = (flags & TAG_NAMES);
|
||||||
int noic = (flags & TAG_NOIC);
|
|
||||||
int get_it_again = false;
|
int get_it_again = false;
|
||||||
int verbose = (flags & TAG_VERBOSE);
|
vimconv_T vimconv;
|
||||||
int use_tfu = ((flags & TAG_NO_TAGFUNC) == 0);
|
|
||||||
int save_p_ic = p_ic;
|
|
||||||
|
|
||||||
// Change the value of 'ignorecase' according to 'tagcase' for the
|
|
||||||
// duration of this function.
|
|
||||||
switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) {
|
|
||||||
case TC_FOLLOWIC:
|
|
||||||
break;
|
|
||||||
case TC_IGNORE:
|
|
||||||
p_ic = true;
|
|
||||||
break;
|
|
||||||
case TC_MATCH:
|
|
||||||
p_ic = false;
|
|
||||||
break;
|
|
||||||
case TC_FOLLOWSCS:
|
|
||||||
p_ic = ignorecase((char_u *)pat);
|
|
||||||
break;
|
|
||||||
case TC_SMART:
|
|
||||||
p_ic = ignorecase_opt((char_u *)pat, true, true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
help_save = curbuf->b_help;
|
|
||||||
orgpat.pat = (char_u *)pat;
|
|
||||||
orgpat.regmatch.regprog = NULL;
|
|
||||||
vimconv.vc_type = CONV_NONE;
|
vimconv.vc_type = CONV_NONE;
|
||||||
|
|
||||||
// Allocate memory for the buffers that are used
|
|
||||||
lbuf = xmalloc((size_t)lbuf_size);
|
|
||||||
tag_fname = xmalloc(MAXPATHL + 1);
|
|
||||||
for (mtt = 0; mtt < MT_COUNT; mtt++) {
|
|
||||||
ga_init(&ga_match[mtt], sizeof(char *), 100);
|
|
||||||
hash_init(&ht_match[mtt]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize a few variables
|
|
||||||
if (help_only) { // want tags from help file
|
|
||||||
curbuf->b_help = true; // will be restored later
|
|
||||||
}
|
|
||||||
|
|
||||||
orgpat.len = (int)strlen(pat);
|
|
||||||
if (curbuf->b_help) {
|
|
||||||
// When "@ab" is specified use only the "ab" language, otherwise
|
|
||||||
// search all languages.
|
|
||||||
if (orgpat.len > 3 && pat[orgpat.len - 3] == '@'
|
|
||||||
&& ASCII_ISALPHA(pat[orgpat.len - 2])
|
|
||||||
&& ASCII_ISALPHA(pat[orgpat.len - 1])) {
|
|
||||||
saved_pat = xstrnsave(pat, (size_t)orgpat.len - 3);
|
|
||||||
help_lang_find = (char_u *)&pat[orgpat.len - 2];
|
|
||||||
orgpat.pat = (char_u *)saved_pat;
|
|
||||||
orgpat.len -= 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p_tl != 0 && orgpat.len > p_tl) { // adjust for 'taglength'
|
|
||||||
orgpat.len = (int)p_tl;
|
|
||||||
}
|
|
||||||
|
|
||||||
save_emsg_off = emsg_off;
|
|
||||||
emsg_off = true; // don't want error for invalid RE here
|
|
||||||
prepare_pats(&orgpat, has_re);
|
|
||||||
emsg_off = save_emsg_off;
|
|
||||||
if (has_re && orgpat.regmatch.regprog == NULL) {
|
|
||||||
goto findtag_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is only to avoid a compiler warning for using search_info
|
// This is only to avoid a compiler warning for using search_info
|
||||||
// uninitialised.
|
// uninitialised.
|
||||||
CLEAR_FIELD(search_info);
|
CLEAR_FIELD(search_info);
|
||||||
|
|
||||||
if (*curbuf->b_p_tfu != NUL && use_tfu && !tfu_in_use) {
|
|
||||||
tfu_in_use = true;
|
|
||||||
retval = find_tagfunc_tags((char_u *)pat, &ga_match[0], &match_count, flags,
|
|
||||||
(char_u *)buf_ffname);
|
|
||||||
tfu_in_use = false;
|
|
||||||
if (retval != NOTDONE) {
|
|
||||||
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
|
|
||||||
// second loop.
|
|
||||||
// When finding all matches, 'tagbsearch' is off, or there is no fixed
|
|
||||||
// string to look for, ignore case right away to avoid going though the
|
|
||||||
// tags files twice.
|
|
||||||
// When the tag file is case-fold sorted, it is either one or the other.
|
|
||||||
// Only ignore case when TAG_NOIC not used or 'ignorecase' set.
|
|
||||||
|
|
||||||
// Set a flag if the file extension is .txt
|
|
||||||
if ((flags & TAG_KEEP_LANG)
|
|
||||||
&& help_lang_find == NULL
|
|
||||||
&& curbuf->b_fname != NULL
|
|
||||||
&& (i = (int)strlen(curbuf->b_fname)) > 4
|
|
||||||
&& STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) {
|
|
||||||
is_txt = true;
|
|
||||||
}
|
|
||||||
orgpat.regmatch.rm_ic = ((p_ic || !noic)
|
|
||||||
&& (findall || orgpat.headlen == 0 || !p_tbs));
|
|
||||||
for (round = 1; round <= 2; round++) {
|
|
||||||
linear = (orgpat.headlen == 0 || !p_tbs || round == 2);
|
|
||||||
|
|
||||||
// Try tag file names from tags option one by one.
|
|
||||||
for (first_file = true;
|
|
||||||
get_tagfname(&tn, first_file, tag_fname) == OK;
|
|
||||||
first_file = false) {
|
|
||||||
// A file that doesn't exist is silently ignored. Only when not a
|
// A file that doesn't exist is silently ignored. Only when not a
|
||||||
// single file is found, an error message is given (further on).
|
// single file is found, an error message is given (further on).
|
||||||
if (curbuf->b_help) {
|
if (curbuf->b_help) {
|
||||||
// Keep en if the file extension is .txt
|
// Keep en if the file extension is .txt
|
||||||
if (is_txt) {
|
if (st->is_txt) {
|
||||||
STRCPY(help_lang, "en");
|
STRCPY(help_lang, "en");
|
||||||
} else {
|
} else {
|
||||||
// Prefer help tags according to 'helplang'. Put the
|
// Prefer help tags according to 'helplang'. Put the
|
||||||
@@ -1589,15 +1475,15 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
|
|
||||||
// When searching for a specific language skip tags files
|
// When searching for a specific language skip tags files
|
||||||
// for other languages.
|
// for other languages.
|
||||||
if (help_lang_find != NULL
|
if (st->help_lang_find != NULL
|
||||||
&& STRICMP(help_lang, help_lang_find) != 0) {
|
&& STRICMP(help_lang, st->help_lang_find) != 0) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For CTRL-] in a help file prefer a match with the same
|
// For CTRL-] in a help file prefer a match with the same
|
||||||
// language.
|
// language.
|
||||||
if ((flags & TAG_KEEP_LANG)
|
if ((flags & TAG_KEEP_LANG)
|
||||||
&& help_lang_find == NULL
|
&& st->help_lang_find == NULL
|
||||||
&& curbuf->b_fname != NULL
|
&& curbuf->b_fname != NULL
|
||||||
&& (i = (int)strlen(curbuf->b_fname)) > 4
|
&& (i = (int)strlen(curbuf->b_fname)) > 4
|
||||||
&& curbuf->b_fname[i - 1] == 'x'
|
&& curbuf->b_fname[i - 1] == 'x'
|
||||||
@@ -1627,7 +1513,7 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((fp = os_fopen(tag_fname, "r")) == NULL) {
|
if ((fp = os_fopen(tag_fname, "r")) == NULL) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_verbose >= 5) {
|
if (p_verbose >= 5) {
|
||||||
@@ -1636,7 +1522,7 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
verbose_leave();
|
verbose_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
did_open = true; // remember that we found at least one file
|
st->did_open = true; // remember that we found at least one file
|
||||||
|
|
||||||
state = TS_START; // we're at the start of the file
|
state = TS_START; // we're at the start of the file
|
||||||
|
|
||||||
@@ -1652,15 +1538,14 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
ins_compl_check_keys(30, false);
|
ins_compl_check_keys(30, false);
|
||||||
}
|
}
|
||||||
if (got_int || ins_compl_interrupted()) {
|
if (got_int || ins_compl_interrupted()) {
|
||||||
stop_searching = true;
|
st->stop_searching = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// When mincount is TAG_MANY, stop when enough matches have been
|
// When mincount is TAG_MANY, stop when enough matches have been
|
||||||
// found (for completion).
|
// found (for completion).
|
||||||
if (mincount == TAG_MANY && match_count >= TAG_MANY) {
|
if (st->mincount == TAG_MANY && st->match_count >= TAG_MANY) {
|
||||||
stop_searching = true;
|
st->stop_searching = true;
|
||||||
retval = OK;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (get_it_again) {
|
if (get_it_again) {
|
||||||
goto line_read_in;
|
goto line_read_in;
|
||||||
@@ -1675,7 +1560,7 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
search_info.curr_offset = offset;
|
search_info.curr_offset = offset;
|
||||||
} else if (state == TS_SKIP_BACK) {
|
} else if (state == TS_SKIP_BACK) {
|
||||||
// Skipping back (after a match during binary search).
|
// Skipping back (after a match during binary search).
|
||||||
search_info.curr_offset -= lbuf_size * 2;
|
search_info.curr_offset -= st->lbuf_size * 2;
|
||||||
if (search_info.curr_offset < 0) {
|
if (search_info.curr_offset < 0) {
|
||||||
search_info.curr_offset = 0;
|
search_info.curr_offset = 0;
|
||||||
rewind(fp);
|
rewind(fp);
|
||||||
@@ -1689,7 +1574,7 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
// Adjust the search file offset to the correct position
|
// Adjust the search file offset to the correct position
|
||||||
search_info.curr_offset_used = search_info.curr_offset;
|
search_info.curr_offset_used = search_info.curr_offset;
|
||||||
vim_fseek(fp, search_info.curr_offset, SEEK_SET);
|
vim_fseek(fp, search_info.curr_offset, SEEK_SET);
|
||||||
eof = vim_fgets((char_u *)lbuf, lbuf_size, fp);
|
eof = vim_fgets((char_u *)st->lbuf, st->lbuf_size, fp);
|
||||||
if (!eof && search_info.curr_offset != 0) {
|
if (!eof && search_info.curr_offset != 0) {
|
||||||
search_info.curr_offset = vim_ftell(fp);
|
search_info.curr_offset = vim_ftell(fp);
|
||||||
if (search_info.curr_offset == search_info.high_offset) {
|
if (search_info.curr_offset == search_info.high_offset) {
|
||||||
@@ -1697,12 +1582,12 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
vim_fseek(fp, search_info.low_offset, SEEK_SET);
|
vim_fseek(fp, search_info.low_offset, SEEK_SET);
|
||||||
search_info.curr_offset = search_info.low_offset;
|
search_info.curr_offset = search_info.low_offset;
|
||||||
}
|
}
|
||||||
eof = vim_fgets((char_u *)lbuf, lbuf_size, fp);
|
eof = vim_fgets((char_u *)st->lbuf, st->lbuf_size, fp);
|
||||||
}
|
}
|
||||||
// skip empty and blank lines
|
// skip empty and blank lines
|
||||||
while (!eof && vim_isblankline(lbuf)) {
|
while (!eof && vim_isblankline(st->lbuf)) {
|
||||||
search_info.curr_offset = vim_ftell(fp);
|
search_info.curr_offset = vim_ftell(fp);
|
||||||
eof = vim_fgets((char_u *)lbuf, lbuf_size, fp);
|
eof = vim_fgets((char_u *)st->lbuf, st->lbuf_size, fp);
|
||||||
}
|
}
|
||||||
if (eof) {
|
if (eof) {
|
||||||
// Hit end of file. Skip backwards.
|
// Hit end of file. Skip backwards.
|
||||||
@@ -1717,8 +1602,8 @@ int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int minc
|
|||||||
// skip empty and blank lines
|
// skip empty and blank lines
|
||||||
do {
|
do {
|
||||||
search_info.curr_offset = vim_ftell(fp);
|
search_info.curr_offset = vim_ftell(fp);
|
||||||
eof = vim_fgets((char_u *)lbuf, lbuf_size, fp);
|
eof = vim_fgets((char_u *)st->lbuf, st->lbuf_size, fp);
|
||||||
} while (!eof && vim_isblankline(lbuf));
|
} while (!eof && vim_isblankline(st->lbuf));
|
||||||
|
|
||||||
if (eof) {
|
if (eof) {
|
||||||
break; // end of file
|
break; // end of file
|
||||||
@@ -1733,16 +1618,16 @@ line_read_in:
|
|||||||
// Convert every line. Converting the pattern from 'enc' to
|
// Convert every line. Converting the pattern from 'enc' to
|
||||||
// the tags file encoding doesn't work, because characters are
|
// the tags file encoding doesn't work, because characters are
|
||||||
// not recognized.
|
// not recognized.
|
||||||
conv_line = string_convert(&vimconv, lbuf, NULL);
|
conv_line = string_convert(&vimconv, st->lbuf, NULL);
|
||||||
if (conv_line != NULL) {
|
if (conv_line != NULL) {
|
||||||
// Copy or swap lbuf and conv_line.
|
// Copy or swap lbuf and conv_line.
|
||||||
len = (int)strlen(conv_line) + 1;
|
len = (int)strlen(conv_line) + 1;
|
||||||
if (len > lbuf_size) {
|
if (len > st->lbuf_size) {
|
||||||
xfree(lbuf);
|
xfree(st->lbuf);
|
||||||
lbuf = conv_line;
|
st->lbuf = conv_line;
|
||||||
lbuf_size = len;
|
st->lbuf_size = len;
|
||||||
} else {
|
} else {
|
||||||
STRCPY(lbuf, conv_line);
|
STRCPY(st->lbuf, conv_line);
|
||||||
xfree(conv_line);
|
xfree(conv_line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1753,23 +1638,23 @@ line_read_in:
|
|||||||
if (state == TS_START) {
|
if (state == TS_START) {
|
||||||
// The header ends when the line sorts below "!_TAG_". When
|
// The header ends when the line sorts below "!_TAG_". When
|
||||||
// case is folded lower case letters sort before "_".
|
// case is folded lower case letters sort before "_".
|
||||||
if (STRNCMP(lbuf, "!_TAG_", 6) <= 0
|
if (strncmp(st->lbuf, "!_TAG_", 6) <= 0
|
||||||
|| (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1]))) {
|
|| (st->lbuf[0] == '!' && ASCII_ISLOWER(st->lbuf[1]))) {
|
||||||
if (STRNCMP(lbuf, "!_TAG_", 6) != 0) {
|
if (strncmp(st->lbuf, "!_TAG_", 6) != 0) {
|
||||||
// Non-header item before the header, e.g. "!" itself.
|
// Non-header item before the header, e.g. "!" itself.
|
||||||
goto parse_line;
|
goto parse_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read header line.
|
// Read header line.
|
||||||
if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) {
|
if (strncmp(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) {
|
||||||
tag_file_sorted = (uint8_t)lbuf[18];
|
tag_file_sorted = (uint8_t)st->lbuf[18];
|
||||||
}
|
}
|
||||||
if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) {
|
if (strncmp(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) {
|
||||||
// Prepare to convert every line from the specified
|
// Prepare to convert every line from the specified
|
||||||
// encoding to 'encoding'.
|
// encoding to 'encoding'.
|
||||||
for (p = lbuf + 20; *p > ' ' && *p < 127; p++) {}
|
for (p = st->lbuf + 20; *p > ' ' && *p < 127; p++) {}
|
||||||
*p = NUL;
|
*p = NUL;
|
||||||
convert_setup(&vimconv, lbuf + 20, p_enc);
|
convert_setup(&vimconv, st->lbuf + 20, p_enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the next line. Unrecognized flags are ignored.
|
// Read the next line. Unrecognized flags are ignored.
|
||||||
@@ -1784,7 +1669,7 @@ line_read_in:
|
|||||||
// the tag file isn't sorted, the second loop will find it.
|
// the tag file isn't sorted, the second loop will find it.
|
||||||
// When "!_TAG_FILE_SORTED" found: start binary search if
|
// When "!_TAG_FILE_SORTED" found: start binary search if
|
||||||
// flag set.
|
// flag set.
|
||||||
if (linear) {
|
if (st->linear) {
|
||||||
state = TS_LINEAR;
|
state = TS_LINEAR;
|
||||||
} else if (tag_file_sorted == NUL) {
|
} else if (tag_file_sorted == NUL) {
|
||||||
state = TS_BINARY;
|
state = TS_BINARY;
|
||||||
@@ -1793,15 +1678,15 @@ line_read_in:
|
|||||||
} else if (tag_file_sorted == '2') {
|
} else if (tag_file_sorted == '2') {
|
||||||
state = TS_BINARY;
|
state = TS_BINARY;
|
||||||
sortic = true;
|
sortic = true;
|
||||||
orgpat.regmatch.rm_ic = (p_ic || !noic);
|
st->orgpat.regmatch.rm_ic = (p_ic || !noic);
|
||||||
} else {
|
} else {
|
||||||
state = TS_LINEAR;
|
state = TS_LINEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic) {
|
if (state == TS_BINARY && st->orgpat.regmatch.rm_ic && !sortic) {
|
||||||
// Binary search won't work for ignoring case, use linear
|
// Binary search won't work for ignoring case, use linear
|
||||||
// search.
|
// search.
|
||||||
linear = true;
|
st->linear = true;
|
||||||
state = TS_LINEAR;
|
state = TS_LINEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1835,10 +1720,10 @@ parse_line:
|
|||||||
// last-but-one byte (see vim_fgets()).
|
// last-but-one byte (see vim_fgets()).
|
||||||
// Has been reported for Mozilla JS with extremely long names.
|
// Has been reported for Mozilla JS with extremely long names.
|
||||||
// In that case we need to increase lbuf_size.
|
// In that case we need to increase lbuf_size.
|
||||||
if (lbuf[lbuf_size - 2] != NUL) {
|
if (st->lbuf[st->lbuf_size - 2] != NUL) {
|
||||||
lbuf_size *= 2;
|
st->lbuf_size *= 2;
|
||||||
xfree(lbuf);
|
xfree(st->lbuf);
|
||||||
lbuf = xmalloc((size_t)lbuf_size);
|
st->lbuf = xmalloc((size_t)st->lbuf_size);
|
||||||
|
|
||||||
if (state == TS_STEP_FORWARD) {
|
if (state == TS_STEP_FORWARD) {
|
||||||
// Seek to the same position to read the same line again
|
// Seek to the same position to read the same line again
|
||||||
@@ -1853,10 +1738,10 @@ parse_line:
|
|||||||
// Figure out where the different strings are in this line.
|
// Figure out where the different strings are in this line.
|
||||||
// For "normal" tags: Do a quick check if the tag matches.
|
// For "normal" tags: Do a quick check if the tag matches.
|
||||||
// This speeds up tag searching a lot!
|
// This speeds up tag searching a lot!
|
||||||
if (orgpat.headlen) {
|
if (st->orgpat.headlen) {
|
||||||
CLEAR_FIELD(tagp);
|
CLEAR_FIELD(tagp);
|
||||||
tagp.tagname = lbuf;
|
tagp.tagname = st->lbuf;
|
||||||
tagp.tagname_end = (char_u *)vim_strchr(lbuf, TAB);
|
tagp.tagname_end = (char_u *)vim_strchr(st->lbuf, TAB);
|
||||||
if (tagp.tagname_end == NULL) {
|
if (tagp.tagname_end == NULL) {
|
||||||
// Corrupted tag line.
|
// Corrupted tag line.
|
||||||
line_error = true;
|
line_error = true;
|
||||||
@@ -1869,9 +1754,9 @@ parse_line:
|
|||||||
if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength'
|
if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength'
|
||||||
cmplen = (int)p_tl;
|
cmplen = (int)p_tl;
|
||||||
}
|
}
|
||||||
if (has_re && orgpat.headlen < cmplen) {
|
if (has_re && st->orgpat.headlen < cmplen) {
|
||||||
cmplen = orgpat.headlen;
|
cmplen = st->orgpat.headlen;
|
||||||
} else if (state == TS_LINEAR && orgpat.headlen != cmplen) {
|
} else if (state == TS_LINEAR && st->orgpat.headlen != cmplen) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1887,18 +1772,18 @@ parse_line:
|
|||||||
|
|
||||||
// Compare the current tag with the searched tag.
|
// Compare the current tag with the searched tag.
|
||||||
if (sortic) {
|
if (sortic) {
|
||||||
tagcmp = tag_strnicmp((char_u *)tagp.tagname, orgpat.head,
|
tagcmp = tag_strnicmp((char_u *)tagp.tagname, st->orgpat.head,
|
||||||
(size_t)cmplen);
|
(size_t)cmplen);
|
||||||
} else {
|
} else {
|
||||||
tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen);
|
tagcmp = STRNCMP(tagp.tagname, st->orgpat.head, cmplen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A match with a shorter tag means to search forward.
|
// A match with a shorter tag means to search forward.
|
||||||
// A match with a longer tag means to search backward.
|
// A match with a longer tag means to search backward.
|
||||||
if (tagcmp == 0) {
|
if (tagcmp == 0) {
|
||||||
if (cmplen < orgpat.headlen) {
|
if (cmplen < st->orgpat.headlen) {
|
||||||
tagcmp = -1;
|
tagcmp = -1;
|
||||||
} else if (cmplen > orgpat.headlen) {
|
} else if (cmplen > st->orgpat.headlen) {
|
||||||
tagcmp = 1;
|
tagcmp = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1939,7 +1824,7 @@ parse_line:
|
|||||||
break;
|
break;
|
||||||
} else if (state == TS_SKIP_BACK) {
|
} else if (state == TS_SKIP_BACK) {
|
||||||
assert(cmplen >= 0);
|
assert(cmplen >= 0);
|
||||||
if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) {
|
if (mb_strnicmp(tagp.tagname, (char *)st->orgpat.head, (size_t)cmplen) != 0) {
|
||||||
state = TS_STEP_FORWARD;
|
state = TS_STEP_FORWARD;
|
||||||
} else {
|
} else {
|
||||||
// Have to skip back more. Restore the curr_offset
|
// Have to skip back more. Restore the curr_offset
|
||||||
@@ -1949,7 +1834,7 @@ parse_line:
|
|||||||
continue;
|
continue;
|
||||||
} else if (state == TS_STEP_FORWARD) {
|
} else if (state == TS_STEP_FORWARD) {
|
||||||
assert(cmplen >= 0);
|
assert(cmplen >= 0);
|
||||||
if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) {
|
if (mb_strnicmp(tagp.tagname, (char *)st->orgpat.head, (size_t)cmplen) != 0) {
|
||||||
if ((off_T)vim_ftell(fp) > search_info.match_offset) {
|
if ((off_T)vim_ftell(fp) > search_info.match_offset) {
|
||||||
break; // past last match
|
break; // past last match
|
||||||
} else {
|
} else {
|
||||||
@@ -1959,10 +1844,10 @@ parse_line:
|
|||||||
} else {
|
} else {
|
||||||
// skip this match if it can't match
|
// skip this match if it can't match
|
||||||
assert(cmplen >= 0);
|
assert(cmplen >= 0);
|
||||||
}
|
if (mb_strnicmp(tagp.tagname, (char *)st->orgpat.head, (size_t)cmplen) != 0) {
|
||||||
if (mb_strnicmp(tagp.tagname, (char *)orgpat.head, (size_t)cmplen) != 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Can be a matching tag, isolate the file name and command.
|
// Can be a matching tag, isolate the file name and command.
|
||||||
tagp.fname = tagp.tagname_end + 1;
|
tagp.fname = tagp.tagname_end + 1;
|
||||||
@@ -1974,7 +1859,7 @@ parse_line:
|
|||||||
i = OK;
|
i = OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i = parse_tag_line((char_u *)lbuf, &tagp);
|
i = parse_tag_line((char_u *)st->lbuf, &tagp);
|
||||||
}
|
}
|
||||||
if (i == FAIL) {
|
if (i == FAIL) {
|
||||||
line_error = true;
|
line_error = true;
|
||||||
@@ -1988,35 +1873,35 @@ parse_line:
|
|||||||
cmplen = (int)p_tl;
|
cmplen = (int)p_tl;
|
||||||
}
|
}
|
||||||
// if tag length does not match, don't try comparing
|
// if tag length does not match, don't try comparing
|
||||||
if (orgpat.len != cmplen) {
|
if (st->orgpat.len != cmplen) {
|
||||||
match = false;
|
match = false;
|
||||||
} else {
|
} else {
|
||||||
if (orgpat.regmatch.rm_ic) {
|
if (st->orgpat.regmatch.rm_ic) {
|
||||||
assert(cmplen >= 0);
|
assert(cmplen >= 0);
|
||||||
match = mb_strnicmp(tagp.tagname, (char *)orgpat.pat, (size_t)cmplen) == 0;
|
match = mb_strnicmp(tagp.tagname, (char *)st->orgpat.pat, (size_t)cmplen) == 0;
|
||||||
if (match) {
|
if (match) {
|
||||||
match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat,
|
match_no_ic = (STRNCMP(tagp.tagname, st->orgpat.pat,
|
||||||
cmplen) == 0);
|
cmplen) == 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0);
|
match = (STRNCMP(tagp.tagname, st->orgpat.pat, cmplen) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has a regexp: Also find tags matching regexp.
|
// Has a regexp: Also find tags matching regexp.
|
||||||
match_re = false;
|
match_re = false;
|
||||||
if (!match && orgpat.regmatch.regprog != NULL) {
|
if (!match && st->orgpat.regmatch.regprog != NULL) {
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
cc = *tagp.tagname_end;
|
cc = *tagp.tagname_end;
|
||||||
*tagp.tagname_end = NUL;
|
*tagp.tagname_end = NUL;
|
||||||
match = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0);
|
match = vim_regexec(&st->orgpat.regmatch, tagp.tagname, (colnr_T)0);
|
||||||
if (match) {
|
if (match) {
|
||||||
matchoff = (int)(orgpat.regmatch.startp[0] - tagp.tagname);
|
matchoff = (int)(st->orgpat.regmatch.startp[0] - tagp.tagname);
|
||||||
if (orgpat.regmatch.rm_ic) {
|
if (st->orgpat.regmatch.rm_ic) {
|
||||||
orgpat.regmatch.rm_ic = false;
|
st->orgpat.regmatch.rm_ic = false;
|
||||||
match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname, (colnr_T)0);
|
match_no_ic = vim_regexec(&st->orgpat.regmatch, tagp.tagname, (colnr_T)0);
|
||||||
orgpat.regmatch.rm_ic = true;
|
st->orgpat.regmatch.rm_ic = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*tagp.tagname_end = (char_u)cc;
|
*tagp.tagname_end = (char_u)cc;
|
||||||
@@ -2047,7 +1932,7 @@ parse_line:
|
|||||||
mtt = MT_GL_OTH;
|
mtt = MT_GL_OTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (orgpat.regmatch.rm_ic && !match_no_ic) {
|
if (st->orgpat.regmatch.rm_ic && !match_no_ic) {
|
||||||
mtt += MT_IC_OFF;
|
mtt += MT_IC_OFF;
|
||||||
}
|
}
|
||||||
if (match_re) {
|
if (match_re) {
|
||||||
@@ -2073,8 +1958,7 @@ parse_line:
|
|||||||
STRCPY(p + len + 1, help_lang);
|
STRCPY(p + len + 1, help_lang);
|
||||||
snprintf(p + len + 1 + ML_EXTRA, strlen(p) + len + 1 + ML_EXTRA, "%06d",
|
snprintf(p + len + 1 + ML_EXTRA, strlen(p) + len + 1 + ML_EXTRA, "%06d",
|
||||||
help_heuristic(tagp.tagname,
|
help_heuristic(tagp.tagname,
|
||||||
match_re ? matchoff : 0, !match_no_ic)
|
match_re ? matchoff : 0, !match_no_ic) + help_pri);
|
||||||
+ help_pri);
|
|
||||||
|
|
||||||
*tagp.tagname_end = TAB;
|
*tagp.tagname_end = TAB;
|
||||||
} else if (name_only) {
|
} else if (name_only) {
|
||||||
@@ -2116,7 +2000,7 @@ parse_line:
|
|||||||
// other tag: <mtt><tag_fname><0x02><0x02><lbuf><NUL>
|
// other tag: <mtt><tag_fname><0x02><0x02><lbuf><NUL>
|
||||||
// without Emacs tags: <mtt><tag_fname><0x02><lbuf><NUL>
|
// without Emacs tags: <mtt><tag_fname><0x02><lbuf><NUL>
|
||||||
// Here <mtt> is the "mtt" value plus 1 to avoid NUL.
|
// Here <mtt> is the "mtt" value plus 1 to avoid NUL.
|
||||||
len = tag_fname_len + strlen(lbuf) + 3;
|
len = tag_fname_len + strlen(st->lbuf) + 3;
|
||||||
mfp = xmalloc(sizeof(char) + len + 1);
|
mfp = xmalloc(sizeof(char) + len + 1);
|
||||||
p = mfp;
|
p = mfp;
|
||||||
p[0] = (char)(mtt + 1);
|
p[0] = (char)(mtt + 1);
|
||||||
@@ -2128,7 +2012,7 @@ parse_line:
|
|||||||
#endif
|
#endif
|
||||||
p[tag_fname_len + 1] = TAG_SEP;
|
p[tag_fname_len + 1] = TAG_SEP;
|
||||||
s = (char_u *)p + 1 + tag_fname_len + 1;
|
s = (char_u *)p + 1 + tag_fname_len + 1;
|
||||||
STRCPY(s, lbuf);
|
STRCPY(s, st->lbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mfp != NULL) {
|
if (mfp != NULL) {
|
||||||
@@ -2140,13 +2024,11 @@ parse_line:
|
|||||||
// follow after it. E.g. help tags store the priority
|
// follow after it. E.g. help tags store the priority
|
||||||
// after the NUL.
|
// after the NUL.
|
||||||
hash = hash_hash((char_u *)mfp);
|
hash = hash_hash((char_u *)mfp);
|
||||||
hi = hash_lookup(&ht_match[mtt], (const char *)mfp,
|
hi = hash_lookup(&st->ht_match[mtt], (const char *)mfp, strlen(mfp), hash);
|
||||||
strlen(mfp), hash);
|
|
||||||
if (HASHITEM_EMPTY(hi)) {
|
if (HASHITEM_EMPTY(hi)) {
|
||||||
hash_add_item(&ht_match[mtt], hi, (char_u *)mfp, hash);
|
hash_add_item(&st->ht_match[mtt], hi, (char_u *)mfp, hash);
|
||||||
ga_grow(&ga_match[mtt], 1);
|
GA_APPEND(char *, &st->ga_match[mtt], mfp);
|
||||||
((char **)(ga_match[mtt].ga_data))[ga_match[mtt].ga_len++] = mfp;
|
st->match_count++;
|
||||||
match_count++;
|
|
||||||
} else {
|
} else {
|
||||||
// duplicate tag, drop it
|
// duplicate tag, drop it
|
||||||
xfree(mfp);
|
xfree(mfp);
|
||||||
@@ -2158,7 +2040,7 @@ parse_line:
|
|||||||
if (line_error) {
|
if (line_error) {
|
||||||
semsg(_("E431: Format error in tags file \"%s\""), tag_fname);
|
semsg(_("E431: Format error in tags file \"%s\""), tag_fname);
|
||||||
semsg(_("Before byte %" PRId64), (int64_t)vim_ftell(fp));
|
semsg(_("Before byte %" PRId64), (int64_t)vim_ftell(fp));
|
||||||
stop_searching = true;
|
st->stop_searching = true;
|
||||||
line_error = false;
|
line_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2174,53 +2056,30 @@ parse_line:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop searching if sufficient tags have been found.
|
// Stop searching if sufficient tags have been found.
|
||||||
if (match_count >= mincount) {
|
if (st->match_count >= st->mincount) {
|
||||||
retval = OK;
|
st->stop_searching = true;
|
||||||
stop_searching = true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (stop_searching) {
|
/// Copy the tags found by find_tags() to "matchesp".
|
||||||
break;
|
static void findtags_copy_matches(findtags_state_T *st, char ***matchesp, int *num_matches,
|
||||||
}
|
int name_only)
|
||||||
} // end of for-each-file loop
|
{
|
||||||
|
char **matches;
|
||||||
|
int mtt;
|
||||||
|
int i;
|
||||||
|
char *mfp;
|
||||||
|
char *p;
|
||||||
|
|
||||||
tagname_free(&tn);
|
if (st->match_count > 0) {
|
||||||
|
matches = xmalloc((size_t)st->match_count * sizeof(char *));
|
||||||
// stop searching when already did a linear search, or when TAG_NOIC
|
|
||||||
// used, and 'ignorecase' not set or already did case-ignore search
|
|
||||||
if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
orgpat.regmatch.rm_ic = true; // try another time while ignoring case
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stop_searching) {
|
|
||||||
if (!did_open && verbose) { // never opened any tags file
|
|
||||||
emsg(_("E433: No tags file"));
|
|
||||||
}
|
|
||||||
retval = OK; // It's OK even when no tag found
|
|
||||||
}
|
|
||||||
|
|
||||||
findtag_end:
|
|
||||||
xfree(lbuf);
|
|
||||||
vim_regfree(orgpat.regmatch.regprog);
|
|
||||||
xfree(tag_fname);
|
|
||||||
|
|
||||||
// Move the matches from the ga_match[] arrays into one list of
|
|
||||||
// matches. When retval == FAIL, free the matches.
|
|
||||||
if (retval == FAIL) {
|
|
||||||
match_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_count > 0) {
|
|
||||||
matches = xmalloc((size_t)match_count * sizeof(char *));
|
|
||||||
} else {
|
} else {
|
||||||
matches = NULL;
|
matches = NULL;
|
||||||
}
|
}
|
||||||
match_count = 0;
|
st->match_count = 0;
|
||||||
for (mtt = 0; mtt < MT_COUNT; mtt++) {
|
for (mtt = 0; mtt < MT_COUNT; mtt++) {
|
||||||
for (i = 0; i < ga_match[mtt].ga_len; i++) {
|
for (i = 0; i < st->ga_match[mtt].ga_len; i++) {
|
||||||
mfp = ((char **)(ga_match[mtt].ga_data))[i];
|
mfp = ((char **)(st->ga_match[mtt].ga_data))[i];
|
||||||
if (matches == NULL) {
|
if (matches == NULL) {
|
||||||
xfree(mfp);
|
xfree(mfp);
|
||||||
} else {
|
} else {
|
||||||
@@ -2235,16 +2094,206 @@ findtag_end:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
matches[match_count++] = mfp;
|
matches[st->match_count++] = mfp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ga_clear(&ga_match[mtt]);
|
ga_clear(&st->ga_match[mtt]);
|
||||||
hash_clear(&ht_match[mtt]);
|
hash_clear(&st->ht_match[mtt]);
|
||||||
}
|
}
|
||||||
|
|
||||||
*matchesp = matches;
|
*matchesp = matches;
|
||||||
*num_matches = match_count;
|
*num_matches = st->match_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// find_tags() - search for tags in tags files
|
||||||
|
///
|
||||||
|
/// Return FAIL if search completely failed (*num_matches will be 0, *matchesp
|
||||||
|
/// will be NULL), OK otherwise.
|
||||||
|
///
|
||||||
|
/// There is a priority in which type of tag is recognized.
|
||||||
|
///
|
||||||
|
/// 6. A static or global tag with a full matching tag for the current file.
|
||||||
|
/// 5. A global tag with a full matching tag for another file.
|
||||||
|
/// 4. A static tag with a full matching tag for another file.
|
||||||
|
/// 3. A static or global tag with an ignore-case matching tag for the
|
||||||
|
/// current file.
|
||||||
|
/// 2. A global tag with an ignore-case matching tag for another file.
|
||||||
|
/// 1. A static tag with an ignore-case matching tag for another file.
|
||||||
|
///
|
||||||
|
/// 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_NO_TAGFUNC do not call the 'tagfunc' function
|
||||||
|
///
|
||||||
|
/// @param pat pattern to search for
|
||||||
|
/// @param num_matches return: number of matches found
|
||||||
|
/// @param matchesp return: array of matches found
|
||||||
|
/// @param mincount MAXCOL: find all matches
|
||||||
|
/// other: minimal number of matches
|
||||||
|
/// @param buf_ffname name of buffer for priority
|
||||||
|
int find_tags(char *pat, int *num_matches, char ***matchesp, int flags, int mincount,
|
||||||
|
char *buf_ffname)
|
||||||
|
{
|
||||||
|
findtags_state_T st;
|
||||||
|
char *tag_fname; // name of tag file
|
||||||
|
tagname_T tn; // info for get_tagfname()
|
||||||
|
int first_file; // trying first tag file
|
||||||
|
int retval = FAIL; // return value
|
||||||
|
int round;
|
||||||
|
|
||||||
|
int save_emsg_off;
|
||||||
|
|
||||||
|
int help_save;
|
||||||
|
int i;
|
||||||
|
char *saved_pat = NULL; // copy of pat[]
|
||||||
|
|
||||||
|
int findall = (mincount == MAXCOL || mincount == TAG_MANY); // find all matching tags
|
||||||
|
int has_re = (flags & TAG_REGEXP); // regexp used
|
||||||
|
int help_only = (flags & TAG_HELP);
|
||||||
|
int name_only = (flags & TAG_NAMES);
|
||||||
|
int noic = (flags & TAG_NOIC);
|
||||||
|
int verbose = (flags & TAG_VERBOSE);
|
||||||
|
int use_tfu = ((flags & TAG_NO_TAGFUNC) == 0);
|
||||||
|
int save_p_ic = p_ic;
|
||||||
|
|
||||||
|
// Change the value of 'ignorecase' according to 'tagcase' for the
|
||||||
|
// duration of this function.
|
||||||
|
switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) {
|
||||||
|
case TC_FOLLOWIC:
|
||||||
|
break;
|
||||||
|
case TC_IGNORE:
|
||||||
|
p_ic = true;
|
||||||
|
break;
|
||||||
|
case TC_MATCH:
|
||||||
|
p_ic = false;
|
||||||
|
break;
|
||||||
|
case TC_FOLLOWSCS:
|
||||||
|
p_ic = ignorecase((char_u *)pat);
|
||||||
|
break;
|
||||||
|
case TC_SMART:
|
||||||
|
p_ic = ignorecase_opt((char_u *)pat, true, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
help_save = curbuf->b_help;
|
||||||
|
|
||||||
|
// Allocate memory for the buffers that are used
|
||||||
|
tag_fname = xmalloc(MAXPATHL + 1);
|
||||||
|
|
||||||
|
findtags_state_init(&st, pat, mincount);
|
||||||
|
|
||||||
|
// Initialize a few variables
|
||||||
|
if (help_only) { // want tags from help file
|
||||||
|
curbuf->b_help = true; // will be restored later
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curbuf->b_help) {
|
||||||
|
// When "@ab" is specified use only the "ab" language, otherwise
|
||||||
|
// search all languages.
|
||||||
|
if (st.orgpat.len > 3 && pat[st.orgpat.len - 3] == '@'
|
||||||
|
&& ASCII_ISALPHA(pat[st.orgpat.len - 2])
|
||||||
|
&& ASCII_ISALPHA(pat[st.orgpat.len - 1])) {
|
||||||
|
saved_pat = xstrnsave(pat, (size_t)st.orgpat.len - 3);
|
||||||
|
st.help_lang_find = &pat[st.orgpat.len - 2];
|
||||||
|
st.orgpat.pat = (char_u *)saved_pat;
|
||||||
|
st.orgpat.len -= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p_tl != 0 && st.orgpat.len > p_tl) { // adjust for 'taglength'
|
||||||
|
st.orgpat.len = (int)p_tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_emsg_off = emsg_off;
|
||||||
|
emsg_off = true; // don't want error for invalid RE here
|
||||||
|
prepare_pats(&st.orgpat, has_re);
|
||||||
|
emsg_off = save_emsg_off;
|
||||||
|
if (has_re && st.orgpat.regmatch.regprog == NULL) {
|
||||||
|
goto findtag_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*curbuf->b_p_tfu != NUL && use_tfu && !tfu_in_use) {
|
||||||
|
tfu_in_use = true;
|
||||||
|
retval = find_tagfunc_tags((char_u *)pat, &st.ga_match[0], &st.match_count, flags,
|
||||||
|
(char_u *)buf_ffname);
|
||||||
|
tfu_in_use = false;
|
||||||
|
if (retval != NOTDONE) {
|
||||||
|
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
|
||||||
|
// second loop.
|
||||||
|
// When finding all matches, 'tagbsearch' is off, or there is no fixed
|
||||||
|
// string to look for, ignore case right away to avoid going though the
|
||||||
|
// tags files twice.
|
||||||
|
// When the tag file is case-fold sorted, it is either one or the other.
|
||||||
|
// Only ignore case when TAG_NOIC not used or 'ignorecase' set.
|
||||||
|
|
||||||
|
// Set a flag if the file extension is .txt
|
||||||
|
if ((flags & TAG_KEEP_LANG)
|
||||||
|
&& st.help_lang_find == NULL
|
||||||
|
&& curbuf->b_fname != NULL
|
||||||
|
&& (i = (int)strlen(curbuf->b_fname)) > 4
|
||||||
|
&& STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) {
|
||||||
|
st.is_txt = true;
|
||||||
|
}
|
||||||
|
st.orgpat.regmatch.rm_ic = ((p_ic || !noic)
|
||||||
|
&& (findall || st.orgpat.headlen == 0 || !p_tbs));
|
||||||
|
for (round = 1; round <= 2; round++) {
|
||||||
|
st.linear = (st.orgpat.headlen == 0 || !p_tbs || round == 2);
|
||||||
|
|
||||||
|
// Try tag file names from tags option one by one.
|
||||||
|
for (first_file = true;
|
||||||
|
get_tagfname(&tn, first_file, tag_fname) == OK;
|
||||||
|
first_file = false) {
|
||||||
|
find_tags_in_file(tag_fname, &st, flags, buf_ffname);
|
||||||
|
if (st.stop_searching) {
|
||||||
|
retval = OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // end of for-each-file loop
|
||||||
|
|
||||||
|
tagname_free(&tn);
|
||||||
|
|
||||||
|
// stop searching when already did a linear search, or when TAG_NOIC
|
||||||
|
// used, and 'ignorecase' not set or already did case-ignore search
|
||||||
|
if (st.stop_searching || st.linear || (!p_ic && noic)
|
||||||
|
|| st.orgpat.regmatch.rm_ic) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try another time while ignoring case
|
||||||
|
st.orgpat.regmatch.rm_ic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!st.stop_searching) {
|
||||||
|
if (!st.did_open && verbose) { // never opened any tags file
|
||||||
|
emsg(_("E433: No tags file"));
|
||||||
|
}
|
||||||
|
retval = OK; // It's OK even when no tag found
|
||||||
|
}
|
||||||
|
|
||||||
|
findtag_end:
|
||||||
|
xfree(st.lbuf);
|
||||||
|
vim_regfree(st.orgpat.regmatch.regprog);
|
||||||
|
xfree(tag_fname);
|
||||||
|
|
||||||
|
// Move the matches from the ga_match[] arrays into one list of
|
||||||
|
// matches. When retval == FAIL, free the matches.
|
||||||
|
if (retval == FAIL) {
|
||||||
|
st.match_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
findtags_copy_matches(&st, matchesp, num_matches, name_only);
|
||||||
|
|
||||||
curbuf->b_help = help_save;
|
curbuf->b_help = help_save;
|
||||||
xfree(saved_pat);
|
xfree(saved_pat);
|
||||||
|
@@ -1448,6 +1448,11 @@ func Test_tagfile_errors()
|
|||||||
endtry
|
endtry
|
||||||
call assert_equal(v:true, caught_431)
|
call assert_equal(v:true, caught_431)
|
||||||
|
|
||||||
|
" tag name and file name are not separated by a tab
|
||||||
|
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||||
|
\ "foo Xfile 1"], 'Xtags')
|
||||||
|
call assert_fails('tag foo', 'E431:')
|
||||||
|
|
||||||
call delete('Xtags')
|
call delete('Xtags')
|
||||||
call delete('Xfile')
|
call delete('Xfile')
|
||||||
set tags&
|
set tags&
|
||||||
|
Reference in New Issue
Block a user