comparison src/sign.c @ 17366:9843fbfa0ee5 v8.1.1682

patch 8.1.1682: placing a larger number of signs is slow commit https://github.com/vim/vim/commit/809ce4d317fe12db0b2c17f16b4f77200fb060c4 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jul 13 21:21:40 2019 +0200 patch 8.1.1682: placing a larger number of signs is slow Problem: Placing a larger number of signs is slow. Solution: Add functions for dealing with a list of signs. (Yegappan Lakshmanan, closes #4636)
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Jul 2019 21:30:04 +0200
parents 82b5d981fe59
children a5874fdc8f3a
comparison
equal deleted inserted replaced
17365:c6491636f12e 17366:9843fbfa0ee5
440 static linenr_T 440 static linenr_T
441 buf_change_sign_type( 441 buf_change_sign_type(
442 buf_T *buf, // buffer to store sign in 442 buf_T *buf, // buffer to store sign in
443 int markId, // sign ID 443 int markId, // sign ID
444 char_u *group, // sign group 444 char_u *group, // sign group
445 int typenr) // typenr of sign we are adding 445 int typenr, // typenr of sign we are adding
446 int prio) // sign priority
446 { 447 {
447 signlist_T *sign; // a sign in the signlist 448 signlist_T *sign; // a sign in the signlist
448 449
449 FOR_ALL_SIGNS_IN_BUF(buf, sign) 450 FOR_ALL_SIGNS_IN_BUF(buf, sign)
450 { 451 {
451 if (sign->id == markId && sign_in_group(sign, group)) 452 if (sign->id == markId && sign_in_group(sign, group))
452 { 453 {
453 sign->typenr = typenr; 454 sign->typenr = typenr;
455 sign->priority = prio;
456 sign_sort_by_prio_on_line(buf, sign);
454 return sign->lnum; 457 return sign->lnum;
455 } 458 }
456 } 459 }
457 460
458 return (linenr_T)0; 461 return (linenr_T)0;
1102 if (lnum > 0) 1105 if (lnum > 0)
1103 // ":sign place {id} line={lnum} name={name} file={fname}": 1106 // ":sign place {id} line={lnum} name={name} file={fname}":
1104 // place a sign 1107 // place a sign
1105 buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr); 1108 buf_addsign(buf, *sign_id, sign_group, prio, lnum, sp->sn_typenr);
1106 else 1109 else
1107 // ":sign place {id} file={fname}": change sign type 1110 // ":sign place {id} file={fname}": change sign type and/or priority
1108 lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr); 1111 lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr,
1112 prio);
1109 if (lnum > 0) 1113 if (lnum > 0)
1110 { 1114 {
1111 redraw_buf_line_later(buf, lnum); 1115 redraw_buf_line_later(buf, lnum);
1112 1116
1113 // When displaying signs in the 'number' column, if the width of the 1117 // When displaying signs in the 'number' column, if the width of the
2094 } 2098 }
2095 } 2099 }
2096 # endif 2100 # endif
2097 2101
2098 /* 2102 /*
2099 * "sign_define()" function 2103 * Define a sign using the attributes in 'dict'. Returns 0 on success and -1 on
2100 */ 2104 * failure.
2101 void 2105 */
2102 f_sign_define(typval_T *argvars, typval_T *rettv) 2106 static int
2103 { 2107 sign_define_from_dict(char_u *name_arg, dict_T *dict)
2104 char_u *name; 2108 {
2105 dict_T *dict; 2109 char_u *name = NULL;
2106 char_u *icon = NULL; 2110 char_u *icon = NULL;
2107 char_u *linehl = NULL; 2111 char_u *linehl = NULL;
2108 char_u *text = NULL; 2112 char_u *text = NULL;
2109 char_u *texthl = NULL; 2113 char_u *texthl = NULL;
2110 2114 int retval = -1;
2111 rettv->vval.v_number = -1; 2115
2112 2116 if (name_arg == NULL)
2113 name = tv_get_string_chk(&argvars[0]); 2117 {
2114 if (name == NULL) 2118 if (dict == NULL)
2115 return; 2119 return -1;
2116 2120 name = dict_get_string(dict, (char_u *)"name", TRUE);
2117 if (argvars[1].v_type != VAR_UNKNOWN) 2121 }
2118 { 2122 else
2119 if (argvars[1].v_type != VAR_DICT) 2123 name = vim_strsave(name_arg);
2120 { 2124 if (name == NULL || name[0] == NUL)
2121 emsg(_(e_dictreq)); 2125 goto cleanup;
2122 return; 2126 if (dict != NULL)
2123 } 2127 {
2124 2128 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
2125 // sign attributes 2129 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
2126 dict = argvars[1].vval.v_dict; 2130 text = dict_get_string(dict, (char_u *)"text", TRUE);
2127 if (dict_find(dict, (char_u *)"icon", -1) != NULL) 2131 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
2128 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
2129 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
2130 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
2131 if (dict_find(dict, (char_u *)"text", -1) != NULL)
2132 text = dict_get_string(dict, (char_u *)"text", TRUE);
2133 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
2134 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
2135 } 2132 }
2136 2133
2137 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK) 2134 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
2138 rettv->vval.v_number = 0; 2135 retval = 0;
2139 2136
2137 cleanup:
2138 vim_free(name);
2140 vim_free(icon); 2139 vim_free(icon);
2141 vim_free(linehl); 2140 vim_free(linehl);
2142 vim_free(text); 2141 vim_free(text);
2143 vim_free(texthl); 2142 vim_free(texthl);
2143
2144 return retval;
2145 }
2146
2147 /*
2148 * Define multiple signs using attributes from list 'l' and store the return
2149 * values in 'retlist'.
2150 */
2151 static void
2152 sign_define_multiple(list_T *l, list_T *retlist)
2153 {
2154 listitem_T *li;
2155 int retval;
2156
2157 for (li = l->lv_first; li != NULL; li = li->li_next)
2158 {
2159 retval = -1;
2160 if (li->li_tv.v_type == VAR_DICT)
2161 retval = sign_define_from_dict(NULL, li->li_tv.vval.v_dict);
2162 else
2163 emsg(_(e_dictreq));
2164 list_append_number(retlist, retval);
2165 }
2166 }
2167
2168 /*
2169 * "sign_define()" function
2170 */
2171 void
2172 f_sign_define(typval_T *argvars, typval_T *rettv)
2173 {
2174 char_u *name;
2175
2176 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN)
2177 {
2178 // Define multiple signs
2179 if (rettv_list_alloc(rettv) != OK)
2180 return;
2181
2182 sign_define_multiple(argvars[0].vval.v_list, rettv->vval.v_list);
2183 return;
2184 }
2185
2186 // Define a single sign
2187 rettv->vval.v_number = -1;
2188
2189 name = tv_get_string_chk(&argvars[0]);
2190 if (name == NULL)
2191 return;
2192
2193 if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_DICT)
2194 {
2195 emsg(_(e_dictreq));
2196 return;
2197 }
2198
2199 rettv->vval.v_number = sign_define_from_dict(name,
2200 argvars[1].v_type == VAR_DICT ? argvars[1].vval.v_dict : NULL);
2144 } 2201 }
2145 2202
2146 /* 2203 /*
2147 * "sign_getdefined()" function 2204 * "sign_getdefined()" function
2148 */ 2205 */
2267 cleanup: 2324 cleanup:
2268 vim_free(sign_group); 2325 vim_free(sign_group);
2269 } 2326 }
2270 2327
2271 /* 2328 /*
2272 * "sign_place()" function 2329 * Place a new sign using the values specified in dict 'dict'. Returns the sign
2273 */ 2330 * identifier if successfully placed, otherwise returns 0.
2274 void 2331 */
2275 f_sign_place(typval_T *argvars, typval_T *rettv) 2332 static int
2276 { 2333 sign_place_from_dict(
2277 int sign_id; 2334 typval_T *id_tv,
2335 typval_T *group_tv,
2336 typval_T *name_tv,
2337 typval_T *buf_tv,
2338 dict_T *dict)
2339 {
2340 int sign_id = 0;
2278 char_u *group = NULL; 2341 char_u *group = NULL;
2279 char_u *sign_name; 2342 char_u *sign_name = NULL;
2280 buf_T *buf; 2343 buf_T *buf = NULL;
2281 dict_T *dict;
2282 dictitem_T *di; 2344 dictitem_T *di;
2283 linenr_T lnum = 0; 2345 linenr_T lnum = 0;
2284 int prio = SIGN_DEF_PRIO; 2346 int prio = SIGN_DEF_PRIO;
2285 int notanum = FALSE; 2347 int notanum = FALSE;
2286 2348 int ret_sign_id = -1;
2287 rettv->vval.v_number = -1; 2349
2288 2350 // sign identifier
2289 // Sign identifier 2351 if (id_tv == NULL)
2290 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum); 2352 {
2291 if (notanum) 2353 di = dict_find(dict, (char_u *)"id", -1);
2292 return; 2354 if (di != NULL)
2293 if (sign_id < 0) 2355 id_tv = &di->di_tv;
2294 { 2356 }
2295 emsg(_(e_invarg)); 2357 if (id_tv == NULL)
2296 return; 2358 sign_id = 0;
2297 }
2298
2299 // Sign group
2300 group = tv_get_string_chk(&argvars[1]);
2301 if (group == NULL)
2302 return;
2303 if (group[0] == '\0')
2304 group = NULL; // global sign group
2305 else 2359 else
2306 { 2360 {
2307 group = vim_strsave(group); 2361 sign_id = tv_get_number_chk(id_tv, &notanum);
2362 if (notanum)
2363 return -1;
2364 if (sign_id < 0)
2365 {
2366 emsg(_(e_invarg));
2367 return -1;
2368 }
2369 }
2370
2371 // sign group
2372 if (group_tv == NULL)
2373 {
2374 di = dict_find(dict, (char_u *)"group", -1);
2375 if (di != NULL)
2376 group_tv = &di->di_tv;
2377 }
2378 if (group_tv == NULL)
2379 group = NULL; // global group
2380 else
2381 {
2382 group = tv_get_string_chk(group_tv);
2308 if (group == NULL) 2383 if (group == NULL)
2309 return; 2384 goto cleanup;
2310 } 2385 if (group[0] == '\0') // global sign group
2311 2386 group = NULL;
2312 // Sign name 2387 else
2313 sign_name = tv_get_string_chk(&argvars[2]); 2388 {
2389 group = vim_strsave(group);
2390 if (group == NULL)
2391 return -1;
2392 }
2393 }
2394
2395 // sign name
2396 if (name_tv == NULL)
2397 {
2398 di = dict_find(dict, (char_u *)"name", -1);
2399 if (di != NULL)
2400 name_tv = &di->di_tv;
2401 }
2402 if (name_tv == NULL)
2403 goto cleanup;
2404 sign_name = tv_get_string_chk(name_tv);
2314 if (sign_name == NULL) 2405 if (sign_name == NULL)
2315 goto cleanup; 2406 goto cleanup;
2316 2407
2317 // Buffer to place the sign 2408 // buffer to place the sign
2318 buf = get_buf_arg(&argvars[3]); 2409 if (buf_tv == NULL)
2410 {
2411 di = dict_find(dict, (char_u *)"buffer", -1);
2412 if (di != NULL)
2413 buf_tv = &di->di_tv;
2414 }
2415 if (buf_tv == NULL)
2416 goto cleanup;
2417 buf = get_buf_arg(buf_tv);
2319 if (buf == NULL) 2418 if (buf == NULL)
2320 goto cleanup; 2419 goto cleanup;
2321 2420
2322 if (argvars[4].v_type != VAR_UNKNOWN) 2421 // line number of the sign
2323 { 2422 di = dict_find(dict, (char_u *)"lnum", -1);
2324 if (argvars[4].v_type != VAR_DICT || 2423 if (di != NULL)
2325 ((dict = argvars[4].vval.v_dict) == NULL)) 2424 {
2326 { 2425 lnum = (int)tv_get_number_chk(&di->di_tv, &notanum);
2327 emsg(_(e_dictreq)); 2426 if (notanum)
2328 goto cleanup; 2427 goto cleanup;
2329 } 2428 }
2330 2429
2331 // Line number where the sign is to be placed 2430 // sign priority
2332 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL) 2431 di = dict_find(dict, (char_u *)"priority", -1);
2333 { 2432 if (di != NULL)
2334 (void)tv_get_number_chk(&di->di_tv, &notanum); 2433 {
2335 if (notanum) 2434 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
2336 goto cleanup; 2435 if (notanum)
2337 lnum = tv_get_lnum(&di->di_tv); 2436 goto cleanup;
2338 }
2339 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
2340 {
2341 // Sign priority
2342 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
2343 if (notanum)
2344 goto cleanup;
2345 }
2346 } 2437 }
2347 2438
2348 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK) 2439 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
2349 rettv->vval.v_number = sign_id; 2440 ret_sign_id = sign_id;
2350 2441
2351 cleanup: 2442 cleanup:
2352 vim_free(group); 2443 vim_free(group);
2444
2445 return ret_sign_id;
2446 }
2447
2448 /*
2449 * "sign_place()" function
2450 */
2451 void
2452 f_sign_place(typval_T *argvars, typval_T *rettv)
2453 {
2454 dict_T *dict = NULL;
2455
2456 rettv->vval.v_number = -1;
2457
2458 if (argvars[4].v_type != VAR_UNKNOWN
2459 && (argvars[4].v_type != VAR_DICT
2460 || ((dict = argvars[4].vval.v_dict) == NULL)))
2461 {
2462 emsg(_(e_dictreq));
2463 return;
2464 }
2465
2466 rettv->vval.v_number = sign_place_from_dict(&argvars[0], &argvars[1],
2467 &argvars[2], &argvars[3], dict);
2468 }
2469
2470 /*
2471 * "sign_placelist()" function. Place multiple signs.
2472 */
2473 void
2474 f_sign_placelist(typval_T *argvars, typval_T *rettv)
2475 {
2476 listitem_T *li;
2477 int sign_id;
2478
2479 if (rettv_list_alloc(rettv) != OK)
2480 return;
2481
2482 if (argvars[0].v_type != VAR_LIST)
2483 {
2484 emsg(_(e_listreq));
2485 return;
2486 }
2487
2488 // Process the List of sign attributes
2489 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
2490 {
2491 sign_id = -1;
2492 if (li->li_tv.v_type == VAR_DICT)
2493 sign_id = sign_place_from_dict(NULL, NULL, NULL, NULL,
2494 li->li_tv.vval.v_dict);
2495 else
2496 emsg(_(e_dictreq));
2497 list_append_number(rettv->vval.v_list, sign_id);
2498 }
2499 }
2500
2501 /*
2502 * Undefine multiple signs
2503 */
2504 static void
2505 sign_undefine_multiple(list_T *l, list_T *retlist)
2506 {
2507 char_u *name;
2508 listitem_T *li;
2509 int retval;
2510
2511 for (li = l->lv_first; li != NULL; li = li->li_next)
2512 {
2513 retval = -1;
2514 name = tv_get_string_chk(&li->li_tv);
2515 if (name != NULL && (sign_undefine_by_name(name) == OK))
2516 retval = 0;
2517 list_append_number(retlist, retval);
2518 }
2353 } 2519 }
2354 2520
2355 /* 2521 /*
2356 * "sign_undefine()" function 2522 * "sign_undefine()" function
2357 */ 2523 */
2358 void 2524 void
2359 f_sign_undefine(typval_T *argvars, typval_T *rettv) 2525 f_sign_undefine(typval_T *argvars, typval_T *rettv)
2360 { 2526 {
2361 char_u *name; 2527 char_u *name;
2528
2529 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN)
2530 {
2531 // Undefine multiple signs
2532 if (rettv_list_alloc(rettv) != OK)
2533 return;
2534
2535 sign_undefine_multiple(argvars[0].vval.v_list, rettv->vval.v_list);
2536 return;
2537 }
2362 2538
2363 rettv->vval.v_number = -1; 2539 rettv->vval.v_number = -1;
2364 2540
2365 if (argvars[0].v_type == VAR_UNKNOWN) 2541 if (argvars[0].v_type == VAR_UNKNOWN)
2366 { 2542 {
2379 rettv->vval.v_number = 0; 2555 rettv->vval.v_number = 0;
2380 } 2556 }
2381 } 2557 }
2382 2558
2383 /* 2559 /*
2384 * "sign_unplace()" function 2560 * Unplace the sign with attributes specified in 'dict'. Returns 0 on success
2385 */ 2561 * and -1 on failure.
2386 void 2562 */
2387 f_sign_unplace(typval_T *argvars, typval_T *rettv) 2563 static int
2388 { 2564 sign_unplace_from_dict(typval_T *group_tv, dict_T *dict)
2389 dict_T *dict; 2565 {
2390 dictitem_T *di; 2566 dictitem_T *di;
2391 int sign_id = 0; 2567 int sign_id = 0;
2392 buf_T *buf = NULL; 2568 buf_T *buf = NULL;
2393 char_u *group = NULL; 2569 char_u *group = NULL;
2394 2570 int retval = -1;
2395 rettv->vval.v_number = -1; 2571
2396 2572 // sign group
2397 if (argvars[0].v_type != VAR_STRING) 2573 if (group_tv != NULL)
2398 { 2574 group = tv_get_string(group_tv);
2399 emsg(_(e_invarg));
2400 return;
2401 }
2402
2403 group = tv_get_string(&argvars[0]);
2404 if (group[0] == '\0')
2405 group = NULL; // global sign group
2406 else 2575 else
2407 { 2576 group = dict_get_string(dict, (char_u *)"group", FALSE);
2408 group = vim_strsave(group); 2577 if (group != NULL)
2409 if (group == NULL) 2578 {
2410 return; 2579 if (group[0] == '\0') // global sign group
2411 } 2580 group = NULL;
2412 2581 else
2413 if (argvars[1].v_type != VAR_UNKNOWN) 2582 {
2414 { 2583 group = vim_strsave(group);
2415 if (argvars[1].v_type != VAR_DICT) 2584 if (group == NULL)
2416 { 2585 return -1;
2417 emsg(_(e_dictreq)); 2586 }
2418 goto cleanup; 2587 }
2419 } 2588
2420 dict = argvars[1].vval.v_dict; 2589 if (dict != NULL)
2421 2590 {
2422 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL) 2591 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
2423 { 2592 {
2424 buf = get_buf_arg(&di->di_tv); 2593 buf = get_buf_arg(&di->di_tv);
2425 if (buf == NULL) 2594 if (buf == NULL)
2426 goto cleanup; 2595 goto cleanup;
2427 } 2596 }
2428 if (dict_find(dict, (char_u *)"id", -1) != NULL) 2597 if (dict_find(dict, (char_u *)"id", -1) != NULL)
2598 {
2429 sign_id = dict_get_number(dict, (char_u *)"id"); 2599 sign_id = dict_get_number(dict, (char_u *)"id");
2600 if (sign_id <= 0)
2601 {
2602 emsg(_(e_invarg));
2603 goto cleanup;
2604 }
2605 }
2430 } 2606 }
2431 2607
2432 if (buf == NULL) 2608 if (buf == NULL)
2433 { 2609 {
2434 // Delete the sign in all the buffers 2610 // Delete the sign in all the buffers
2611 retval = 0;
2435 FOR_ALL_BUFFERS(buf) 2612 FOR_ALL_BUFFERS(buf)
2436 if (sign_unplace(sign_id, group, buf, 0) == OK) 2613 if (sign_unplace(sign_id, group, buf, 0) != OK)
2437 rettv->vval.v_number = 0; 2614 retval = -1;
2438 } 2615 }
2439 else 2616 else if (sign_unplace(sign_id, group, buf, 0) == OK)
2440 { 2617 retval = 0;
2441 if (sign_unplace(sign_id, group, buf, 0) == OK)
2442 rettv->vval.v_number = 0;
2443 }
2444 2618
2445 cleanup: 2619 cleanup:
2446 vim_free(group); 2620 vim_free(group);
2621
2622 return retval;
2623 }
2624
2625 /*
2626 * "sign_unplace()" function
2627 */
2628 void
2629 f_sign_unplace(typval_T *argvars, typval_T *rettv)
2630 {
2631 dict_T *dict = NULL;
2632
2633 rettv->vval.v_number = -1;
2634
2635 if (argvars[0].v_type != VAR_STRING)
2636 {
2637 emsg(_(e_invarg));
2638 return;
2639 }
2640
2641 if (argvars[1].v_type != VAR_UNKNOWN)
2642 {
2643 if (argvars[1].v_type != VAR_DICT)
2644 {
2645 emsg(_(e_dictreq));
2646 return;
2647 }
2648 dict = argvars[1].vval.v_dict;
2649 }
2650
2651 rettv->vval.v_number = sign_unplace_from_dict(&argvars[0], dict);
2652 }
2653
2654 /*
2655 * "sign_unplacelist()" function
2656 */
2657 void
2658 f_sign_unplacelist(typval_T *argvars, typval_T *rettv)
2659 {
2660 listitem_T *li;
2661 int retval;
2662
2663 if (rettv_list_alloc(rettv) != OK)
2664 return;
2665
2666 if (argvars[0].v_type != VAR_LIST)
2667 {
2668 emsg(_(e_listreq));
2669 return;
2670 }
2671
2672 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
2673 {
2674 retval = -1;
2675 if (li->li_tv.v_type == VAR_DICT)
2676 retval = sign_unplace_from_dict(NULL, li->li_tv.vval.v_dict);
2677 else
2678 emsg(_(e_dictreq));
2679 list_append_number(rettv->vval.v_list, retval);
2680 }
2447 } 2681 }
2448 2682
2449 #endif /* FEAT_SIGNS */ 2683 #endif /* FEAT_SIGNS */