0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

patch 7.4.941

Problem:    There is no way to ignore case only for tag searches.
Solution:   Add the 'tagcase' option. (Gary Johnson)
This commit is contained in:
Bram Moolenaar
2015-11-24 18:48:14 +01:00
parent 2a1b474fd8
commit 0f6562e903
20 changed files with 254 additions and 24 deletions

View File

@@ -4109,7 +4109,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
Ignore case in search patterns. Also used when searching in the tags
file.
Also see 'smartcase'.
Also see 'smartcase' and 'tagcase'.
Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|.
@@ -7339,19 +7339,22 @@ A jump table for the options with a short description can be found at |Q_op|.
< [The whitespace before and after the '0' must be a single <Tab>]
When a binary search was done and no match was found in any of the
files listed in 'tags', and 'ignorecase' is set or a pattern is used
files listed in 'tags', and case is ignored or a pattern is used
instead of a normal tag name, a retry is done with a linear search.
Tags in unsorted tags files, and matches with different case will only
be found in the retry.
If a tag file indicates that it is case-fold sorted, the second,
linear search can be avoided for the 'ignorecase' case. Use a value
of '2' in the "!_TAG_FILE_SORTED" line for this. A tag file can be
case-fold sorted with the -f switch to "sort" in most unices, as in
the command: "sort -f -o tags tags". For "Exuberant ctags" version
5.x or higher (at least 5.5) the --sort=foldcase switch can be used
for this as well. Note that case must be folded to uppercase for this
to work.
linear search can be avoided when case is ignored. Use a value of '2'
in the "!_TAG_FILE_SORTED" line for this. A tag file can be case-fold
sorted with the -f switch to "sort" in most unices, as in the command:
"sort -f -o tags tags". For "Exuberant ctags" version 5.x or higher
(at least 5.5) the --sort=foldcase switch can be used for this as
well. Note that case must be folded to uppercase for this to work.
By default, tag searches are case-sensitive. Case is ignored when
'ignorecase' is set and 'tagcase' is "followic", or when 'tagcase' is
"ignore".
When 'tagbsearch' is off, tags searching is slower when a full match
exists, but faster when no full match exists. Tags in unsorted tags
@@ -7363,6 +7366,16 @@ 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}
*'tagcase'* *'tc'*
'tagcase' 'tc' string (default "followic")
global or local to buffer |global-local|
{not in Vi}
This option specifies how case is handled when searching the tags
file:
followic Follow the 'ignorecase' option
ignore Ignore case
match Match case
*'taglength'* *'tl'*
'taglength' 'tl' number (default 0)
global

View File

@@ -904,6 +904,7 @@ Short explanation of each option: *option-list*
'tabpagemax' 'tpm' maximum number of tab pages for |-p| and "tab all"
'tabstop' 'ts' number of spaces that <Tab> in file uses
'tagbsearch' 'tbs' use binary searching in tags files
'tagcase' 'tc' how to handle case when searching in tags files
'taglength' 'tl' number of significant characters for a tag
'tagrelative' 'tr' file names in tag file are relative
'tags' 'tag' list of file names used by the tag command

View File

@@ -85,11 +85,13 @@ changed, to avoid confusion when using ":tnext". It is changed when using
":tag {ident}".
The ignore-case matches are not found for a ":tag" command when the
'ignorecase' option is off. They are found when a pattern is used (starting
with a "/") and for ":tselect", also when 'ignorecase' is off. Note that
using ignore-case tag searching disables binary searching in the tags file,
which causes a slowdown. This can be avoided by fold-case sorting the tag
file. See the 'tagbsearch' option for an explanation.
'ignorecase' option is off and 'tagcase' is "followic" or when 'tagcase' is
"match". They are found when a pattern is used (starting with a "/") and for
":tselect", also when 'ignorecase' is off and 'tagcase' is "followic" or when
'tagcase' is "match". Note that using ignore-case tag searching disables
binary searching in the tags file, which causes a slowdown. This can be
avoided by fold-case sorting the tag file. See the 'tagbsearch' option for an
explanation.
==============================================================================
2. Tag stack *tag-stack* *tagstack* *E425*
@@ -440,12 +442,13 @@ file "tags". It can also be used to access a common tags file.
The next file in the list is not used when:
- A matching static tag for the current buffer has been found.
- A matching global tag has been found.
This also depends on the 'ignorecase' option. If it is off, and the tags file
only has a match without matching case, the next tags file is searched for a
match with matching case. If no tag with matching case is found, the first
match without matching case is used. If 'ignorecase' is on, and a matching
global tag with or without matching case is found, this one is used, no
further tags files are searched.
This also depends on whether case is ignored. Case is ignored when
'ignorecase' is set and 'tagcase' is "followic", or when 'tagcase' is
"ignore". If case is not ignored, and the tags file only has a match without
matching case, the next tags file is searched for a match with matching case.
If no tag with matching case is found, the first match without matching case
is used. If case is ignored, and a matching global tag with or without
matching case is found, this one is used, no further tags files are searched.
When a tag file name starts with "./", the '.' is replaced with the path of
the current file. This makes it possible to use a tags file in the directory
@@ -579,8 +582,10 @@ that indicates if the file was sorted. When this line is found, Vim uses
binary searching for the tags file:
!_TAG_FILE_SORTED<Tab>1<Tab>{anything} ~
A tag file may be case-fold sorted to avoid a linear search when 'ignorecase'
is on. See 'tagbsearch' for details. The value '2' should be used then:
A tag file may be case-fold sorted to avoid a linear search when case is
ignored. (Case is ignored when 'ignorecase' is set and 'tagcase' is
"followic", or when 'tagcase' is "ignore".) See 'tagbsearch' for details.
The value '2' should be used then:
!_TAG_FILE_SORTED<Tab>2<Tab>{anything} ~
The other tag that Vim recognizes, but only when compiled with the

