comparison src/tag.c @ 11008:0ecd07cd2e43 v8.0.0393

patch 8.0.0393: order of duplicate tags is not preserved commit https://github.com/vim/vim/commit/98e83b295628bc29bc67bcc1adb8ae75d01b8e07 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Mar 1 15:45:05 2017 +0100 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.
author Christian Brabandt <cb@256bit.org>
date Wed, 01 Mar 2017 16:00:05 +0100
parents ed6f03535745
children 778c10516955
comparison
equal deleted inserted replaced
11007:14a0d274348d 11008:0ecd07cd2e43
33 char_u *tagkind; /* "kind:" value */ 33 char_u *tagkind; /* "kind:" value */
34 char_u *tagkind_end; /* end of tagkind */ 34 char_u *tagkind_end; /* end of tagkind */
35 } tagptrs_T; 35 } tagptrs_T;
36 36
37 /* 37 /*
38 * The matching tags are first stored in one of the ht_match[] hash tables. In 38 * The matching tags are first stored in one of the hash tables. In
39 * which one depends on the priority of the match. 39 * which one depends on the priority of the match.
40 * At the end, all the matches from ht_match[] are concatenated, to make a list 40 * ht_match[] is used to find duplicates, ga_match[] to keep them in sequence.
41 * At the end, all the matches from ga_match[] are concatenated, to make a list
41 * sorted on priority. 42 * sorted on priority.
42 */ 43 */
43 #define MT_ST_CUR 0 /* static match in current file */ 44 #define MT_ST_CUR 0 /* static match in current file */
44 #define MT_GL_CUR 1 /* global match in current file */ 45 #define MT_GL_CUR 1 /* global match in current file */
45 #define MT_GL_OTH 2 /* global match in other file */ 46 #define MT_GL_OTH 2 /* global match in other file */
1337 char_u *ebuf; /* additional buffer for etag fname */ 1338 char_u *ebuf; /* additional buffer for etag fname */
1338 int is_etag; /* current file is emaces style */ 1339 int is_etag; /* current file is emaces style */
1339 #endif 1340 #endif
1340 1341
1341 char_u *mfp; 1342 char_u *mfp;
1342 hashtab_T ht_match[MT_COUNT]; 1343 garray_T ga_match[MT_COUNT]; /* stores matches in sequence */
1344 hashtab_T ht_match[MT_COUNT]; /* stores matches by key */
1343 hash_T hash = 0; 1345 hash_T hash = 0;
1344 int match_count = 0; /* number of matches found */ 1346 int match_count = 0; /* number of matches found */
1345 char_u **matches; 1347 char_u **matches;
1346 int mtt; 1348 int mtt;
1347 int help_save; 1349 int help_save;
1403 tag_fname = alloc(MAXPATHL + 1); 1405 tag_fname = alloc(MAXPATHL + 1);
1404 #ifdef FEAT_EMACS_TAGS 1406 #ifdef FEAT_EMACS_TAGS
1405 ebuf = alloc(LSIZE); 1407 ebuf = alloc(LSIZE);
1406 #endif 1408 #endif
1407 for (mtt = 0; mtt < MT_COUNT; ++mtt) 1409 for (mtt = 0; mtt < MT_COUNT; ++mtt)
1410 {
1411 ga_init2(&ga_match[mtt], (int)sizeof(char_u *), 100);
1408 hash_init(&ht_match[mtt]); 1412 hash_init(&ht_match[mtt]);
1413 }
1409 1414
1410 /* check for out of memory situation */ 1415 /* check for out of memory situation */
1411 if (lbuf == NULL || tag_fname == NULL 1416 if (lbuf == NULL || tag_fname == NULL
1412 #ifdef FEAT_EMACS_TAGS 1417 #ifdef FEAT_EMACS_TAGS
1413 || ebuf == NULL 1418 || ebuf == NULL
2211 *tagp.tagname_end = cc; 2216 *tagp.tagname_end = cc;
2212 match_re = TRUE; 2217 match_re = TRUE;
2213 } 2218 }
2214 2219
2215 /* 2220 /*
2216 * If a match is found, add it to ht_match[]. 2221 * If a match is found, add it to ht_match[] and ga_match[].
2217 */ 2222 */
2218 if (match) 2223 if (match)
2219 { 2224 {
2220 int len = 0; 2225 int len = 0;
2221 2226
2269 if (match_re) 2274 if (match_re)
2270 mtt += MT_RE_OFF; 2275 mtt += MT_RE_OFF;
2271 } 2276 }
2272 2277
2273 /* 2278 /*
2274 * Add the found match in ht_match[mtt]. 2279 * Add the found match in ht_match[mtt] and ga_match[mtt].
2275 * Store the info we need later, which depends on the kind of 2280 * Store the info we need later, which depends on the kind of
2276 * tags we are dealing with. 2281 * tags we are dealing with.
2277 */ 2282 */
2278 if (help_only) 2283 if (help_only)
2279 { 2284 {
2421 hash = hash_hash(mfp); 2426 hash = hash_hash(mfp);
2422 hi = hash_lookup(&ht_match[mtt], mfp, hash); 2427 hi = hash_lookup(&ht_match[mtt], mfp, hash);
2423 if (HASHITEM_EMPTY(hi)) 2428 if (HASHITEM_EMPTY(hi))
2424 { 2429 {
2425 if (hash_add_item(&ht_match[mtt], hi, mfp, hash) 2430 if (hash_add_item(&ht_match[mtt], hi, mfp, hash)
2426 == FAIL) 2431 == FAIL
2432 || ga_grow(&ga_match[mtt], 1) != OK)
2427 { 2433 {
2428 /* Out of memory! Just forget about the rest. */ 2434 /* Out of memory! Just forget about the rest. */
2429 retval = OK; 2435 retval = OK;
2430 stop_searching = TRUE; 2436 stop_searching = TRUE;
2431 break; 2437 break;
2432 } 2438 }
2433 else 2439 else
2440 {
2441 ((char_u **)(ga_match[mtt].ga_data))
2442 [ga_match[mtt].ga_len++] = mfp;
2434 ++match_count; 2443 ++match_count;
2444 }
2435 } 2445 }
2436 else 2446 else
2437 /* duplicate tag, drop it */ 2447 /* duplicate tag, drop it */
2438 vim_free(mfp); 2448 vim_free(mfp);
2439 } 2449 }
2531 #ifdef FEAT_EMACS_TAGS 2541 #ifdef FEAT_EMACS_TAGS
2532 vim_free(ebuf); 2542 vim_free(ebuf);
2533 #endif 2543 #endif
2534 2544
2535 /* 2545 /*
2536 * Move the matches from the ht_match[] arrays into one list of 2546 * Move the matches from the ga_match[] arrays into one list of
2537 * matches. When retval == FAIL, free the matches. 2547 * matches. When retval == FAIL, free the matches.
2538 */ 2548 */
2539 if (retval == FAIL) 2549 if (retval == FAIL)
2540 match_count = 0; 2550 match_count = 0;
2541 2551
2545 else 2555 else
2546 matches = NULL; 2556 matches = NULL;
2547 match_count = 0; 2557 match_count = 0;
2548 for (mtt = 0; mtt < MT_COUNT; ++mtt) 2558 for (mtt = 0; mtt < MT_COUNT; ++mtt)
2549 { 2559 {
2550 hashitem_T *hi; 2560 for (i = 0; i < ga_match[mtt].ga_len; ++i)
2551 long_u todo; 2561 {
2552 2562 mfp = ((char_u **)(ga_match[mtt].ga_data))[i];
2553 todo = (long)ht_match[mtt].ht_used; 2563 if (matches == NULL)
2554 for (hi = ht_match[mtt].ht_array; todo > 0; ++hi) 2564 vim_free(mfp);
2555 { 2565 else
2556 if (!HASHITEM_EMPTY(hi)) 2566 {
2557 { 2567 if (!name_only)
2558 mfp = hi->hi_key; 2568 {
2559 if (matches == NULL) 2569 /* Change mtt back to zero-based. */
2560 vim_free(mfp); 2570 *mfp = *mfp - 1;
2561 else 2571
2562 { 2572 /* change the TAG_SEP back to NUL */
2563 if (!name_only) 2573 for (p = mfp + 1; *p != NUL; ++p)
2564 { 2574 if (*p == TAG_SEP)
2565 /* Change mtt back to zero-based. */ 2575 *p = NUL;
2566 *mfp = *mfp - 1; 2576 }
2567 2577 matches[match_count++] = (char_u *)mfp;
2568 /* change the TAG_SEP back to NUL */ 2578 }
2569 for (p = mfp + 1; *p != NUL; ++p) 2579 }
2570 if (*p == TAG_SEP) 2580
2571 *p = NUL; 2581 ga_clear(&ga_match[mtt]);
2572 }
2573 matches[match_count++] = (char_u *)mfp;
2574 }
2575 todo--;
2576 }
2577 }
2578 hash_clear(&ht_match[mtt]); 2582 hash_clear(&ht_match[mtt]);
2579 } 2583 }
2580 2584
2581 *matchesp = matches; 2585 *matchesp = matches;
2582 *num_matches = match_count; 2586 *num_matches = match_count;