forked from aniani/vim
patch 8.0.0393: order of duplicate tags is not preserved
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.
This commit is contained in:
parent
e0c31f6a30
commit
98e83b2956
60
src/tag.c
60
src/tag.c
@ -35,9 +35,10 @@ typedef struct tag_pointers
|
|||||||
} tagptrs_T;
|
} tagptrs_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.
|
* which one depends on the priority of the match.
|
||||||
* At the end, all 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, all the matches from ga_match[] are concatenated, to make a list
|
||||||
* sorted on priority.
|
* sorted on priority.
|
||||||
*/
|
*/
|
||||||
#define MT_ST_CUR 0 /* static match in current file */
|
#define MT_ST_CUR 0 /* static match in current file */
|
||||||
@ -1339,7 +1340,8 @@ find_tags(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
char_u *mfp;
|
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;
|
hash_T hash = 0;
|
||||||
int match_count = 0; /* number of matches found */
|
int match_count = 0; /* number of matches found */
|
||||||
char_u **matches;
|
char_u **matches;
|
||||||
@ -1405,7 +1407,10 @@ find_tags(
|
|||||||
ebuf = alloc(LSIZE);
|
ebuf = alloc(LSIZE);
|
||||||
#endif
|
#endif
|
||||||
for (mtt = 0; mtt < MT_COUNT; ++mtt)
|
for (mtt = 0; mtt < MT_COUNT; ++mtt)
|
||||||
|
{
|
||||||
|
ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100);
|
||||||
hash_init(&ht_match[mtt]);
|
hash_init(&ht_match[mtt]);
|
||||||
|
}
|
||||||
|
|
||||||
/* check for out of memory situation */
|
/* check for out of memory situation */
|
||||||
if (lbuf == NULL || tag_fname == NULL
|
if (lbuf == NULL || tag_fname == NULL
|
||||||
@ -2213,7 +2218,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)
|
if (match)
|
||||||
{
|
{
|
||||||
@ -2271,7 +2276,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
|
* Store the info we need later, which depends on the kind of
|
||||||
* tags we are dealing with.
|
* tags we are dealing with.
|
||||||
*/
|
*/
|
||||||
@ -2423,7 +2428,8 @@ parse_line:
|
|||||||
if (HASHITEM_EMPTY(hi))
|
if (HASHITEM_EMPTY(hi))
|
||||||
{
|
{
|
||||||
if (hash_add_item(&ht_match[mtt], hi, mfp, hash)
|
if (hash_add_item(&ht_match[mtt], hi, mfp, hash)
|
||||||
== FAIL)
|
== FAIL
|
||||||
|
|| ga_grow(&ga_match[mtt], 1) != OK)
|
||||||
{
|
{
|
||||||
/* Out of memory! Just forget about the rest. */
|
/* Out of memory! Just forget about the rest. */
|
||||||
retval = OK;
|
retval = OK;
|
||||||
@ -2431,7 +2437,11 @@ parse_line:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
((char_u **)(ga_match[mtt].ga_data))
|
||||||
|
[ga_match[mtt].ga_len++] = mfp;
|
||||||
++match_count;
|
++match_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* duplicate tag, drop it */
|
/* duplicate tag, drop it */
|
||||||
@ -2533,7 +2543,7 @@ findtag_end:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
* matches. When retval == FAIL, free the matches.
|
||||||
*/
|
*/
|
||||||
if (retval == FAIL)
|
if (retval == FAIL)
|
||||||
@ -2547,34 +2557,28 @@ findtag_end:
|
|||||||
match_count = 0;
|
match_count = 0;
|
||||||
for (mtt = 0; mtt < MT_COUNT; ++mtt)
|
for (mtt = 0; mtt < MT_COUNT; ++mtt)
|
||||||
{
|
{
|
||||||
hashitem_T *hi;
|
for (i = 0; i < ga_match[mtt].ga_len; ++i)
|
||||||
long_u todo;
|
|
||||||
|
|
||||||
todo = (long)ht_match[mtt].ht_used;
|
|
||||||
for (hi = ht_match[mtt].ht_array; todo > 0; ++hi)
|
|
||||||
{
|
{
|
||||||
if (!HASHITEM_EMPTY(hi))
|
mfp = ((char_u **)(ga_match[mtt].ga_data))[i];
|
||||||
|
if (matches == NULL)
|
||||||
|
vim_free(mfp);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
mfp = hi->hi_key;
|
if (!name_only)
|
||||||
if (matches == NULL)
|
|
||||||
vim_free(mfp);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (!name_only)
|
/* Change mtt back to zero-based. */
|
||||||
{
|
*mfp = *mfp - 1;
|
||||||
/* Change mtt back to zero-based. */
|
|
||||||
*mfp = *mfp - 1;
|
|
||||||
|
|
||||||
/* change the TAG_SEP back to NUL */
|
/* change the TAG_SEP back to NUL */
|
||||||
for (p = mfp + 1; *p != NUL; ++p)
|
for (p = mfp + 1; *p != NUL; ++p)
|
||||||
if (*p == TAG_SEP)
|
if (*p == TAG_SEP)
|
||||||
*p = NUL;
|
*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]);
|
hash_clear(&ht_match[mtt]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,10 +35,34 @@ func Test_static_tagjump()
|
|||||||
tag one
|
tag one
|
||||||
call assert_equal(2, line('.'))
|
call assert_equal(2, line('.'))
|
||||||
|
|
||||||
|
bwipe!
|
||||||
set tags&
|
set tags&
|
||||||
call delete('Xtags')
|
call delete('Xtags')
|
||||||
call delete('Xfile1')
|
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!
|
bwipe!
|
||||||
|
set tags&
|
||||||
|
call delete('Xtags')
|
||||||
|
call delete('Xfile1')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Tests for [ CTRL-I and CTRL-W CTRL-I commands
|
" Tests for [ CTRL-I and CTRL-W CTRL-I commands
|
||||||
|
@ -764,6 +764,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
393,
|
||||||
/**/
|
/**/
|
||||||
392,
|
392,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user