View File

@@ -255,7 +255,8 @@ function.
RELATED ITEMS
You can set 'ignorecase' to make case in tag names be ignored.
To make case in tag names be ignored, you can set 'ignorecase' while leaving
'tagcase' as "followic", or set 'tagcase' to "ignore".
The 'tagbsearch' option tells if the tags file is sorted or not. The default
is to assume a sorted tags file, which makes a tags search a lot faster, but

View File

@@ -289,6 +289,10 @@ call append("$", " \tset tl=" . &tl)
call append("$", "tags\tlist of file names to search for tags")
call append("$", "\t(global or local to buffer)")
call <SID>OptionG("tag", &tag)
call append("$", "tagcase\thow to handle case when searching in tags files:")
call append("$", "\t\"followic\" to follow 'ignorecase', \"ignore\" or \"match\"")
call append("$", "\t(global or local to buffer)")
call <SID>OptionG("tc", &tc)
call append("$", "tagrelative\tfile names in a tags file are relative to the tags file")
call <SID>BinOptionG("tr", &tr)
call append("$", "tagstack\ta :tag command will use the tagstack")

View File

@@ -1930,6 +1930,7 @@ test1 \
test_search_mbyte \
test_set \
test_signs \
test_tagcase \
test_textobjects \
test_utf8 \
test_writefile \

View File

@@ -1991,6 +1991,7 @@ free_buf_options(buf, free_p_ff)
clear_string_option(&buf->b_p_ep);
clear_string_option(&buf->b_p_path);
clear_string_option(&buf->b_p_tags);
clear_string_option(&buf->b_p_tc);
#ifdef FEAT_INS_EXPAND
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);

View File

