Patch 8.2.0088
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)
Files: runtime/doc/tagsrch.txt, src/tag.c,
src/testdir/test_ins_complete.vim, src/testdir/test_tagfunc.vim,
src/testdir/test_tagjump.vim, src/testdir/test_taglist.vim
*** ../vim-8.2.0087/runtime/doc/tagsrch.txt 2019-12-12 12:49:06.000000000
+0100
--- runtime/doc/tagsrch.txt 2020-01-05 20:28:54.700971203 +0100
***************
*** 344,354 ****
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'.
*tag-binary-search*
Vim uses binary searching in the tags file to find the desired tag quickly
--- 344,354 ----
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. 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,433 ****
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.
*emacs-tags* *emacs_tags* *E430*
Emacs style tag files are only supported if Vim was compiled with the
--- 426,432 ----
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'.
*emacs-tags* *emacs_tags* *E430*
Emacs style tag files are only supported if Vim was compiled with the
*** ../vim-8.2.0087/src/tag.c 2020-01-02 14:02:12.316159489 +0100
--- src/tag.c 2020-01-05 20:28:54.700971203 +0100
***************
*** 3808,3813 ****
--- 3808,3814 ----
find_extra(char_u **pp)
{
char_u *str = *pp;
+ char_u first_char = **pp;
// Repeat for addresses separated with ';'
for (;;)
***************
*** 3817,3823 ****
else if (*str == '/' || *str == '?')
{
str = skip_regexp(str + 1, *str, FALSE, NULL);
! if (*str != **pp)
str = NULL;
else
++str;
--- 3818,3824 ----
else if (*str == '/' || *str == '?')
{
str = skip_regexp(str + 1, *str, FALSE, NULL);
! if (*str != first_char)
str = NULL;
else
++str;
***************
*** 3837,3842 ****
--- 3838,3844 ----
|| !(VIM_ISDIGIT(str[1]) || str[1] == '/' || str[1] == '?'))
break;
++str; // skip ';'
+ first_char = *str;
}
if (str != NULL && STRNCMP(str, ";\"", 2) == 0)
*** ../vim-8.2.0087/src/testdir/test_ins_complete.vim 2020-01-04
14:32:35.522717984 +0100
--- src/testdir/test_ins_complete.vim 2020-01-05 20:28:54.700971203 +0100
***************
*** 432,434 ****
--- 432,462 ----
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
*** ../vim-8.2.0087/src/testdir/test_tagfunc.vim 2019-04-28
17:48:10.000000000 +0200
--- src/testdir/test_tagfunc.vim 2020-01-05 20:28:54.700971203 +0100
***************
*** 81,84 ****
--- 81,108 ----
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
*** ../vim-8.2.0087/src/testdir/test_tagjump.vim 2020-01-02
14:02:12.316159489 +0100
--- src/testdir/test_tagjump.vim 2020-01-05 20:28:54.700971203 +0100
***************
*** 578,581 ****
--- 578,870 ----
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
*** ../vim-8.2.0087/src/testdir/test_taglist.vim 2019-09-08
18:09:15.000000000 +0200
--- src/testdir/test_taglist.vim 2020-01-05 20:28:54.700971203 +0100
***************
*** 115,117 ****
--- 115,213 ----
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
*** ../vim-8.2.0087/src/version.c 2020-01-05 14:38:37.110600924 +0100
--- src/version.c 2020-01-05 20:32:05.072265610 +0100
***************
*** 744,745 ****
--- 744,747 ----
{ /* Add new patch number below this line */
+ /**/
+ 88,
/**/
--
ARTHUR: No, hang on! Just answer the five questions ...
GALAHAD: Three questions ...
ARTHUR: Three questions ... And we shall watch ... and pray.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202001051936.005JaLXF020605%40masaka.moolenaar.net.