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.

Raspunde prin e-mail lui