@@ -174,6 +174,7 @@
#define PV_SW OPT_BUF(BV_SW)
#define PV_SWF OPT_BUF(BV_SWF)
#define PV_TAGS OPT_BOTH(OPT_BUF(BV_TAGS))
#define PV_TC OPT_BOTH(OPT_BUF(BV_TC))
#define PV_TS OPT_BUF(BV_TS)
#define PV_TW OPT_BUF(BV_TW)
#define PV_TX OPT_BUF(BV_TX)
@@ -2602,6 +2603,9 @@ static struct vimoption
{(char_u *)TRUE, (char_u *)0L}
#endif
SCRIPTID_INIT},
{"tagcase", "tc", P_STRING|P_VIM,
(char_u *)&p_tc, PV_TC,
{(char_u *)"followic", (char_u *)"followic"} SCRIPTID_INIT},
{"taglength", "tl", P_NUM|P_VI_DEF,
(char_u *)&p_tl, PV_NONE,
{(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
@@ -5363,6 +5367,7 @@ didset_options()
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
#endif
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, FALSE);
#ifdef FEAT_VIRTUALEDIT
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE);
#endif
@@ -5525,6 +5530,7 @@ check_buf_options(buf)
check_string_option(&buf->b_p_ep);
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
check_string_option(&buf->b_p_tc);
#ifdef FEAT_INS_EXPAND
check_string_option(&buf->b_p_dict);
check_string_option(&buf->b_p_tsr);
@@ -7044,6 +7050,30 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
errmsg = e_invarg;
}
/* 'tagcase' */
else if (gvarp == &p_tc)
{
unsigned int *flags;
if (opt_flags & OPT_LOCAL)
{
p = curbuf->b_p_tc;
flags = &curbuf->b_tc_flags;
}
else
{
p = p_tc;
flags = &tc_flags;
}
if ((opt_flags & OPT_LOCAL) && *p == NUL)
/* make the local value empty: use the global value */
*flags = 0;
else if (*p == NUL
|| opt_strings_flags(p, p_tc_values, flags, FALSE) != OK)
errmsg = e_invarg;
}
#ifdef FEAT_MBYTE
/* 'casemap' */
else if (varp == &p_cmp)
@@ -10083,6 +10113,10 @@ unset_global_local_option(name, from)
case PV_TAGS:
clear_string_option(&buf->b_p_tags);
break;
case PV_TC:
clear_string_option(&buf->b_p_tc);
buf->b_tc_flags = 0;
break;
#ifdef FEAT_FIND_ID
case PV_DEF:
clear_string_option(&buf->b_p_def);
@@ -10164,6 +10198,7 @@ get_varp_scope(p, opt_flags)
case PV_PATH: return (char_u *)&(curbuf->b_p_path);
case PV_AR: return (char_u *)&(curbuf->b_p_ar);
case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
case PV_TC: return (char_u *)&(curbuf->b_p_tc);
#ifdef FEAT_FIND_ID
case PV_DEF: return (char_u *)&(curbuf->b_p_def);
case PV_INC: return (char_u *)&(curbuf->b_p_inc);
@@ -10218,6 +10253,8 @@ get_varp(p)
? (char_u *)&(curbuf->b_p_ar) : p->var;
case PV_TAGS: return *curbuf->b_p_tags != NUL
? (char_u *)&(curbuf->b_p_tags) : p->var;
case PV_TC: return *curbuf->b_p_tc != NUL
? (char_u *)&(curbuf->b_p_tc) : p->var;
case PV_BKC: return *curbuf->b_p_bkc != NUL
? (char_u *)&(curbuf->b_p_bkc) : p->var;
#ifdef FEAT_FIND_ID
@@ -10826,6 +10863,8 @@ buf_copy_options(buf, flags)
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
buf->b_p_tags = empty_option;
buf->b_p_tc = empty_option;
buf->b_tc_flags = 0;
#ifdef FEAT_FIND_ID
buf->b_p_def = empty_option;
buf->b_p_inc = empty_option;

View File

@@ -820,6 +820,14 @@ static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", "vsplit
#define SWB_NEWTAB 0x008
#define SWB_VSPLIT 0x010
EXTERN int p_tbs; /* 'tagbsearch' */
EXTERN char_u *p_tc; /* 'tagcase' */
EXTERN unsigned tc_flags; /* flags from 'tagcase' */
#ifdef IN_OPTION_C
static char *(p_tc_values[]) = {"followic", "ignore", "match", NULL};
#endif
#define TC_FOLLOWIC 0x01
#define TC_IGNORE 0x02
#define TC_MATCH 0x04
EXTERN long p_tl; /* 'taglength' */
EXTERN int p_tr; /* 'tagrelative' */
EXTERN char_u *p_tags; /* 'tags' */
@@ -1081,6 +1089,7 @@ enum
, BV_SW
, BV_SWF
, BV_TAGS
, BV_TC
, BV_TS
, BV_TW
, BV_TX

View File

@@ -1674,6 +1674,8 @@ struct file_buffer
char_u *b_p_path; /* 'path' local value */
int b_p_ar; /* 'autoread' local value */
char_u *b_p_tags; /* 'tags' local value */
char_u *b_p_tc; /* 'tagcase' local value */
unsigned b_tc_flags; /* flags for 'tagcase' */
#ifdef FEAT_INS_EXPAND
char_u *b_p_dict; /* 'dictionary' local value */
char_u *b_p_tsr; /* 'thesaurus' local value */
@@ -2063,7 +2065,7 @@ struct window_S
current virtual column */
/*
* the next six are used to update the visual part
* the next seven are used to update the visual part
*/
char w_old_visual_mode; /* last known VIsual_mode */
linenr_T w_old_cursor_lnum; /* last known end of visual part */

View File

@@ -1385,6 +1385,18 @@ find_tags(pat, num_matches, matchesp, flags, mincount, buf_ffname)
int use_cscope = (flags & TAG_CSCOPE);
#endif
int verbose = (flags & TAG_VERBOSE);
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;
}
help_save = curbuf->b_help;
orgpat.pat = pat;
@@ -2552,6 +2564,8 @@ findtag_end:
vim_free(saved_pat);
#endif
p_ic = save_p_ic;
return retval;
}

