To: vim_dev@googlegroups.com Subject: Patch 8.0.0393 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0393 (after 8.0.0190) 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. Files: src/tag.c, src/testdir/test_tagjump.vim *** ../vim-8.0.0392/src/tag.c 2017-01-23 20:47:09.037078522 +0100 --- src/tag.c 2017-03-01 15:38:25.293498562 +0100 *************** *** 35,43 **** } tagptrs_T; /* ! * 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, all the matches from ht_match[] are concatenated, to make a list * sorted on priority. */ #define MT_ST_CUR 0 /* static match in current file */ --- 35,44 ---- } tagptrs_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, all the matches from ga_match[] are concatenated, to make a list * sorted on priority. */ #define MT_ST_CUR 0 /* static match in current file */ *************** *** 1339,1345 **** #endif char_u *mfp; ! hashtab_T ht_match[MT_COUNT]; hash_T hash = 0; int match_count = 0; /* number of matches found */ char_u **matches; --- 1340,1347 ---- #endif char_u *mfp; ! 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; *************** *** 1405,1411 **** --- 1407,1416 ---- ebuf = alloc(LSIZE); #endif for (mtt = 0; mtt < MT_COUNT; ++mtt) + { + ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100); hash_init(&ht_match[mtt]); + } /* check for out of memory situation */ if (lbuf == NULL || tag_fname == NULL *************** *** 2213,2219 **** } /* ! * If a match is found, add it to ht_match[]. */ if (match) { --- 2218,2224 ---- } /* ! * If a match is found, add it to ht_match[] and ga_match[]. */ if (match) { *************** *** 2271,2277 **** } /* ! * 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. */ --- 2276,2282 ---- } /* ! * 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. */ *************** *** 2423,2429 **** if (HASHITEM_EMPTY(hi)) { if (hash_add_item(&ht_match[mtt], hi, mfp, hash) ! == FAIL) { /* Out of memory! Just forget about the rest. */ retval = OK; --- 2428,2435 ---- if (HASHITEM_EMPTY(hi)) { if (hash_add_item(&ht_match[mtt], hi, mfp, hash) ! == FAIL ! || ga_grow(&ga_match[mtt], 1) != OK) { /* Out of memory! Just forget about the rest. */ retval = OK; *************** *** 2431,2437 **** --- 2437,2447 ---- break; } else + { + ((char_u **)(ga_match[mtt].ga_data)) + [ga_match[mtt].ga_len++] = mfp; ++match_count; + } } else /* duplicate tag, drop it */ *************** *** 2533,2539 **** #endif /* ! * Move the matches from the ht_match[] arrays into one list of * matches. When retval == FAIL, free the matches. */ if (retval == FAIL) --- 2543,2549 ---- #endif /* ! * Move the matches from the ga_match[] arrays into one list of * matches. When retval == FAIL, free the matches. */ if (retval == FAIL) *************** *** 2547,2580 **** match_count = 0; for (mtt = 0; mtt < MT_COUNT; ++mtt) { ! hashitem_T *hi; ! 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 = hi->hi_key; ! if (matches == NULL) ! vim_free(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--; } } hash_clear(&ht_match[mtt]); } --- 2557,2584 ---- match_count = 0; 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) ! vim_free(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; } } + + ga_clear(&ga_match[mtt]); hash_clear(&ht_match[mtt]); } *** ../vim-8.0.0392/src/testdir/test_tagjump.vim 2017-01-16 20:53:31.154599637 +0100 --- src/testdir/test_tagjump.vim 2017-03-01 15:25:28.362478203 +0100 *************** *** 35,44 **** --- 35,68 ---- 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 " Tests for [ CTRL-I and CTRL-W CTRL-I commands *** ../vim-8.0.0392/src/version.c 2017-03-01 15:07:01.345621994 +0100 --- src/version.c 2017-03-01 15:27:14.853795967 +0100 *************** *** 766,767 **** --- 766,769 ---- { /* Add new patch number below this line */ + /**/ + 393, /**/ -- To define recursion, we must first define recursion. /// 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 ///