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

patch 7.4.2230

Problem:    There is no equivalent of 'smartcase' for a tag search.
Solution:   Add value "followscs" and "smart" to 'tagcase'. (Christian
            Brabandt, closes #712) Turn tagcase test into new style.
This commit is contained in:
Bram Moolenaar 2016-08-20 16:57:02 +02:00
parent f04507d132
commit 66e29d7112
13 changed files with 131 additions and 156 deletions

View File

@ -7417,6 +7417,9 @@ A jump table for the options with a short description can be found at |Q_op|.
By default, tag searches are case-sensitive. Case is ignored when
'ignorecase' is set and 'tagcase' is "followic", or when 'tagcase' is
"ignore".
Also when 'tagcase' is "followscs" and 'smartcase' is set, or
'tagcase' is "smart", and the pattern contains only lowercase
characters.
When 'tagbsearch' is off, tags searching is slower when a full match
exists, but faster when no full match exists. Tags in unsorted tags
@ -7435,8 +7438,10 @@ A jump table for the options with a short description can be found at |Q_op|.
This option specifies how case is handled when searching the tags
file:
followic Follow the 'ignorecase' option
followscs Follow the 'smartcase' and 'ignorecase' options
ignore Ignore case
match Match case
smart Ignore case unless an upper case letter is used
*'taglength'* *'tl'*
'taglength' 'tl' number (default 0)

View File

@ -84,14 +84,23 @@ Note that when the current file changes, the priority list is mostly not
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 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.
The ignore-case matches are not found for a ":tag" command when:
- the 'ignorecase' option is off and 'tagcase' is "followic"
- 'tagcase' is "match"
- 'tagcase' is "smart" and the pattern contains an upper case character.
- 'tagcase' is "followscs" and 'smartcase' option is on and the pattern
contains an upper case character.
The gnore-case matches are found when:
- a pattern is used (starting with a "/")
- for ":tselect"
- when 'tagcase' is "followic" and 'ignorecase' is off
- when 'tagcase' is "match"
- when 'tagcase' is "followscs" and the 'smartcase' option 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.
==============================================================================
2. Tag stack *tag-stack* *tagstack* *E425*
@ -442,13 +451,18 @@ 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 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.
This also depends on whether case is ignored. Case is ignored when:
- 'tagcase' is "followic" and 'ignorecase' is set
- 'tagcase' is "ignore"
- 'tagcase' is "smart" and and the pattern only contains lower case
characters.
- 'tagcase' is "followscs" and 'smartcase' is set and and the pattern only
contains lower case characters.
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

View File

@ -2031,7 +2031,6 @@ test1 \
test_marks \
test_nested_function \
test_search_mbyte \
test_tagcase \
test_utf8 \
test_wordcount \
test_writefile \
@ -2123,6 +2122,7 @@ test_arglist \
test_syntax \
test_tabline \
test_tabpage \
test_tagcase \
test_tagjump \
test_textobjects \
test_timers \

View File

@ -822,11 +822,13 @@ 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};
static char *(p_tc_values[]) = {"followic", "ignore", "match", "followscs", "smart", NULL};
#endif
#define TC_FOLLOWIC 0x01
#define TC_IGNORE 0x02
#define TC_MATCH 0x04
#define TC_FOLLOWSCS 0x08
#define TC_SMART 0x10
EXTERN long p_tl; /* 'taglength' */
EXTERN int p_tr; /* 'tagrelative' */
EXTERN char_u *p_tags; /* 'tags' */

View File

@ -7,6 +7,7 @@ void save_search_patterns(void);
void restore_search_patterns(void);
void free_search_patterns(void);
int ignorecase(char_u *pat);
int ignorecase_opt(char_u *pat, int ic_in, int scs);
int pat_has_uppercase(char_u *pat);
char_u *last_csearch(void);
int last_csearch_forward(void);

View File

@ -367,9 +367,18 @@ free_search_patterns(void)
int
ignorecase(char_u *pat)
{
int ic = p_ic;
return ignorecase_opt(pat, p_ic, p_scs);
}
if (ic && !no_smartcase && p_scs
/*
* As ignorecase() put pass the "ic" and "scs" flags.
*/
int
ignorecase_opt(char_u *pat, int ic_in, int scs)
{
int ic = ic_in;
if (ic && !no_smartcase && scs
#ifdef FEAT_INS_EXPAND
&& !(ctrl_x_mode && curbuf->b_p_inf)
#endif

View File

@ -1385,9 +1385,11 @@ find_tags(
*/
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_FOLLOWIC: break;
case TC_IGNORE: p_ic = TRUE; break;
case TC_MATCH: p_ic = FALSE; break;
case TC_FOLLOWSCS: p_ic = ignorecase(pat); break;
case TC_SMART: p_ic = ignorecase_opt(pat, TRUE, TRUE); break;
}
help_save = curbuf->b_help;

View File

@ -100,7 +100,6 @@ SCRIPTS_ALL = \
test_marks.out \
test_nested_function.out \
test_search_mbyte.out \
test_tagcase.out \
test_utf8.out \
test_wordcount.out \
test_writefile.out

View File

@ -35,6 +35,7 @@ source test_statusline.vim
source test_syn_attr.vim
source test_tabline.vim
source test_tabpage.vim
source test_tagcase.vim
source test_tagjump.vim
source test_timers.vim
source test_true_false.vim

View File

@ -1,57 +0,0 @@
Tests for 'tagcase' option
STARTTEST
:so small.vim
:lang mess C
:/^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

@ -1,76 +0,0 @@
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

@ -0,0 +1,73 @@
" test 'tagcase' option
func Test_tagcase()
call writefile(["Bar\tXtext\t3", "Foo\tXtext\t2", "foo\tXtext\t4"], 'Xtags')
set tags=Xtags
e Xtext
for &ic in [0, 1]
for &scs in [0, 1]
for &g:tc in ["followic", "ignore", "match", "followscs", "smart"]
for &l:tc in ["", "followic", "ignore", "match", "followscs", "smart"]
let smart = 0
if &l:tc != ''
let tc = &l:tc
else
let tc = &g:tc
endif
if tc == 'followic'
let ic = &ic
elseif tc == 'ignore'
let ic = 1
elseif tc == 'followscs'
let ic = &ic
let smart = &scs
elseif tc == 'smart'
let ic = 1
let smart = 1
else
let ic = 0
endif
if ic && smart
call assert_equal(['foo', 'Foo'], map(taglist("^foo$"), {i, v -> v.name}))
call assert_equal(['Foo'], map(taglist("^Foo$"), {i, v -> v.name}))
elseif ic
call assert_equal(['foo', 'Foo'], map(taglist("^foo$"), {i, v -> v.name}))
call assert_equal(['Foo', 'foo'], map(taglist("^Foo$"), {i, v -> v.name}))
else
call assert_equal(['foo'], map(taglist("^foo$"), {i, v -> v.name}))
call assert_equal(['Foo'], map(taglist("^Foo$"), {i, v -> v.name}))
endif
endfor
endfor
endfor
endfor
call delete('Xtags')
set ic&
setg tc&
setl tc&
set scs&
endfunc
func Test_set_tagcase()
" Verify default values.
set ic&
setg tc&
setl tc&
call assert_equal(0, &ic)
call assert_equal('followic', &g:tc)
call assert_equal('followic', &l:tc)
call assert_equal('followic', &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.
setl tc=
call assert_fails('setg tc=', 'E474:')
call assert_fails('set tc=', 'E474:')
set ic&
setg tc&
setl tc&
endfunc

View File

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