changeset 27986:c724906134a3 v8.2.4518

patch 8.2.4518: the binary tag search feature is always enabled Commit: https://github.com/vim/vim/commit/655b734ee858e90dd8d28549b7704a71b25d30e7 Author: Yegappan Lakshmanan <yegappan@yahoo.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Sun, 06 Mar 2022 15:30:06 +0100
parents 719dc5b9fc6e
children 250bf98317ea
files src/evalfunc.c src/feature.h src/tag.c src/testdir/test_tagjump.vim src/testdir/test_taglist.vim src/version.c
diffstat 6 files changed, 92 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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)
--- 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)
     {
--- 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
--- 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
--- 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,