To: vim_dev@googlegroups.com Subject: Patch 7.4.2230 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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. Files: runtime/doc/options.txt, runtime/doc/tagsrch.txt, src/option.h, src/tag.c, src/search.c, src/proto/search.pro, src/testdir/test_tagcase.in, src/testdir/test_tagcase.ok, src/testdir/test_tagcase.vim, src/Makefile, src/testdir/Make_all.mak, src/testdir/test_alot.vim *** ../vim-7.4.2229/runtime/doc/options.txt 2016-08-14 19:54:16.324930218 +0200 --- runtime/doc/options.txt 2016-08-20 16:17:45.435665366 +0200 *************** *** 7375,7380 **** --- 7417,7425 ---- 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 *************** *** 7393,7400 **** --- 7438,7447 ---- 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) *** ../vim-7.4.2229/runtime/doc/tagsrch.txt 2015-11-24 18:45:52.633647066 +0100 --- runtime/doc/tagsrch.txt 2016-08-20 16:24:45.035950333 +0200 *************** *** 84,97 **** 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. ============================================================================== 2. Tag stack *tag-stack* *tagstack* *E425* --- 84,106 ---- 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" ! - '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,454 **** 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. 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 --- 451,468 ---- 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: ! - '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 *** ../vim-7.4.2229/src/option.h 2016-08-12 18:29:36.610738320 +0200 --- src/option.h 2016-08-20 16:25:42.063445094 +0200 *************** *** 822,832 **** 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}; #endif #define TC_FOLLOWIC 0x01 #define TC_IGNORE 0x02 #define TC_MATCH 0x04 EXTERN long p_tl; /* 'taglength' */ EXTERN int p_tr; /* 'tagrelative' */ EXTERN char_u *p_tags; /* 'tags' */ --- 822,834 ---- 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", "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' */ *** ../vim-7.4.2229/src/tag.c 2016-08-12 16:29:03.347068413 +0200 --- src/tag.c 2016-08-20 16:40:01.675745662 +0200 *************** *** 1385,1393 **** */ 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; } help_save = curbuf->b_help; --- 1385,1395 ---- */ 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_FOLLOWSCS: p_ic = ignorecase(pat); break; ! case TC_SMART: p_ic = ignorecase_opt(pat, TRUE, TRUE); break; } help_save = curbuf->b_help; *** ../vim-7.4.2229/src/search.c 2016-07-24 17:32:41.877505078 +0200 --- src/search.c 2016-08-20 16:36:49.649488868 +0200 *************** *** 367,375 **** int ignorecase(char_u *pat) { ! int ic = p_ic; ! if (ic && !no_smartcase && p_scs #ifdef FEAT_INS_EXPAND && !(ctrl_x_mode && curbuf->b_p_inf) #endif --- 367,384 ---- int ignorecase(char_u *pat) { ! return ignorecase_opt(pat, p_ic, 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 *** ../vim-7.4.2229/src/proto/search.pro 2016-01-19 13:21:55.845334290 +0100 --- src/proto/search.pro 2016-08-20 16:36:47.257510589 +0200 *************** *** 7,12 **** --- 7,13 ---- 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); *** ../vim-7.4.2229/src/testdir/test_tagcase.in 2015-12-03 20:46:16.462602318 +0100 --- src/testdir/test_tagcase.in 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,57 **** - 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 but that the global setting - :" does not. The first of these (setting the local value to ) 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 --- 0 ---- *** ../vim-7.4.2229/src/testdir/test_tagcase.ok 2015-11-24 18:45:52.641646980 +0100 --- src/testdir/test_tagcase.ok 1970-01-01 01:00:00.000000000 +0100 *************** *** 1,76 **** - 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 --- 0 ---- *** ../vim-7.4.2229/src/testdir/test_tagcase.vim 2016-08-20 16:54:30.039875281 +0200 --- src/testdir/test_tagcase.vim 2016-08-20 16:41:35.618893238 +0200 *************** *** 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 but that the global setting + " does not. The first of these (setting the local value to ) 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 *** ../vim-7.4.2229/src/Makefile 2016-08-18 22:11:27.036228825 +0200 --- src/Makefile 2016-08-20 16:08:16.752731752 +0200 *************** *** 2031,2037 **** test_marks \ test_nested_function \ test_search_mbyte \ - test_tagcase \ test_utf8 \ test_wordcount \ test_writefile \ --- 2031,2036 ---- *************** *** 2123,2128 **** --- 2122,2128 ---- test_syntax \ test_tabline \ test_tabpage \ + test_tagcase \ test_tagjump \ test_textobjects \ test_timers \ *** ../vim-7.4.2229/src/testdir/Make_all.mak 2016-08-18 22:11:27.036228825 +0200 --- src/testdir/Make_all.mak 2016-08-20 16:08:31.280600234 +0200 *************** *** 100,106 **** test_marks.out \ test_nested_function.out \ test_search_mbyte.out \ - test_tagcase.out \ test_utf8.out \ test_wordcount.out \ test_writefile.out --- 100,105 ---- *** ../vim-7.4.2229/src/testdir/test_alot.vim 2016-08-18 22:11:27.036228825 +0200 --- src/testdir/test_alot.vim 2016-08-20 16:08:57.404363754 +0200 *************** *** 35,40 **** --- 35,41 ---- 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 *** ../vim-7.4.2229/src/version.c 2016-08-20 15:05:35.566703103 +0200 --- src/version.c 2016-08-20 16:15:23.224923437 +0200 *************** *** 765,766 **** --- 765,768 ---- { /* Add new patch number below this line */ + /**/ + 2230, /**/ -- It is hard to understand how a cemetery raised its burial cost and blamed it on the cost of living. /// Bram Moolenaar -- Bram@Moolenaar.net -- 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 ///