0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.4518: the binary tag search feature is always enabled

Problem:    The binary tag search feature is always enabled.
Solution:   Remove the #ifdefs.  Add a few more tests. (Yegappan Lakshmanan,
            closes #9893)
This commit is contained in:
Yegappan Lakshmanan 2022-03-06 14:27:10 +00:00 committed by Bram Moolenaar
parent 9eccee0e85
commit 655b734ee8
6 changed files with 91 additions and 63 deletions

View File

@ -4382,7 +4382,8 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
|| (is_funcref && trans_name == NULL)) || (is_funcref && trans_name == NULL))
semsg(_(e_invalid_argument_str), use_string ? tv_get_string(&argvars[0]) : s); semsg(_(e_invalid_argument_str),
use_string ? tv_get_string(&argvars[0]) : s);
// Don't check an autoload name for existence here. // Don't check an autoload name for existence here.
else if (trans_name != NULL && (is_funcref else if (trans_name != NULL && (is_funcref
? find_func(trans_name, is_global) == NULL ? find_func(trans_name, is_global) == NULL
@ -6101,13 +6102,7 @@ f_has(typval_T *argvars, typval_T *rettv)
0 0
#endif #endif
}, },
{"tag_binary", {"tag_binary", 1}, // graduated feature
#ifdef FEAT_TAG_BINS
1
#else
0
#endif
},
{"tcl", {"tcl",
#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL) #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
1 1

View File

@ -248,11 +248,6 @@
# define FEAT_EMACS_TAGS # define FEAT_EMACS_TAGS
#endif #endif
/*
* +tag_binary Can use a binary search for the tags file.
*/
#define FEAT_TAG_BINS
/* /*
* +cscope Unix only: Cscope support. * +cscope Unix only: Cscope support.
*/ */

View File

@ -1270,7 +1270,6 @@ do_tags(exarg_T *eap UNUSED)
msg_puts("\n>"); msg_puts("\n>");
} }
#ifdef FEAT_TAG_BINS
/* /*
* Compare two strings, for length "len", ignoring case the ASCII way. * Compare two strings, for length "len", ignoring case the ASCII way.
* return 0 for match, < 0 for smaller, > 0 for bigger * return 0 for match, < 0 for smaller, > 0 for bigger
@ -1294,7 +1293,6 @@ tag_strnicmp(char_u *s1, char_u *s2, size_t len)
} }
return 0; // strings match return 0; // strings match
} }
#endif
/* /*
* Structure to hold info about the tag pattern being used. * Structure to hold info about the tag pattern being used.
@ -1592,9 +1590,7 @@ typedef struct {
int did_open; // did open a tag file int did_open; // did open a tag file
int mincount; // MAXCOL: find all matches int mincount; // MAXCOL: find all matches
// other: minimal number of matches // other: minimal number of matches
#ifdef FEAT_TAG_BINS
int linear; // do a linear search int linear; // do a linear search
#endif
char_u *lbuf; // line buffer char_u *lbuf; // line buffer
int lbuf_size; // length of lbuf int lbuf_size; // length of lbuf
#ifdef FEAT_EMACS_TAGS #ifdef FEAT_EMACS_TAGS
@ -1960,10 +1956,8 @@ tags_file_hdr_parse(findtags_state_T *st, vimconv_T *vcp, int *sorted_file)
return FALSE; return FALSE;
// Read header line. // Read header line.
#ifdef FEAT_TAG_BINS
if (STRNCMP(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) if (STRNCMP(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0)
*sorted_file = st->lbuf[18]; *sorted_file = st->lbuf[18];
#endif
if (STRNCMP(st->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
@ -2264,23 +2258,18 @@ find_tags_in_file(
int help_pri = 0; int help_pri = 0;
char_u help_lang[3] = ""; // lang of current tags file char_u help_lang[3] = ""; // lang of current tags file
#endif #endif
#ifdef FEAT_TAG_BINS
int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
off_T filesize; off_T filesize;
int tagcmp; int tagcmp;
off_T offset; off_T offset;
#endif
enum enum
{ {
TS_START, // at start of file TS_START, // at start of file
TS_LINEAR // linear searching forward, till EOF TS_LINEAR, // linear searching forward, till EOF
#ifdef FEAT_TAG_BINS TS_BINARY, // binary searching
, TS_BINARY, // binary searching
TS_SKIP_BACK, // skipping backwards TS_SKIP_BACK, // skipping backwards
TS_STEP_FORWARD // stepping forwards TS_STEP_FORWARD // stepping forwards
#endif
} state; // Current search state } state; // Current search state
#ifdef FEAT_TAG_BINS
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
@ -2293,7 +2282,6 @@ find_tags_in_file(
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;
#endif
int cmplen; int cmplen;
int match; // matches int match; // matches
@ -2305,11 +2293,9 @@ find_tags_in_file(
hash_T hash = 0; hash_T hash = 0;
#ifdef FEAT_TAG_BINS
int sort_error = FALSE; // tags file not sorted int sort_error = FALSE; // tags file not sorted
int sortic = FALSE; // tag file sorted in nocase int sortic = FALSE; // tag file sorted in nocase
int noic = (flags & TAG_NOIC); int noic = (flags & TAG_NOIC);
#endif
int line_error = FALSE; // syntax error int line_error = FALSE; // syntax error
int has_re = (flags & TAG_REGEXP); // regexp used int has_re = (flags & TAG_REGEXP); // regexp used
#ifdef FEAT_CSCOPE #ifdef FEAT_CSCOPE
@ -2319,11 +2305,9 @@ find_tags_in_file(
vimconv.vc_type = CONV_NONE; vimconv.vc_type = CONV_NONE;
#ifdef FEAT_TAG_BINS
// 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);
#endif
// 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).
@ -2359,12 +2343,10 @@ find_tags_in_file(
// Read and parse the lines in the file one by one // Read and parse the lines in the file one by one
for (;;) for (;;)
{ {
#ifdef FEAT_TAG_BINS
// check for CTRL-C typed, more often when jumping around // check for CTRL-C typed, more often when jumping around
if (state == TS_BINARY || state == TS_SKIP_BACK) if (state == TS_BINARY || state == TS_SKIP_BACK)
line_breakcheck(); line_breakcheck();
else else
#endif
fast_breakcheck(); fast_breakcheck();
if ((flags & TAG_INS_COMP)) // Double brackets for gcc if ((flags & TAG_INS_COMP)) // Double brackets for gcc
ins_compl_check_keys(30, FALSE); ins_compl_check_keys(30, FALSE);
@ -2382,7 +2364,6 @@ find_tags_in_file(
} }
if (st->get_searchpat) if (st->get_searchpat)
goto line_read_in; goto line_read_in;
#ifdef FEAT_TAG_BINS
// For binary search: compute the next offset to use. // For binary search: compute the next offset to use.
if (state == TS_BINARY) if (state == TS_BINARY)
{ {
@ -2449,7 +2430,6 @@ find_tags_in_file(
* Not jumping around in the file: Read the next line. * Not jumping around in the file: Read the next line.
*/ */
else else
#endif
{ {
// skip empty and blank lines // skip empty and blank lines
do do
@ -2460,9 +2440,7 @@ find_tags_in_file(
else else
#endif #endif
{ {
#ifdef FEAT_TAG_BINS
search_info.curr_offset = vim_ftell(fp); search_info.curr_offset = vim_ftell(fp);
#endif
eof = vim_fgets(st->lbuf, st->lbuf_size, fp); eof = vim_fgets(st->lbuf, st->lbuf_size, fp);
} }
} while (!eof && vim_isblankline(st->lbuf)); } while (!eof && vim_isblankline(st->lbuf));
@ -2525,7 +2503,6 @@ line_read_in:
// Headers ends. // Headers ends.
#ifdef FEAT_TAG_BINS
/* /*
* When there is no tag head, or ignoring case, need to do a * When there is no tag head, or ignoring case, need to do a
* linear search. * linear search.
@ -2561,11 +2538,7 @@ line_read_in:
st->linear = TRUE; st->linear = TRUE;
state = TS_LINEAR; state = TS_LINEAR;
} }
#else
state = TS_LINEAR;
#endif
#ifdef FEAT_TAG_BINS
// When starting a binary search, get the size of the file and // When starting a binary search, get the size of the file and
// compute the first offset. // compute the first offset.
if (state == TS_BINARY) if (state == TS_BINARY)
@ -2591,7 +2564,6 @@ line_read_in:
} }
continue; continue;
} }
#endif
} }
parse_line: parse_line:
@ -2615,14 +2587,12 @@ parse_line:
return FAIL; return FAIL;
} }
#ifdef FEAT_TAG_BINS
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
vim_fseek(fp, search_info.curr_offset, SEEK_SET); vim_fseek(fp, search_info.curr_offset, SEEK_SET);
// this will try the same thing again, make sure the offset is // this will try the same thing again, make sure the offset is
// different // different
search_info.curr_offset = 0; search_info.curr_offset = 0;
#endif
continue; continue;
} }
@ -2659,7 +2629,6 @@ parse_line:
else if (state == TS_LINEAR && st->orgpat.headlen != cmplen) else if (state == TS_LINEAR && st->orgpat.headlen != cmplen)
continue; continue;
#ifdef FEAT_TAG_BINS
if (state == TS_BINARY) if (state == TS_BINARY)
{ {
/* /*
@ -2750,7 +2719,6 @@ parse_line:
} }
} }
else else
#endif
// skip this match if it can't match // skip this match if it can't match
if (MB_STRNICMP(tagp.tagname, st->orgpat.head, cmplen) != 0) if (MB_STRNICMP(tagp.tagname, st->orgpat.head, cmplen) != 0)
continue; continue;
@ -2874,14 +2842,12 @@ parse_line:
if (vimconv.vc_type != CONV_NONE) if (vimconv.vc_type != CONV_NONE)
convert_setup(&vimconv, NULL, NULL); convert_setup(&vimconv, NULL, NULL);
#ifdef FEAT_TAG_BINS
tag_file_sorted = NUL; tag_file_sorted = NUL;
if (sort_error) if (sort_error)
{ {
semsg(_(e_tags_file_not_sorted_str), st->tag_fname); semsg(_(e_tags_file_not_sorted_str), st->tag_fname);
sort_error = FALSE; sort_error = FALSE;
} }
#endif
/* /*
* Stop searching if sufficient tags have been found. * Stop searching if sufficient tags have been found.
@ -2983,9 +2949,7 @@ find_tags(
tagname_T tn; // info for get_tagfname() tagname_T tn; // info for get_tagfname()
int first_file; // trying first tag file int first_file; // trying first tag file
int retval = FAIL; // return value int retval = FAIL; // return value
#ifdef FEAT_TAG_BINS
int round; int round;
#endif
int save_emsg_off; int save_emsg_off;
@ -2995,10 +2959,8 @@ find_tags(
char_u *saved_pat = NULL; // copy of pat[] char_u *saved_pat = NULL; // copy of pat[]
#endif #endif
#ifdef FEAT_TAG_BINS
int findall = (mincount == MAXCOL || mincount == TAG_MANY); int findall = (mincount == MAXCOL || mincount == TAG_MANY);
// find all matching tags // find all matching tags
#endif
int has_re = (flags & TAG_REGEXP); // regexp used int has_re = (flags & TAG_REGEXP); // regexp used
int noic = (flags & TAG_NOIC); int noic = (flags & TAG_NOIC);
#ifdef FEAT_CSCOPE #ifdef FEAT_CSCOPE
@ -3101,15 +3063,11 @@ find_tags(
* When the tag file is case-fold sorted, it is either one or the other. * 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. * Only ignore case when TAG_NOIC not used or 'ignorecase' set.
*/ */
#ifdef FEAT_TAG_BINS
st.orgpat.regmatch.rm_ic = ((p_ic || !noic) st.orgpat.regmatch.rm_ic = ((p_ic || !noic)
&& (findall || st.orgpat.headlen == 0 || !p_tbs)); && (findall || st.orgpat.headlen == 0 || !p_tbs));
for (round = 1; round <= 2; ++round) for (round = 1; round <= 2; ++round)
{ {
st.linear = (st.orgpat.headlen == 0 || !p_tbs || round == 2); st.linear = (st.orgpat.headlen == 0 || !p_tbs || round == 2);
#else
st.orgpat.regmatch.rm_ic = (p_ic || !noic);
#endif
/* /*
* Try tag file names from tags option one by one. * Try tag file names from tags option one by one.
@ -3139,7 +3097,6 @@ find_tags(
#endif #endif
tagname_free(&tn); tagname_free(&tn);
#ifdef FEAT_TAG_BINS
// stop searching when already did a linear search, or when TAG_NOIC // stop searching when already did a linear search, or when TAG_NOIC
// used, and 'ignorecase' not set or already did case-ignore search // used, and 'ignorecase' not set or already did case-ignore search
if (st.stop_searching || st.linear || (!p_ic && noic) || if (st.stop_searching || st.linear || (!p_ic && noic) ||
@ -3153,7 +3110,6 @@ find_tags(
// try another time while ignoring case // try another time while ignoring case
st.orgpat.regmatch.rm_ic = TRUE; st.orgpat.regmatch.rm_ic = TRUE;
} }
#endif
if (!st.stop_searching) if (!st.stop_searching)
{ {

View File

@ -1503,4 +1503,77 @@ func Test_stag_close_window_on_error()
set tags& set tags&
endfunc endfunc
" Test for 'tagbsearch' (binary search)
func Test_tagbsearch()
" If a tags file header says the tags are sorted, but the tags are actually
" unsorted, then binary search should fail and linear search should work.
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/",
\ "third\tXfoo\t3",
\ "second\tXfoo\t2",
\ "first\tXfoo\t1"],
\ 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
int second() {}
int third() {}
[CODE]
call writefile(code, 'Xfoo')
enew
set tagbsearch
call assert_fails('tag first', 'E426:')
call assert_equal('', bufname())
call assert_fails('tag second', 'E426:')
call assert_equal('', bufname())
tag third
call assert_equal('Xfoo', bufname())
call assert_equal(3, line('.'))
%bw!
set notagbsearch
tag first
call assert_equal('Xfoo', bufname())
call assert_equal(1, line('.'))
enew
tag second
call assert_equal('Xfoo', bufname())
call assert_equal(2, line('.'))
enew
tag third
call assert_equal('Xfoo', bufname())
call assert_equal(3, line('.'))
%bw!
" If a tags file header says the tags are unsorted, but the tags are
" actually sorted, then binary search should work.
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/",
\ "first\tXfoo\t1",
\ "second\tXfoo\t2",
\ "third\tXfoo\t3"],
\ 'Xtags')
set tagbsearch
tag first
call assert_equal('Xfoo', bufname())
call assert_equal(1, line('.'))
enew
tag second
call assert_equal('Xfoo', bufname())
call assert_equal(2, line('.'))
enew
tag third
call assert_equal('Xfoo', bufname())
call assert_equal(3, line('.'))
%bw!
call delete('Xtags')
call delete('Xfoo')
set tags& tagbsearch&
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@ -37,6 +37,12 @@ func Test_taglist()
call assert_equal('d', cmd[0]['kind']) call assert_equal('d', cmd[0]['kind'])
call assert_equal('call cursor(3, 4)', cmd[0]['cmd']) call assert_equal('call cursor(3, 4)', cmd[0]['cmd'])
" Use characters with value > 127 in the tag extra field.
call writefile([
\ "vFoo\tXfoo\t4" .. ';"' .. "\ttypename:int\ta£££\tv",
\ ], 'Xtags')
call assert_equal('v', taglist('vFoo')[0].kind)
call assert_fails("let l=taglist([])", 'E730:') call assert_fails("let l=taglist([])", 'E730:')
call delete('Xtags') call delete('Xtags')
@ -216,6 +222,11 @@ func Test_format_error()
endtry endtry
call assert_true(caught_exception) call assert_true(caught_exception)
" no field after the filename for a tag
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "foo\tXfile"], 'Xtags')
call assert_fails("echo taglist('foo')", 'E431:')
set tags& set tags&
call delete('Xtags') call delete('Xtags')
endfunc endfunc

View File

@ -590,11 +590,7 @@ static char *(features[]) =
#if defined(USE_SYSTEM) && defined(UNIX) #if defined(USE_SYSTEM) && defined(UNIX)
"+system()", "+system()",
#endif #endif
#ifdef FEAT_TAG_BINS
"+tag_binary", "+tag_binary",
#else
"-tag_binary",
#endif
"-tag_old_static", "-tag_old_static",
"-tag_any_white", "-tag_any_white",
#ifdef FEAT_TCL #ifdef FEAT_TCL
@ -754,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4518,
/**/ /**/
4517, 4517,
/**/ /**/