diff options
-rw-r--r-- | src/nvim/tag.c | 57 | ||||
-rw-r--r-- | src/nvim/testdir/test_tagjump.vim | 24 |
2 files changed, 54 insertions, 27 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 (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; - } + 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; + + // 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 |