View File

@@ -66,6 +66,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out
@@ -221,5 +222,6 @@ test_ruby.out: test_ruby.in
test_search_mbyte.out: test_search_mbyte.in
test_set.out: test_set.in
test_signs.out: test_signs.in
test_tagcase.out: test_tagcase.in
test_textobjects.out: test_textobjects.in
test_utf8.out: test_utf8.in

View File

@@ -65,6 +65,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out

View File

@@ -87,6 +87,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out

View File

@@ -67,6 +67,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out

View File

@@ -126,6 +126,7 @@ SCRIPT = test1.out test2.out test3.out test4.out test5.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out

View File

@@ -63,6 +63,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test_search_mbyte.out \
test_set.out \
test_signs.out \
test_tagcase.out \
test_textobjects.out \
test_utf8.out

View File

@@ -0,0 +1,55 @@
Tests for 'tagcase' option
STARTTEST
:/^start text$/+1,/^end text$/w! Xtext
:/^start tags$/+1,/^end tags$/-1w! Xtags
:set tags=Xtags
:e Xtext
:"
:" Verify default values.
:set ic& | setg tc& | setl tc&
:call append('$', "ic=".&ic." g:tc=".&g:tc." l:tc=".&l:tc." tc=".&tc)
:"
:" Verify that the local setting accepts <empty> but that the global setting
:" does not. The first of these (setting the local value to <empty>) should
:" succeed; the other two should fail.
:let v:errmsg = ""
:setl tc=
:call append('$', v:errmsg)
:let v:errmsg = ""
:setg tc=
:call append('$', v:errmsg)
:let v:errmsg = ""
:set tc=
:call append('$', v:errmsg)
:"
:" Verify that the correct number of matching tags is found for all values of
:" 'ignorecase' and global and local values 'tagcase', in all combinations.
:for &ic in [0, 1]
: for &g:tc in ["followic", "ignore", "match"]
: for &l:tc in ["", "followic", "ignore", "match"]
: call append('$', "ic=".&ic." g:tc=".&g:tc." l:tc=".&l:tc." tc=".&tc)
: call append('$', len(taglist("^foo$")))
: call append('$', len(taglist("^Foo$")))
: endfor
: endfor
:endfor
:"
:1,/^end text$/d
:w! test.out
:qa!
ENDTEST
start text
Foo
Bar
foo
end text
start tags
Bar Xtext 3
Foo Xtext 2
foo Xtext 4
end tags

View File

@@ -0,0 +1,76 @@
ic=0 g:tc=followic l:tc=followic tc=followic
E474: Invalid argument: tc=
E474: Invalid argument: tc=
ic=0 g:tc=followic l:tc= tc=followic
1
1
ic=0 g:tc=followic l:tc=followic tc=followic
1
1
ic=0 g:tc=followic l:tc=ignore tc=ignore
2
2
ic=0 g:tc=followic l:tc=match tc=match
1
1
ic=0 g:tc=ignore l:tc= tc=ignore
2
2
ic=0 g:tc=ignore l:tc=followic tc=followic
1
1
ic=0 g:tc=ignore l:tc=ignore tc=ignore
2
2
ic=0 g:tc=ignore l:tc=match tc=match
1
1
ic=0 g:tc=match l:tc= tc=match
1
1
ic=0 g:tc=match l:tc=followic tc=followic
1
1
ic=0 g:tc=match l:tc=ignore tc=ignore
2
2
ic=0 g:tc=match l:tc=match tc=match
1
1
ic=1 g:tc=followic l:tc= tc=followic
2
2
ic=1 g:tc=followic l:tc=followic tc=followic
2
2
ic=1 g:tc=followic l:tc=ignore tc=ignore
2
2
ic=1 g:tc=followic l:tc=match tc=match
1
1
ic=1 g:tc=ignore l:tc= tc=ignore
2
2
ic=1 g:tc=ignore l:tc=followic tc=followic
2
2
ic=1 g:tc=ignore l:tc=ignore tc=ignore
2
2
ic=1 g:tc=ignore l:tc=match tc=match
1
1
ic=1 g:tc=match l:tc= tc=match
1
1
ic=1 g:tc=match l:tc=followic tc=followic
2
2
ic=1 g:tc=match l:tc=ignore tc=ignore
2
2
ic=1 g:tc=match l:tc=match tc=match
1
1

View File

@@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
941,
/**/
940,
/**/