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:
parent
f04507d132
commit
66e29d7112
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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' */
|
||||
|
@ -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);
|
||||
|
13
src/search.c
13
src/search.c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
73
src/testdir/test_tagcase.vim
Normal file
73
src/testdir/test_tagcase.vim
Normal 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
|
@ -763,6 +763,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2230,
|
||||
/**/
|
||||
2229,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user