From 934137fb489f0c99c32abe32e32f683e0ba3d40f Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 13:14:49 -0400 Subject: [PATCH 1/6] vim-patch:8.0.0116 Problem: When reading English help and using CTRl-] the language from 'helplang' is used. Solution: Make help tag jumps keep the language. (Tatsuki, test by Hirohito Higashi, closes vim/vim#1249) https://github.com/vim/vim/commit/6dbf66aa3e2197ce41f2b1cc7602bb9c15840548 --- src/nvim/tag.c | 26 ++++++++++++++++----- src/nvim/testdir/test_help_tagjump.vim | 32 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 2c70f396a1..9c9f24b9c0 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1135,6 +1135,7 @@ find_tags ( char_u *help_lang_find = NULL; /* lang to be found */ char_u help_lang[3]; /* lang of current tags file */ char_u *saved_pat = NULL; /* copy of pat[] */ + bool is_txt = false; pat_T orgpat; /* holds unconverted pattern info */ vimconv_T vimconv; @@ -1232,6 +1233,14 @@ find_tags ( * When the tag file is case-fold sorted, it is either one or the other. * Only ignore case when TAG_NOIC not used or 'ignorecase' set. */ + // Set a flag if the file extension is .txt + if ((flags & TAG_KEEP_LANG) + && help_lang_find == NULL + && curbuf->b_fname != NULL + && (i = (int)STRLEN(curbuf->b_fname)) > 4 + && STRICMP(curbuf->b_fname + i - 4, ".txt") == 0) { + is_txt = true; + } orgpat.regmatch.rm_ic = ((p_ic || !noic) && (findall || orgpat.headlen == 0 || !p_tbs)); for (round = 1; round <= 2; ++round) { @@ -1247,13 +1256,18 @@ find_tags ( fp = NULL; // avoid GCC warning } else { if (curbuf->b_help) { - /* Prefer help tags according to 'helplang'. Put the - * two-letter language name in help_lang[]. */ - i = (int)STRLEN(tag_fname); - if (i > 3 && tag_fname[i - 3] == '-') - STRCPY(help_lang, tag_fname + i - 2); - else + // Keep en if the file extension is .txt + if (is_txt) { STRCPY(help_lang, "en"); + } else { + /* Prefer help tags according to 'helplang'. Put the + * two-letter language name in help_lang[]. */ + i = (int)STRLEN(tag_fname); + if (i > 3 && tag_fname[i - 3] == '-') + STRCPY(help_lang, tag_fname + i - 2); + else + STRCPY(help_lang, "en"); + } /* When searching for a specific language skip tags files * for other languages. */ diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim index aabfe40537..1ca0f722cf 100644 --- a/src/nvim/testdir/test_help_tagjump.vim +++ b/src/nvim/testdir/test_help_tagjump.vim @@ -162,4 +162,36 @@ func Test_help_complete() endtry endfunc +func Test_help_respect_current_file_lang() + try + let list = [] + call s:doc_config_setup() + + if has('multi_lang') + function s:check_help_file_ext(help_keyword, ext) + exec 'help ' . a:help_keyword + call assert_equal(a:ext, expand('%:e')) + call feedkeys("\", 'tx') + call assert_equal(a:ext, expand('%:e')) + pop + helpclose + endfunc + + set rtp+=Xdir1/doc-ab + set rtp+=Xdir1/doc-ja + + set helplang=ab + call s:check_help_file_ext('test-char', 'abx') + call s:check_help_file_ext('test-char@ja', 'jax') + set helplang=ab,ja + call s:check_help_file_ext('test-char@ja', 'jax') + call s:check_help_file_ext('test-char@en', 'txt') + endif + catch + call assert_exception('X') + finally + call s:doc_config_teardown() + endtry +endfunc + " vim: shiftwidth=2 sts=2 expandtab From 058516aaf9c29b41bf27c8d4adfa2773c3896205 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 13:24:45 -0400 Subject: [PATCH 2/6] vim-patch:8.0.0190 Problem: Detecting duplicate tags uses a slow linear search. Solution: Use a much faster hash table solution. (James McCoy, closes vim/vim#1046) But don't add hi_keylen, it makes hash tables 50% bigger. https://github.com/vim/vim/commit/810f9c361c83afb36b9f1cdadca2b93f1201d039 --- src/nvim/tag.c | 239 ++++++++++++++++++++++++------------------------- 1 file changed, 116 insertions(+), 123 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 9c9f24b9c0..c3c2634598 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -73,9 +73,9 @@ typedef struct { } pat_T; /* - * The matching tags are first stored in ga_match[]. In which one depends on - * the priority of the match. - * At the end, the matches from ga_match[] are concatenated, to make a list + * The matching tags are first stored in one of the ht_match[] hash tables. In + * which one depends on the priority of the match. + * At the end, the matches from ht_match[] are concatenated, to make a list * sorted on priority. */ #define MT_ST_CUR 0 /* static match in current file */ @@ -1122,11 +1122,9 @@ find_tags ( int save_emsg_off; - struct match_found { - int len; /* nr of chars of match[] to be compared */ - char_u match[1]; /* actually longer */ - } *mfp, *mfp2; - garray_T ga_match[MT_COUNT]; + char_u *mfp; + hashtab_T ht_match[MT_COUNT]; + hash_T hash = 0; int match_count = 0; /* number of matches found */ char_u **matches; int mtt; @@ -1186,7 +1184,7 @@ find_tags ( lbuf = xmalloc(lbuf_size); tag_fname = xmalloc(MAXPATHL + 1); for (mtt = 0; mtt < MT_COUNT; ++mtt) - ga_init(&ga_match[mtt], (int)sizeof(struct match_found *), 100); + hash_init(&ht_match[mtt]); STRCPY(tag_fname, "from cscope"); /* for error messages */ @@ -1752,9 +1750,11 @@ parse_line: } /* - * If a match is found, add it to ga_match[]. + * If a match is found, add it to ht_match[]. */ if (match) { + int len = 0; + if (use_cscope) { /* Don't change the ordering, always use the same table. */ mtt = MT_GL_OTH; @@ -1790,116 +1790,102 @@ parse_line: } /* - * Add the found match in ga_match[mtt], avoiding duplicates. + * Add the found match in ht_match[mtt]. * Store the info we need later, which depends on the kind of * tags we are dealing with. */ - ga_grow(&ga_match[mtt], 1); - { - int len; - - if (help_only) { + if (help_only) { # define ML_EXTRA 3 - /* - * Append the help-heuristic number after the - * tagname, for sorting it later. - */ - *tagp.tagname_end = NUL; - len = (int)(tagp.tagname_end - tagp.tagname); - mfp = xmalloc(sizeof(struct match_found) + len + 10 + ML_EXTRA); - /* "len" includes the language and the NUL, but - * not the priority. */ - mfp->len = len + ML_EXTRA + 1; -#define ML_HELP_LEN 6 - p = mfp->match; - STRCPY(p, tagp.tagname); - p[len] = '@'; - STRCPY(p + len + 1, help_lang); - sprintf((char *)p + len + 1 + ML_EXTRA, "%06d", - help_heuristic(tagp.tagname, - match_re ? matchoff : 0, !match_no_ic) - + help_pri - ); + // Append the help-heuristic number after the tagname, for + // sorting it later. The heuristic is ignored for + // detecting duplicates. + // The format is {tagname}@{lang}NUL{heuristic}NUL + *tagp.tagname_end = NUL; + len = (int)(tagp.tagname_end - tagp.tagname); + mfp = xmalloc(sizeof(char_u) + len + 10 + ML_EXTRA + 1); - *tagp.tagname_end = TAB; - } else if (name_only) { - if (get_it_again) { - char_u *temp_end = tagp.command; + p = mfp; + STRCPY(p, tagp.tagname); + p[len] = '@'; + STRCPY(p + len + 1, help_lang); + sprintf((char *)p + len + 1 + ML_EXTRA, "%06d", + help_heuristic(tagp.tagname, + match_re ? matchoff : 0, !match_no_ic) + + help_pri); - if (*temp_end == '/') - while (*temp_end && *temp_end != '\r' - && *temp_end != '\n' - && *temp_end != '$') - temp_end++; + *tagp.tagname_end = TAB; + } else if (name_only) { + if (get_it_again) { + char_u *temp_end = tagp.command; - if (tagp.command + 2 < temp_end) { - len = (int)(temp_end - tagp.command - 2); - mfp = xmalloc(sizeof(struct match_found) + len); - mfp->len = len + 1; /* include the NUL */ - p = mfp->match; - STRLCPY(p, tagp.command + 2, len + 1); - } else - mfp = NULL; - get_it_again = FALSE; - } else { - len = (int)(tagp.tagname_end - tagp.tagname); - mfp = xmalloc(sizeof(struct match_found) + len); - mfp->len = len + 1; /* include the NUL */ - p = mfp->match; - STRLCPY(p, tagp.tagname, len + 1); + if (*temp_end == '/') + while (*temp_end && *temp_end != '\r' + && *temp_end != '\n' + && *temp_end != '$') + temp_end++; - /* if wanted, re-read line to get long form too */ - if (State & INSERT) - get_it_again = p_sft; - } - } else { - /* Save the tag in a buffer. - * Emacs tag: - * other tag: - * without Emacs tags: - */ - len = (int)STRLEN(tag_fname) - + (int)STRLEN(lbuf) + 3; - mfp = xmalloc(sizeof(struct match_found) + len); - mfp->len = len; - p = mfp->match; - p[0] = mtt; - STRCPY(p + 1, tag_fname); -#ifdef BACKSLASH_IN_FILENAME - /* Ignore differences in slashes, avoid adding - * both path/file and path\file. */ - slash_adjust(p + 1); -#endif - s = p + 1 + STRLEN(tag_fname) + 1; - STRCPY(s, lbuf); - } - - if (mfp != NULL) { - /* - * Don't add identical matches. - * This can take a lot of time when finding many - * matches, check for CTRL-C now and then. - * Add all cscope tags, because they are all listed. - */ - if (use_cscope) - i = -1; - else - for (i = ga_match[mtt].ga_len; --i >= 0 && !got_int; ) { - mfp2 = ((struct match_found **) - (ga_match[mtt].ga_data))[i]; - if (mfp2->len == mfp->len - && memcmp(mfp2->match, mfp->match, - (size_t)mfp->len) == 0) - break; - fast_breakcheck(); - } - if (i < 0) { - ((struct match_found **)(ga_match[mtt].ga_data)) - [ga_match[mtt].ga_len++] = mfp; - ++match_count; + if (tagp.command + 2 < temp_end) { + len = (int)(temp_end - tagp.command - 2); + mfp = xmalloc(sizeof(char_u) + len + 1); + STRLCPY(mfp, tagp.command + 2, len + 1); } else - xfree(mfp); + mfp = NULL; + get_it_again = FALSE; + } else { + len = (int)(tagp.tagname_end - tagp.tagname); + mfp = xmalloc(sizeof(char_u) + len + 1); + STRLCPY(mfp, tagp.tagname, len + 1); + + /* if wanted, re-read line to get long form too */ + if (State & INSERT) + get_it_again = p_sft; } + } else { +#define TAG_SEP 0x01 + size_t tag_fname_len = STRLEN(tag_fname); + /* Save the tag in a buffer. + * Use 0x01 to separate fields (Can't use NUL, because the + * hash key is terminated by NUL). + * Emacs tag: + * other tag: + * without Emacs tags: + */ + len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3; + mfp = xmalloc(sizeof(char_u) + len + 1); + p = mfp; + p[0] = mtt; + STRCPY(p + 1, tag_fname); +#ifdef BACKSLASH_IN_FILENAME + /* Ignore differences in slashes, avoid adding + * both path/file and path\file. */ + slash_adjust(p + 1); +#endif + p[tag_fname_len + 1] = TAG_SEP; + s = p + 1 + tag_fname_len + 1; + STRCPY(s, lbuf); + } + + if (mfp != NULL) { + hashitem_T *hi; + + // Don't add identical matches. + // Add all cscope tags, because they are all listed. + // "mfp" is used as a hash key, there is a NUL byte to end + // the part matters for comparing, more bytes may follow + // after it. E.g. help tags store the priority after the + // NUL. + if (use_cscope) + hash++; + else + hash = hash_hash(mfp); + hi = hash_lookup(&ht_match[mtt], (const char *)mfp, + STRLEN(mfp), hash); + if (HASHITEM_EMPTY(hi)) { + hash_add_item(&ht_match[mtt], hi, mfp, hash); + ++match_count; + } else + // duplicate tag, drop it + xfree(mfp); } } if (use_cscope && eof) @@ -1962,7 +1948,7 @@ findtag_end: xfree(tag_fname); /* - * Move the matches from the ga_match[] arrays into one list of + * Move the matches from the ht_match[] arrays into one list of * matches. When retval == FAIL, free the matches. */ if (retval == FAIL) @@ -1974,20 +1960,27 @@ findtag_end: matches = NULL; match_count = 0; for (mtt = 0; mtt < MT_COUNT; ++mtt) { - for (int i = 0; i < ga_match[mtt].ga_len; ++i) { - mfp = ((struct match_found **)(ga_match[mtt].ga_data))[i]; - if (matches == NULL) - xfree(mfp); - else { - /* To avoid allocating memory again we turn the struct - * match_found into a string. For help the priority was not - * included in the length. */ - memmove(mfp, mfp->match, - (size_t)(mfp->len + (help_only ? ML_HELP_LEN : 0))); - matches[match_count++] = (char_u *)mfp; + hashitem_T *hi; + long todo = (long)ht_match[mtt].ht_used; + + for (hi = ht_match[mtt].ht_array; todo > 0; hi++) { + if (!HASHITEM_EMPTY(hi)) { + mfp = hi->hi_key; + if (matches == NULL) { + xfree(mfp); + } else { + // now change the TAG_SEP back to NUL + for (p = mfp; *p != NUL; p++) { + if (*p == TAG_SEP) { + *p = NUL; + } + } + matches[match_count++] = (char_u *)mfp; + } + todo--; } } - ga_clear(&ga_match[mtt]); + hash_clear(&ht_match[mtt]); } *matchesp = matches; From e1af49b425f25024a3e6361ed576cf69296a1da4 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 14:50:00 -0400 Subject: [PATCH 3/6] vim-patch:8.0.0195 Problem: Jumping to a tag that is a static item in the current file fails. (Kazunobu Kuriyama) Solution: Make sure the first byte of the tag key is not NUL. (Suggested by James McCoy, closes vim/vim#1387) https://github.com/vim/vim/commit/a9d23c20879d0dcb289a4db54b3c7df060f87c3c --- src/nvim/tag.c | 22 ++++++++++++---------- src/nvim/testdir/test_tagjump.vim | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index c3c2634598..92a535ab91 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -82,10 +82,6 @@ typedef struct { #define MT_GL_CUR 1 /* global match in current file */ #define MT_GL_OTH 2 /* global match in other file */ #define MT_ST_OTH 3 /* static match in other file */ -#define MT_IC_ST_CUR 4 /* icase static match in current file */ -#define MT_IC_GL_CUR 5 /* icase global match in current file */ -#define MT_IC_GL_OTH 6 /* icase global match in other file */ -#define MT_IC_ST_OTH 7 /* icase static match in other file */ #define MT_IC_OFF 4 /* add for icase match */ #define MT_RE_OFF 8 /* add for regexp match */ #define MT_MASK 7 /* mask for printing priority */ @@ -1826,7 +1822,7 @@ parse_line: if (tagp.command + 2 < temp_end) { len = (int)(temp_end - tagp.command - 2); - mfp = xmalloc(sizeof(char_u) + len + 1); + mfp = xmalloc(len + 2); STRLCPY(mfp, tagp.command + 2, len + 1); } else mfp = NULL; @@ -1849,11 +1845,12 @@ parse_line: * Emacs tag: * other tag: * without Emacs tags: + * Here is the "mtt" value plus 1 to avoid NUL. */ len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3; mfp = xmalloc(sizeof(char_u) + len + 1); p = mfp; - p[0] = mtt; + p[0] = mtt + 1; STRCPY(p + 1, tag_fname); #ifdef BACKSLASH_IN_FILENAME /* Ignore differences in slashes, avoid adding @@ -1969,10 +1966,15 @@ findtag_end: if (matches == NULL) { xfree(mfp); } else { - // now change the TAG_SEP back to NUL - for (p = mfp; *p != NUL; p++) { - if (*p == TAG_SEP) { - *p = NUL; + if (!name_only) { + // Change mtt back to zero-based. + *mfp = *mfp - 1; + + // change the TAG_SEP back to NUL + for (p = mfp + 1; *p != NUL; p++) { + if (*p == TAG_SEP) { + *p = NUL; + } } } matches[match_count++] = (char_u *)mfp; diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim index 678ad0ada8..54b5f4afd6 100644 --- a/src/nvim/testdir/test_tagjump.vim +++ b/src/nvim/testdir/test_tagjump.vim @@ -23,4 +23,22 @@ func Test_cancel_ptjump() quit endfunc +func Test_static_tagjump() + set tags=Xtags + call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", + \ "one\tXfile1\t/^one/;\"\tf\tfile:\tsignature:(void)", + \ "word\tXfile2\tcmd2"], + \ 'Xtags') + new Xfile1 + call setline(1, ['empty', 'one()', 'empty']) + write + tag one + call assert_equal(2, line('.')) + + set tags& + call delete('Xtags') + call delete('Xfile1') + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab From d3f15f1e6d299796bd552896c0ba01a7cca58618 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 15:08:26 -0400 Subject: [PATCH 4/6] vim-patch:8.0.0223 Problem: Coverity gets confused by the flags passed to find_tags() and warnts for an uninitialized variable. Solution: Disallow using cscope and help tags at the same time. https://github.com/vim/vim/commit/fffbf308dd98d1129ba4914d921ab47dc6a6c9b1 --- src/nvim/tag.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 92a535ab91..1cbf789270 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1057,6 +1057,7 @@ static void prepare_pats(pat_T *pats, int has_re) * TAG_REGEXP use "pat" as a regexp * TAG_NOIC don't always ignore case * TAG_KEEP_LANG keep language + * TAG_CSCOPE use cscope results for tags */ int find_tags ( @@ -1189,6 +1190,11 @@ find_tags ( */ if (help_only) /* want tags from help file */ curbuf->b_help = true; /* will be restored later */ + else if (use_cscope) { + // Make sure we don't mix help and cscope, confuses Coverity. + help_only = false; + curbuf->b_help = false; + } orgpat.len = (int)STRLEN(pat); if (curbuf->b_help) { From 097d04ac71499f5ba0126ab6f731d4f4af0a4e84 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 15:10:27 -0400 Subject: [PATCH 5/6] vim-patch:8.0.0393 Problem: When the same tag appears more than once, the order is unpredictable. (Charles Campbell) Solution: Besides using a dict for finding duplicates, use a grow array for keeping the tags in sequence. https://github.com/vim/vim/commit/98e83b295628bc29bc67bcc1adb8ae75d01b8e07 --- src/nvim/tag.c | 55 ++++++++++++++++--------------- src/nvim/testdir/test_tagjump.vim | 24 ++++++++++++++ 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 1cbf789270..0d5008b4ce 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -73,9 +73,10 @@ typedef struct { } pat_T; /* - * The matching tags are first stored in one of the ht_match[] hash tables. In + * The matching tags are first stored in one of the hash tables. In * which one depends on the priority of the match. - * At the end, the matches from ht_match[] are concatenated, to make a list + * ht_match[] is used to find duplicates, ga_match[] to keep them in sequence. + * At the end, the matches from ga_match[] are concatenated, to make a list * sorted on priority. */ #define MT_ST_CUR 0 /* static match in current file */ @@ -1120,7 +1121,8 @@ find_tags ( char_u *mfp; - hashtab_T ht_match[MT_COUNT]; + garray_T ga_match[MT_COUNT]; // stores matches in sequence + hashtab_T ht_match[MT_COUNT]; // stores matches by key hash_T hash = 0; int match_count = 0; /* number of matches found */ char_u **matches; @@ -1180,8 +1182,10 @@ find_tags ( */ lbuf = xmalloc(lbuf_size); tag_fname = xmalloc(MAXPATHL + 1); - for (mtt = 0; mtt < MT_COUNT; ++mtt) + for (mtt = 0; mtt < MT_COUNT; ++mtt) { + ga_init(&ga_match[mtt], sizeof(char_u *), 100); hash_init(&ht_match[mtt]); + } STRCPY(tag_fname, "from cscope"); /* for error messages */ @@ -1752,7 +1756,7 @@ parse_line: } /* - * If a match is found, add it to ht_match[]. + * If a match is found, add it to ht_match[] and ga_match[]. */ if (match) { int len = 0; @@ -1792,7 +1796,7 @@ parse_line: } /* - * Add the found match in ht_match[mtt]. + * Add the found match in ht_match[mtt] and ga_match[mtt]. * Store the info we need later, which depends on the kind of * tags we are dealing with. */ @@ -1885,6 +1889,9 @@ parse_line: STRLEN(mfp), hash); if (HASHITEM_EMPTY(hi)) { hash_add_item(&ht_match[mtt], hi, mfp, hash); + ga_grow(&ga_match[mtt], 1); + ((char_u **)(ga_match[mtt].ga_data)) + [ga_match[mtt].ga_len++] = mfp; ++match_count; } else // duplicate tag, drop it @@ -1951,7 +1958,7 @@ findtag_end: xfree(tag_fname); /* - * Move the matches from the ht_match[] arrays into one list of + * Move the matches from the ga_match[] arrays into one list of * matches. When retval == FAIL, free the matches. */ if (retval == FAIL) @@ -1963,31 +1970,27 @@ findtag_end: matches = NULL; match_count = 0; for (mtt = 0; mtt < MT_COUNT; ++mtt) { - hashitem_T *hi; - long todo = (long)ht_match[mtt].ht_used; + for (i = 0; i < ga_match[mtt].ga_len; i++) { + mfp = ((char_u **)(ga_match[mtt].ga_data))[i]; + if (matches == NULL) { + xfree(mfp); + } else { + if (!name_only) { + // Change mtt back to zero-based. + *mfp = *mfp - 1; - for (hi = ht_match[mtt].ht_array; todo > 0; hi++) { - if (!HASHITEM_EMPTY(hi)) { - mfp = hi->hi_key; - if (matches == NULL) { - xfree(mfp); - } else { - if (!name_only) { - // Change mtt back to zero-based. - *mfp = *mfp - 1; - - // change the TAG_SEP back to NUL - for (p = mfp + 1; *p != NUL; p++) { - if (*p == TAG_SEP) { - *p = NUL; - } + // change the TAG_SEP back to NUL + for (p = mfp + 1; *p != NUL; p++) { + if (*p == TAG_SEP) { + *p = NUL; } } - matches[match_count++] = (char_u *)mfp; } - todo--; + matches[match_count++] = (char_u *)mfp; } } + + ga_clear(&ga_match[mtt]); hash_clear(&ht_match[mtt]); } diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim index 54b5f4afd6..2044c23f79 100644 --- a/src/nvim/testdir/test_tagjump.vim +++ b/src/nvim/testdir/test_tagjump.vim @@ -35,10 +35,34 @@ func Test_static_tagjump() tag one call assert_equal(2, line('.')) + bwipe! set tags& call delete('Xtags') call delete('Xfile1') +endfunc + +func Test_duplicate_tagjump() + set tags=Xtags + call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", + \ "thesame\tXfile1\t1;\"\td\tfile:", + \ "thesame\tXfile1\t2;\"\td\tfile:", + \ "thesame\tXfile1\t3;\"\td\tfile:", + \ ], + \ 'Xtags') + new Xfile1 + call setline(1, ['thesame one', 'thesame two', 'thesame three']) + write + tag thesame + call assert_equal(1, line('.')) + tnext + call assert_equal(2, line('.')) + tnext + call assert_equal(3, line('.')) + bwipe! + set tags& + call delete('Xtags') + call delete('Xfile1') endfunc " vim: shiftwidth=2 sts=2 expandtab From a56615214dbbc4b2f9cf38f65f95172a2ef06289 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 19 Mar 2017 21:00:45 -0400 Subject: [PATCH 6/6] lint --- src/nvim/tag.c | 118 ++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 0d5008b4ce..7bcaff662c 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -72,20 +72,18 @@ typedef struct { regmatch_T regmatch; /* regexp program, may be NULL */ } pat_T; -/* - * The matching tags are first stored in one of the hash tables. In - * which one depends on the priority of the match. - * ht_match[] is used to find duplicates, ga_match[] to keep them in sequence. - * At the end, the matches from ga_match[] are concatenated, to make a list - * sorted on priority. - */ -#define MT_ST_CUR 0 /* static match in current file */ -#define MT_GL_CUR 1 /* global match in current file */ -#define MT_GL_OTH 2 /* global match in other file */ -#define MT_ST_OTH 3 /* static match in other file */ -#define MT_IC_OFF 4 /* add for icase match */ -#define MT_RE_OFF 8 /* add for regexp match */ -#define MT_MASK 7 /* mask for printing priority */ +// The matching tags are first stored in one of the hash tables. In +// which one depends on the priority of the match. +// ht_match[] is used to find duplicates, ga_match[] to keep them in sequence. +// At the end, the matches from ga_match[] are concatenated, to make a list +// sorted on priority. +#define MT_ST_CUR 0 // static match in current file +#define MT_GL_CUR 1 // global match in current file +#define MT_GL_OTH 2 // global match in other file +#define MT_ST_OTH 3 // static match in other file +#define MT_IC_OFF 4 // add for icase match +#define MT_RE_OFF 8 // add for regexp match +#define MT_MASK 7 // mask for printing priority #define MT_COUNT 16 static char *mt_names[MT_COUNT/2] = @@ -1124,14 +1122,14 @@ find_tags ( garray_T ga_match[MT_COUNT]; // stores matches in sequence hashtab_T ht_match[MT_COUNT]; // stores matches by key hash_T hash = 0; - int match_count = 0; /* number of matches found */ + int match_count = 0; // number of matches found char_u **matches; int mtt; int help_save; int help_pri = 0; - char_u *help_lang_find = NULL; /* lang to be found */ - char_u help_lang[3]; /* lang of current tags file */ - char_u *saved_pat = NULL; /* copy of pat[] */ + char_u *help_lang_find = NULL; // lang to be found + char_u help_lang[3]; // lang of current tags file + char_u *saved_pat = NULL; // copy of pat[] bool is_txt = false; pat_T orgpat; /* holds unconverted pattern info */ @@ -1182,7 +1180,7 @@ find_tags ( */ lbuf = xmalloc(lbuf_size); tag_fname = xmalloc(MAXPATHL + 1); - for (mtt = 0; mtt < MT_COUNT; ++mtt) { + for (mtt = 0; mtt < MT_COUNT; mtt++) { ga_init(&ga_match[mtt], sizeof(char_u *), 100); hash_init(&ht_match[mtt]); } @@ -1192,9 +1190,9 @@ find_tags ( /* * Initialize a few variables */ - if (help_only) /* want tags from help file */ - curbuf->b_help = true; /* will be restored later */ - else if (use_cscope) { + if (help_only) { // want tags from help file + curbuf->b_help = true; // will be restored later + } else if (use_cscope) { // Make sure we don't mix help and cscope, confuses Coverity. help_only = false; curbuf->b_help = false; @@ -1264,13 +1262,14 @@ find_tags ( if (is_txt) { STRCPY(help_lang, "en"); } else { - /* Prefer help tags according to 'helplang'. Put the - * two-letter language name in help_lang[]. */ + // Prefer help tags according to 'helplang'. Put the + // two-letter language name in help_lang[]. i = (int)STRLEN(tag_fname); - if (i > 3 && tag_fname[i - 3] == '-') + if (i > 3 && tag_fname[i - 3] == '-') { STRCPY(help_lang, tag_fname + i - 2); - else + } else { STRCPY(help_lang, "en"); + } } /* When searching for a specific language skip tags files @@ -1755,9 +1754,7 @@ parse_line: match_re = TRUE; } - /* - * If a match is found, add it to ht_match[] and ga_match[]. - */ + // If a match is found, add it to ht_match[] and ga_match[]. if (match) { int len = 0; @@ -1795,11 +1792,9 @@ parse_line: mtt += MT_RE_OFF; } - /* - * Add the found match in ht_match[mtt] and ga_match[mtt]. - * Store the info we need later, which depends on the kind of - * tags we are dealing with. - */ + // Add the found match in ht_match[mtt] and ga_match[mtt]. + // Store the info we need later, which depends on the kind of + // tags we are dealing with. if (help_only) { # define ML_EXTRA 3 // Append the help-heuristic number after the tagname, for @@ -1814,57 +1809,60 @@ parse_line: STRCPY(p, tagp.tagname); p[len] = '@'; STRCPY(p + len + 1, help_lang); - sprintf((char *)p + len + 1 + ML_EXTRA, "%06d", - help_heuristic(tagp.tagname, - match_re ? matchoff : 0, !match_no_ic) - + help_pri); + snprintf((char *)p + len + 1 + ML_EXTRA, 10, "%06d", + help_heuristic(tagp.tagname, + match_re ? matchoff : 0, !match_no_ic) + + help_pri); *tagp.tagname_end = TAB; } else if (name_only) { if (get_it_again) { char_u *temp_end = tagp.command; - if (*temp_end == '/') + if (*temp_end == '/') { while (*temp_end && *temp_end != '\r' && *temp_end != '\n' - && *temp_end != '$') + && *temp_end != '$') { temp_end++; + } + } if (tagp.command + 2 < temp_end) { len = (int)(temp_end - tagp.command - 2); mfp = xmalloc(len + 2); STRLCPY(mfp, tagp.command + 2, len + 1); - } else + } else { mfp = NULL; - get_it_again = FALSE; + } + get_it_again = false; } else { len = (int)(tagp.tagname_end - tagp.tagname); mfp = xmalloc(sizeof(char_u) + len + 1); STRLCPY(mfp, tagp.tagname, len + 1); - /* if wanted, re-read line to get long form too */ - if (State & INSERT) + // if wanted, re-read line to get long form too + if (State & INSERT) { get_it_again = p_sft; + } } } else { #define TAG_SEP 0x01 size_t tag_fname_len = STRLEN(tag_fname); - /* Save the tag in a buffer. - * Use 0x01 to separate fields (Can't use NUL, because the - * hash key is terminated by NUL). - * Emacs tag: - * other tag: - * without Emacs tags: - * Here is the "mtt" value plus 1 to avoid NUL. - */ + // Save the tag in a buffer. + // Use 0x01 to separate fields (Can't use NUL, because the + // hash key is terminated by NUL). + // Emacs tag: + // other tag: + // without Emacs tags: + // Here is the "mtt" value plus 1 to avoid NUL. len = (int)tag_fname_len + (int)STRLEN(lbuf) + 3; mfp = xmalloc(sizeof(char_u) + len + 1); p = mfp; p[0] = mtt + 1; STRCPY(p + 1, tag_fname); #ifdef BACKSLASH_IN_FILENAME - /* Ignore differences in slashes, avoid adding - * both path/file and path\file. */ + // Ignore differences in slashes, avoid adding + // both path/file and path\file. slash_adjust(p + 1); #endif p[tag_fname_len + 1] = TAG_SEP; @@ -1881,10 +1879,11 @@ parse_line: // the part matters for comparing, more bytes may follow // after it. E.g. help tags store the priority after the // NUL. - if (use_cscope) + if (use_cscope) { hash++; - else + } else { hash = hash_hash(mfp); + } hi = hash_lookup(&ht_match[mtt], (const char *)mfp, STRLEN(mfp), hash); if (HASHITEM_EMPTY(hi)) { @@ -1892,10 +1891,11 @@ parse_line: ga_grow(&ga_match[mtt], 1); ((char_u **)(ga_match[mtt].ga_data)) [ga_match[mtt].ga_len++] = mfp; - ++match_count; - } else + match_count++; + } else { // duplicate tag, drop it xfree(mfp); + } } } if (use_cscope && eof) @@ -1969,7 +1969,7 @@ findtag_end: else matches = NULL; match_count = 0; - for (mtt = 0; mtt < MT_COUNT; ++mtt) { + for (mtt = 0; mtt < MT_COUNT; mtt++) { for (i = 0; i < ga_match[mtt].ga_len; i++) { mfp = ((char_u **)(ga_match[mtt].ga_data))[i]; if (matches == NULL) {