mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.0088: insufficient tests for tags; bug in using extra tag field
Problem: Insufficient tests for tags; bug in using extra tag field when using an ex command to position the cursor. Solution: Fix the bug, add more tests. (Yegappan Lakshmanan, closes #5439)
This commit is contained in:
@@ -344,11 +344,11 @@ the same as above, with a "p" prepended.
|
||||
A static tag is a tag that is defined for a specific file. In a C program
|
||||
this could be a static function.
|
||||
|
||||
In Vi jumping to a tag sets the current search pattern. This means that
|
||||
the "n" command after jumping to a tag does not search for the same pattern
|
||||
that it did before jumping to the tag. Vim does not do this as we consider it
|
||||
to be a bug. You can still find the tag search pattern in the search history.
|
||||
If you really want the old Vi behavior, set the 't' flag in 'cpoptions'.
|
||||
In Vi jumping to a tag sets the current search pattern. This means that the
|
||||
"n" command after jumping to a tag does not search for the same pattern that
|
||||
it did before jumping to the tag. Vim does not do this as we consider it to
|
||||
be a bug. If you really want the old Vi behavior, set the 't' flag in
|
||||
'cpoptions'.
|
||||
|
||||
*tag-binary-search*
|
||||
Vim uses binary searching in the tags file to find the desired tag quickly
|
||||
@@ -426,8 +426,7 @@ would otherwise go unnoticed. Example: >
|
||||
|
||||
In Vi the ":tag" command sets the last search pattern when the tag is searched
|
||||
for. In Vim this is not done, the previous search pattern is still remembered,
|
||||
unless the 't' flag is present in 'cpoptions'. The search pattern is always
|
||||
put in the search history, so you can modify it if searching fails.
|
||||
unless the 't' flag is present in 'cpoptions'.
|
||||
|
||||
*emacs-tags* *emacs_tags* *E430*
|
||||
Emacs style tag files are only supported if Vim was compiled with the
|
||||
|
@@ -3808,6 +3808,7 @@ test_for_current(
|
||||
find_extra(char_u **pp)
|
||||
{
|
||||
char_u *str = *pp;
|
||||
char_u first_char = **pp;
|
||||
|
||||
// Repeat for addresses separated with ';'
|
||||
for (;;)
|
||||
@@ -3817,7 +3818,7 @@ find_extra(char_u **pp)
|
||||
else if (*str == '/' || *str == '?')
|
||||
{
|
||||
str = skip_regexp(str + 1, *str, FALSE, NULL);
|
||||
if (*str != **pp)
|
||||
if (*str != first_char)
|
||||
str = NULL;
|
||||
else
|
||||
++str;
|
||||
@@ -3837,6 +3838,7 @@ find_extra(char_u **pp)
|
||||
|| !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?'))
|
||||
break;
|
||||
++str; // skip ';'
|
||||
first_char = *str;
|
||||
}
|
||||
|
||||
if (str != NULL && STRNCMP(str, ";\"", 2) == 0)
|
||||
|
@@ -432,3 +432,31 @@ func Test_pum_with_preview_win()
|
||||
call StopVimInTerminal(buf)
|
||||
call delete('Xpreviewscript')
|
||||
endfunc
|
||||
|
||||
" Test for inserting the tag search pattern in insert mode
|
||||
func Test_ins_compl_tag_sft()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfoo\t/^int first() {}$/",
|
||||
\ "second\tXfoo\t/^int second() {}$/",
|
||||
\ "third\tXfoo\t/^int third() {}$/"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int second() {}
|
||||
int third() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
enew
|
||||
set showfulltag
|
||||
exe "normal isec\<C-X>\<C-]>\<C-N>\<CR>"
|
||||
call assert_equal('int second() {}', getline(1))
|
||||
set noshowfulltag
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
@@ -81,4 +81,28 @@ func Test_tagfunc()
|
||||
call delete('Xfile1')
|
||||
endfunc
|
||||
|
||||
" Test for modifying the tag stack from a tag function and jumping to a tag
|
||||
" from a tag function
|
||||
func Test_tagfunc_settagstack()
|
||||
func Mytagfunc1(pat, flags, info)
|
||||
call settagstack(1, {'tagname' : 'mytag', 'from' : [0, 10, 1, 0]})
|
||||
return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
|
||||
endfunc
|
||||
set tagfunc=Mytagfunc1
|
||||
call writefile([''], 'Xtest')
|
||||
call assert_fails('tag xyz', 'E986:')
|
||||
|
||||
func Mytagfunc2(pat, flags, info)
|
||||
tag test_tag
|
||||
return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
|
||||
endfunc
|
||||
set tagfunc=Mytagfunc2
|
||||
call assert_fails('tag xyz', 'E986:')
|
||||
|
||||
call delete('Xtest')
|
||||
set tagfunc&
|
||||
delfunc Mytagfunc1
|
||||
delfunc Mytagfunc2
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@@ -578,4 +578,293 @@ func Test_tagline()
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" Test for expanding environment variable in a tag file name
|
||||
func Test_tag_envvar()
|
||||
call writefile(["Func1\t$FOO\t/^Func1/"], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let $FOO='TagTestEnv'
|
||||
|
||||
let caught_exception = v:false
|
||||
try
|
||||
tag Func1
|
||||
catch /E429:/
|
||||
call assert_match('E429:.*"TagTestEnv".*', v:exception)
|
||||
let caught_exception = v:true
|
||||
endtry
|
||||
call assert_true(caught_exception)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
unlet $FOO
|
||||
endfunc
|
||||
|
||||
" Test for :ptag
|
||||
func Test_ptag()
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "second\tXfile1\t2",
|
||||
\ "third\tXfile1\t3",],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
call writefile(['first', 'second', 'third'], 'Xfile1')
|
||||
|
||||
enew | only
|
||||
ptag third
|
||||
call assert_equal(2, winnr())
|
||||
call assert_equal(2, winnr('$'))
|
||||
call assert_equal(1, getwinvar(1, '&previewwindow'))
|
||||
call assert_equal(0, getwinvar(2, '&previewwindow'))
|
||||
wincmd w
|
||||
call assert_equal(3, line('.'))
|
||||
|
||||
" jump to the tag again
|
||||
ptag third
|
||||
call assert_equal(3, line('.'))
|
||||
|
||||
" close the preview window
|
||||
pclose
|
||||
call assert_equal(1, winnr('$'))
|
||||
|
||||
call delete('Xfile1')
|
||||
call delete('Xtags')
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" Tests for guessing the tag location
|
||||
func Test_tag_guess()
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "func1\tXfoo\t/^int func1(int x)/",
|
||||
\ "func2\tXfoo\t/^int func2(int y)/",
|
||||
\ "func3\tXfoo\t/^func3/",
|
||||
\ "func4\tXfoo\t/^func4/"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
|
||||
int FUNC1 (int x) { }
|
||||
int
|
||||
func2 (int y) { }
|
||||
int * func3 () { }
|
||||
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
let v:statusmsg = ''
|
||||
ta func1
|
||||
call assert_match('E435:', v:statusmsg)
|
||||
call assert_equal(2, line('.'))
|
||||
let v:statusmsg = ''
|
||||
ta func2
|
||||
call assert_match('E435:', v:statusmsg)
|
||||
call assert_equal(4, line('.'))
|
||||
let v:statusmsg = ''
|
||||
ta func3
|
||||
call assert_match('E435:', v:statusmsg)
|
||||
call assert_equal(5, line('.'))
|
||||
call assert_fails('ta func4', 'E434:')
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" Test for an unsorted tags file
|
||||
func Test_tag_sort()
|
||||
call writefile([
|
||||
\ "first\tXfoo\t1",
|
||||
\ "ten\tXfoo\t3",
|
||||
\ "six\tXfoo\t2"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int six() {}
|
||||
int ten() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
call assert_fails('tag first', 'E432:')
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" Test for an unsorted tags file
|
||||
func Test_tag_fold()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "!_TAG_FILE_SORTED\t2\t/0=unsorted, 1=sorted, 2=foldcase/",
|
||||
\ "first\tXfoo\t1",
|
||||
\ "second\tXfoo\t2",
|
||||
\ "third\tXfoo\t3"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int second() {}
|
||||
int third() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
enew
|
||||
tag second
|
||||
call assert_equal('Xfoo', bufname(''))
|
||||
call assert_equal(2, line('.'))
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" Test for the :ltag command
|
||||
func Test_ltag()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfoo\t1",
|
||||
\ "second\tXfoo\t/^int second() {}$/",
|
||||
\ "third\tXfoo\t3"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int second() {}
|
||||
int third() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
enew
|
||||
call setloclist(0, [], 'f')
|
||||
ltag third
|
||||
call assert_equal('Xfoo', bufname(''))
|
||||
call assert_equal(3, line('.'))
|
||||
call assert_equal([{'lnum': 3, 'bufnr': bufnr('Xfoo'), 'col': 0,
|
||||
\ 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '',
|
||||
\ 'module': '', 'text': 'third'}], getloclist(0))
|
||||
|
||||
ltag second
|
||||
call assert_equal(2, line('.'))
|
||||
call assert_equal([{'lnum': 0, 'bufnr': bufnr('Xfoo'), 'col': 0,
|
||||
\ 'pattern': '^\Vint second() {}\$', 'valid': 1, 'vcol': 0, 'nr': 0,
|
||||
\ 'type': '', 'module': '', 'text': 'second'}], getloclist(0))
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" Test for setting the last search pattern to the tag search pattern
|
||||
" when cpoptions has 't'
|
||||
func Test_tag_last_search_pat()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfoo\t/^int first() {}/",
|
||||
\ "second\tXfoo\t/^int second() {}/",
|
||||
\ "third\tXfoo\t/^int third() {}/"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int second() {}
|
||||
int third() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
enew
|
||||
let save_cpo = &cpo
|
||||
set cpo+=t
|
||||
let @/ = ''
|
||||
tag second
|
||||
call assert_equal('^int second() {}', @/)
|
||||
let &cpo = save_cpo
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" Test for jumping to a tag when the tag stack is full
|
||||
func Test_tag_stack_full()
|
||||
let l = []
|
||||
for i in range(10, 31)
|
||||
let l += ["var" .. i .. "\tXfoo\t/^int var" .. i .. ";$/"]
|
||||
endfor
|
||||
call writefile(l, 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let l = []
|
||||
for i in range(10, 31)
|
||||
let l += ["int var" .. i .. ";"]
|
||||
endfor
|
||||
call writefile(l, 'Xfoo')
|
||||
|
||||
enew
|
||||
for i in range(10, 30)
|
||||
exe "tag var" .. i
|
||||
endfor
|
||||
let l = gettagstack()
|
||||
call assert_equal(20, l.length)
|
||||
call assert_equal('var11', l.items[0].tagname)
|
||||
tag var31
|
||||
let l = gettagstack()
|
||||
call assert_equal('var12', l.items[0].tagname)
|
||||
call assert_equal('var31', l.items[19].tagname)
|
||||
|
||||
" Jump from the top of the stack
|
||||
call assert_fails('tag', 'E556:')
|
||||
|
||||
" Pop from an unsaved buffer
|
||||
enew!
|
||||
call append(1, "sample text")
|
||||
call assert_fails('pop', 'E37:')
|
||||
call assert_equal(21, gettagstack().curidx)
|
||||
enew!
|
||||
|
||||
" Pop all the entries in the tag stack
|
||||
call assert_fails('30pop', 'E555:')
|
||||
|
||||
" Pop the tag stack when it is empty
|
||||
call settagstack(1, {'items' : []})
|
||||
call assert_fails('pop', 'E73:')
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" Test for browsing multiple matching tags
|
||||
func Test_tag_multimatch()
|
||||
call writefile([
|
||||
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfoo\t1",
|
||||
\ "first\tXfoo\t2",
|
||||
\ "first\tXfoo\t3"],
|
||||
\ 'Xtags')
|
||||
set tags=Xtags
|
||||
let code =<< trim [CODE]
|
||||
int first() {}
|
||||
int first() {}
|
||||
int first() {}
|
||||
[CODE]
|
||||
call writefile(code, 'Xfoo')
|
||||
|
||||
tag first
|
||||
tlast
|
||||
call assert_equal(3, line('.'))
|
||||
call assert_fails('tnext', 'E428:')
|
||||
tfirst
|
||||
call assert_equal(1, line('.'))
|
||||
call assert_fails('tprev', 'E425:')
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfoo')
|
||||
set tags&
|
||||
%bwipe
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@@ -115,3 +115,99 @@ func Test_tagsfile_without_trailing_newline()
|
||||
call delete('Xtags')
|
||||
set tags&
|
||||
endfunc
|
||||
|
||||
" Test for ignoring comments in a tags file
|
||||
func Test_tagfile_ignore_comments()
|
||||
call writefile([
|
||||
\ "!_TAG_PROGRAM_NAME /Test tags generator/",
|
||||
\ "FBar\tXfoo\t2" .. ';"' .. "\textrafield\tf",
|
||||
\ "!_TAG_FILE_FORMAT 2 /extended format/",
|
||||
\ ], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let l = taglist('.*')
|
||||
call assert_equal(1, len(l))
|
||||
call assert_equal('FBar', l[0].name)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
endfunc
|
||||
|
||||
" Test for using an excmd in a tags file to position the cursor (instead of a
|
||||
" search pattern or a line number)
|
||||
func Test_tagfile_excmd()
|
||||
call writefile([
|
||||
\ "vFoo\tXfoo\tcall cursor(3, 4)" .. '|;"' .. "\tv",
|
||||
\ ], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let l = taglist('.*')
|
||||
call assert_equal([{
|
||||
\ 'cmd' : 'call cursor(3, 4)',
|
||||
\ 'static' : 0,
|
||||
\ 'name' : 'vFoo',
|
||||
\ 'kind' : 'v',
|
||||
\ 'filename' : 'Xfoo'}], l)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
endfunc
|
||||
|
||||
" Test for duplicate fields in a tag in a tags file
|
||||
func Test_duplicate_field()
|
||||
call writefile([
|
||||
\ "vFoo\tXfoo\t4" .. ';"' .. "\ttypename:int\ttypename:int\tv",
|
||||
\ ], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let l = taglist('.*')
|
||||
call assert_equal([{
|
||||
\ 'cmd' : '4',
|
||||
\ 'static' : 0,
|
||||
\ 'name' : 'vFoo',
|
||||
\ 'kind' : 'v',
|
||||
\ 'typename' : 'int',
|
||||
\ 'filename' : 'Xfoo'}], l)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
endfunc
|
||||
|
||||
" Test for tag address with ;
|
||||
func Test_tag_addr_with_semicolon()
|
||||
call writefile([
|
||||
\ "Func1\tXfoo\t6;/^Func1/" .. ';"' .. "\tf"
|
||||
\ ], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let l = taglist('.*')
|
||||
call assert_equal([{
|
||||
\ 'cmd' : '6;/^Func1/',
|
||||
\ 'static' : 0,
|
||||
\ 'name' : 'Func1',
|
||||
\ 'kind' : 'f',
|
||||
\ 'filename' : 'Xfoo'}], l)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
endfunc
|
||||
|
||||
" Test for format error in a tags file
|
||||
func Test_format_error()
|
||||
call writefile(['vFoo-Xfoo-4'], 'Xtags')
|
||||
set tags=Xtags
|
||||
|
||||
let caught_exception = v:false
|
||||
try
|
||||
let l = taglist('.*')
|
||||
catch /E431:/
|
||||
" test succeeded
|
||||
let caught_exception = v:true
|
||||
catch
|
||||
call assert_report('Caught ' . v:exception . ' in ' . v:throwpoint)
|
||||
endtry
|
||||
call assert_true(caught_exception)
|
||||
|
||||
set tags&
|
||||
call delete('Xtags')
|
||||
endfunc
|
||||
|
@@ -742,6 +742,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
88,
|
||||
/**/
|
||||
87,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user