# HG changeset patch # User Bram Moolenaar # Date 1646577006 -3600 # Node ID c724906134a3ffaef6ec485d6719586b0b06bcb1 # Parent 719dc5b9fc6e1e2cc960568e37465e8c25184afa patch 8.2.4518: the binary tag search feature is always enabled Commit: https://github.com/vim/vim/commit/655b734ee858e90dd8d28549b7704a71b25d30e7 Author: Yegappan Lakshmanan Date: Sun Mar 6 14:27:10 2022 +0000 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) diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -4382,7 +4382,8 @@ common_function(typval_T *argvars, typva if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) || (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. else if (trans_name != NULL && (is_funcref ? find_func(trans_name, is_global) == NULL @@ -6101,13 +6102,7 @@ f_has(typval_T *argvars, typval_T *rettv 0 #endif }, - {"tag_binary", -#ifdef FEAT_TAG_BINS - 1 -#else - 0 -#endif - }, + {"tag_binary", 1}, // graduated feature {"tcl", #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL) 1 diff --git a/src/feature.h b/src/feature.h --- a/src/feature.h +++ b/src/feature.h @@ -249,11 +249,6 @@ #endif /* - * +tag_binary Can use a binary search for the tags file. - */ -#define FEAT_TAG_BINS - -/* * +cscope Unix only: Cscope support. */ #if defined(UNIX) && defined(FEAT_BIG) && !defined(FEAT_CSCOPE) && !defined(MACOS_X) diff --git a/src/tag.c b/src/tag.c --- a/src/tag.c +++ b/src/tag.c @@ -1270,7 +1270,6 @@ do_tags(exarg_T *eap UNUSED) msg_puts("\n>"); } -#ifdef FEAT_TAG_BINS /* * Compare two strings, for length "len", ignoring case the ASCII way. * return 0 for match, < 0 for smaller, > 0 for bigger @@ -1294,7 +1293,6 @@ tag_strnicmp(char_u *s1, char_u *s2, siz } return 0; // strings match } -#endif /* * 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 mincount; // MAXCOL: find all matches // other: minimal number of matches -#ifdef FEAT_TAG_BINS int linear; // do a linear search -#endif char_u *lbuf; // line buffer int lbuf_size; // length of lbuf #ifdef FEAT_EMACS_TAGS @@ -1960,10 +1956,8 @@ tags_file_hdr_parse(findtags_state_T *st return FALSE; // Read header line. -#ifdef FEAT_TAG_BINS if (STRNCMP(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) *sorted_file = st->lbuf[18]; -#endif if (STRNCMP(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) { // Prepare to convert every line from the specified @@ -2264,23 +2258,18 @@ find_tags_in_file( int help_pri = 0; char_u help_lang[3] = ""; // lang of current tags file #endif -#ifdef FEAT_TAG_BINS int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value off_T filesize; int tagcmp; off_T offset; -#endif enum { TS_START, // at start of file - TS_LINEAR // linear searching forward, till EOF -#ifdef FEAT_TAG_BINS - , TS_BINARY, // binary searching + TS_LINEAR, // linear searching forward, till EOF + TS_BINARY, // binary searching TS_SKIP_BACK, // skipping backwards TS_STEP_FORWARD // stepping forwards -#endif } state; // Current search state -#ifdef FEAT_TAG_BINS struct tag_search_info // Binary search file offsets { 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 high_char; // first char at high_offset } search_info; -#endif int cmplen; int match; // matches @@ -2305,11 +2293,9 @@ find_tags_in_file( hash_T hash = 0; -#ifdef FEAT_TAG_BINS int sort_error = FALSE; // tags file not sorted int sortic = FALSE; // tag file sorted in nocase int noic = (flags & TAG_NOIC); -#endif int line_error = FALSE; // syntax error int has_re = (flags & TAG_REGEXP); // regexp used #ifdef FEAT_CSCOPE @@ -2319,11 +2305,9 @@ find_tags_in_file( vimconv.vc_type = CONV_NONE; -#ifdef FEAT_TAG_BINS // This is only to avoid a compiler warning for using search_info // uninitialised. CLEAR_FIELD(search_info); -#endif // A file that doesn't exist is silently ignored. Only when not a // 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 for (;;) { -#ifdef FEAT_TAG_BINS // check for CTRL-C typed, more often when jumping around if (state == TS_BINARY || state == TS_SKIP_BACK) line_breakcheck(); else -#endif fast_breakcheck(); if ((flags & TAG_INS_COMP)) // Double brackets for gcc ins_compl_check_keys(30, FALSE); @@ -2382,7 +2364,6 @@ find_tags_in_file( } if (st->get_searchpat) goto line_read_in; -#ifdef FEAT_TAG_BINS // For binary search: compute the next offset to use. if (state == TS_BINARY) { @@ -2449,7 +2430,6 @@ find_tags_in_file( * Not jumping around in the file: Read the next line. */ else -#endif { // skip empty and blank lines do @@ -2460,9 +2440,7 @@ find_tags_in_file( else #endif { -#ifdef FEAT_TAG_BINS search_info.curr_offset = vim_ftell(fp); -#endif eof = vim_fgets(st->lbuf, st->lbuf_size, fp); } } while (!eof && vim_isblankline(st->lbuf)); @@ -2525,7 +2503,6 @@ line_read_in: // Headers ends. -#ifdef FEAT_TAG_BINS /* * When there is no tag head, or ignoring case, need to do a * linear search. @@ -2561,11 +2538,7 @@ line_read_in: st->linear = TRUE; state = TS_LINEAR; } -#else - state = TS_LINEAR; -#endif - -#ifdef FEAT_TAG_BINS + // When starting a binary search, get the size of the file and // compute the first offset. if (state == TS_BINARY) @@ -2591,7 +2564,6 @@ line_read_in: } continue; } -#endif } parse_line: @@ -2615,14 +2587,12 @@ parse_line: return FAIL; } -#ifdef FEAT_TAG_BINS if (state == TS_STEP_FORWARD) // Seek to the same position to read the same line again vim_fseek(fp, search_info.curr_offset, SEEK_SET); // this will try the same thing again, make sure the offset is // different search_info.curr_offset = 0; -#endif continue; } @@ -2659,7 +2629,6 @@ parse_line: else if (state == TS_LINEAR && st->orgpat.headlen != cmplen) continue; -#ifdef FEAT_TAG_BINS if (state == TS_BINARY) { /* @@ -2750,7 +2719,6 @@ parse_line: } } else -#endif // skip this match if it can't match if (MB_STRNICMP(tagp.tagname, st->orgpat.head, cmplen) != 0) continue; @@ -2874,14 +2842,12 @@ parse_line: if (vimconv.vc_type != CONV_NONE) convert_setup(&vimconv, NULL, NULL); -#ifdef FEAT_TAG_BINS tag_file_sorted = NUL; if (sort_error) { semsg(_(e_tags_file_not_sorted_str), st->tag_fname); sort_error = FALSE; } -#endif /* * Stop searching if sufficient tags have been found. @@ -2983,9 +2949,7 @@ find_tags( tagname_T tn; // info for get_tagfname() int first_file; // trying first tag file int retval = FAIL; // return value -#ifdef FEAT_TAG_BINS int round; -#endif int save_emsg_off; @@ -2995,10 +2959,8 @@ find_tags( char_u *saved_pat = NULL; // copy of pat[] #endif -#ifdef FEAT_TAG_BINS int findall = (mincount == MAXCOL || mincount == TAG_MANY); // find all matching tags -#endif int has_re = (flags & TAG_REGEXP); // regexp used int noic = (flags & TAG_NOIC); #ifdef FEAT_CSCOPE @@ -3101,15 +3063,11 @@ find_tags( * 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. */ -#ifdef FEAT_TAG_BINS 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); -#else - st.orgpat.regmatch.rm_ic = (p_ic || !noic); -#endif /* * Try tag file names from tags option one by one. @@ -3139,7 +3097,6 @@ find_tags( #endif tagname_free(&tn); -#ifdef FEAT_TAG_BINS // 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) || @@ -3153,7 +3110,6 @@ find_tags( // try another time while ignoring case st.orgpat.regmatch.rm_ic = TRUE; } -#endif if (!st.stop_searching) { diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -1503,4 +1503,77 @@ func Test_stag_close_window_on_error() set tags& 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 diff --git a/src/testdir/test_taglist.vim b/src/testdir/test_taglist.vim --- a/src/testdir/test_taglist.vim +++ b/src/testdir/test_taglist.vim @@ -37,6 +37,12 @@ func Test_taglist() call assert_equal('d', cmd[0]['kind']) 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 delete('Xtags') @@ -216,6 +222,11 @@ func Test_format_error() endtry 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& call delete('Xtags') endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -590,11 +590,7 @@ static char *(features[]) = #if defined(USE_SYSTEM) && defined(UNIX) "+system()", #endif -#ifdef FEAT_TAG_BINS "+tag_binary", -#else - "-tag_binary", -#endif "-tag_old_static", "-tag_any_white", #ifdef FEAT_TCL @@ -755,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4518, +/**/ 4517, /**/ 4516,