refactor(sign): store 'signcolumn' width range when it is set

Problem:  Minimum and maximum signcolumn width is determined each redraw.
Solution: Determine and store 'signcolumn' range when option is set.
This commit is contained in:
Luuk van Baal 2023-11-20 02:27:16 +01:00 committed by Lewis Russell
parent fec5e3ab24
commit 585eeacb24
7 changed files with 56 additions and 69 deletions

View File

@ -1206,6 +1206,8 @@ struct window_S {
int w_nrwidth; // width of 'number' and 'relativenumber'
// column being used
int w_scwidth; // width of 'signcolumn'
int w_minscwidth; // minimum width or SCL_NO/SCL_NUM
int w_maxscwidth; // maximum width or SCL_NO/SCL_NUM
// === end of cached values ===

View File

@ -442,7 +442,9 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
int *cul_id, int *num_id)
{
MarkTreeIter itr[1];
if (!buf->b_signs || !marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
if (!buf->b_signs
|| wp->w_minscwidth == SCL_NO
|| !marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
return;
}
@ -471,7 +473,7 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
}
if (kv_size(signs)) {
int width = (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u') ? 1 : wp->w_scwidth;
int width = wp->w_minscwidth == SCL_NUM ? 1 : wp->w_scwidth;
int idx = MIN(width, num_text) - 1;
qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(MTKey), sign_cmp);

View File

@ -561,7 +561,7 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int sign_num_attr, in
&& !((has_cpo_n && !wp->w_p_bri) && wp->w_skipcol > 0 && wlv->lnum == wp->w_topline)) {
// If 'signcolumn' is set to 'number' and a sign is present in "lnum",
// then display the sign instead of the line number.
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && wlv->sattrs[0].text) {
if (wp->w_minscwidth == SCL_NUM && wlv->sattrs[0].text) {
get_sign_display_info(true, wp, wlv, 0, sign_cul_attr);
} else {
// Draw the line number (empty space after wrapping).

View File

@ -606,7 +606,7 @@ int update_screen(void)
}
// Reset 'statuscolumn' if there is no dedicated signcolumn but it is invalid.
if (*wp->w_p_stc != NUL && !wp->w_buffer->b_signcols.valid && win_no_signcol(wp)) {
if (*wp->w_p_stc != NUL && !wp->w_buffer->b_signcols.valid && wp->w_minscwidth <= SCL_NO) {
wp->w_nrwidth_line_count = 0;
wp->w_valid &= ~VALID_WCOL;
wp->w_redr_type = UPD_NOT_VALID;
@ -619,7 +619,7 @@ int update_screen(void)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
// Validate b_signcols if there is no dedicated signcolumn but 'statuscolumn' is set.
if (*wp->w_p_stc != NUL && win_no_signcol(wp)) {
if (*wp->w_p_stc != NUL && wp->w_minscwidth <= SCL_NO) {
buf_signcols(wp->w_buffer, 0);
}
@ -2632,8 +2632,7 @@ int number_width(win_T *wp)
// If 'signcolumn' is set to 'number' and there is a sign to display, then
// the minimal width for the number column is 2.
if (n < 2 && wp->w_buffer->b_signs_with_text
&& (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
if (n < 2 && wp->w_buffer->b_signs_with_text && wp->w_minscwidth == SCL_NUM) {
n = 2;
}

View File

@ -2245,6 +2245,7 @@ static const char *did_set_number_relativenumber(optset_T *args)
// When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width.
win->w_nrwidth_line_count = 0;
}
check_signcolumn(win);
return NULL;
}
@ -4861,6 +4862,7 @@ void didset_window_options(win_T *wp, bool valid_cursor)
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp);
set_winbar_win(wp, false, valid_cursor);
check_signcolumn(wp);
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
}
@ -6170,49 +6172,12 @@ bool fish_like_shell(void)
/// buffer signs and on user configuration.
int win_signcol_count(win_T *wp)
{
return win_signcol_configured(wp);
}
/// Return true when window "wp" has no sign column.
bool win_no_signcol(win_T *wp)
{
const char *scl = wp->w_p_scl;
return (*scl == 'n' && (*(scl + 1) == 'o' || (*(scl + 1) == 'u'
&& (wp->w_p_nu || wp->w_p_rnu))));
}
/// Return the number of requested sign columns, based on user / configuration.
int win_signcol_configured(win_T *wp)
{
const char *scl = wp->w_p_scl;
if (win_no_signcol(wp)) {
if (wp->w_minscwidth <= SCL_NO) {
return 0;
}
// yes or yes
if (!strncmp(scl, "yes:", 4)) {
// Fixed amount of columns
return scl[4] - '0';
}
if (*scl == 'y') {
return 1;
}
int minimum = 0, maximum = 1;
if (!strncmp(scl, "auto:", 5)) {
// Variable depending on a configuration
maximum = scl[5] - '0';
// auto:<NUM>-<NUM>
if (strlen(scl) == 8 && *(scl + 6) == '-') {
minimum = maximum;
maximum = scl[7] - '0';
}
}
int needed_signcols = buf_signcols(wp->w_buffer, maximum);
int ret = MAX(minimum, MIN(maximum, needed_signcols));
int needed_signcols = buf_signcols(wp->w_buffer, wp->w_maxscwidth);
int ret = MAX(wp->w_minscwidth, MIN(wp->w_maxscwidth, needed_signcols));
assert(ret <= SIGN_SHOW_MAX);
return ret;
}

View File

@ -947,3 +947,6 @@ enum {
#define MAX_NUMBERWIDTH 20 // used for 'numberwidth' and 'statuscolumn'
#define TABSTOP_MAX 9999
#define SCL_NO -1 // 'signcolumn' set to "no"
#define SCL_NUM -2 // 'signcolumn' set to "number"

View File

@ -388,34 +388,53 @@ static bool valid_filetype(const char *val)
return valid_name(val, ".-_");
}
/// Handle setting 'signcolumn' for value 'val'
/// Handle setting 'signcolumn' for value 'val'. Store minimum and maximum width.
///
/// @return OK when the value is valid, FAIL otherwise
static int check_signcolumn(char *val)
int check_signcolumn(win_T *wp)
{
char *val = wp->w_p_scl;
if (*val == NUL) {
return FAIL;
}
// check for basic match
if (check_opt_strings(val, p_scl_values, false) == OK) {
return OK;
}
// check for 'auto:<NUMBER>-<NUMBER>'
if (strlen(val) == 8
&& !strncmp(val, "auto:", 5)
&& ascii_isdigit(val[5])
&& val[6] == '-'
&& ascii_isdigit(val[7])) {
int min = val[5] - '0';
int max = val[7] - '0';
if (min < 1 || max < 2 || min > 8 || max > 9 || min >= max) {
return FAIL;
if (check_opt_strings(val, p_scl_values, false) == OK) {
if (!strncmp(val, "no", 2)) { // no
wp->w_minscwidth = wp->w_maxscwidth = SCL_NO;
} else if (!strncmp(val, "nu", 2) && (wp->w_p_nu || wp->w_p_rnu)) { // number
wp->w_minscwidth = wp->w_maxscwidth = SCL_NUM;
} else if (!strncmp(val, "yes:", 4)) { // yes:<NUM>
wp->w_minscwidth = wp->w_maxscwidth = val[4] - '0';
} else if (*val == 'y') { // yes
wp->w_minscwidth = wp->w_maxscwidth = 1;
} else if (!strncmp(val, "auto:", 5)) { // auto:<NUM>
wp->w_minscwidth = 0;
wp->w_maxscwidth = val[5] - '0';
} else { // auto
wp->w_minscwidth = 0;
wp->w_maxscwidth = 1;
}
return OK;
}
return FAIL;
if (strncmp(val, "auto:", 5) != 0
|| strlen(val) != 8
|| !ascii_isdigit(val[5])
|| val[6] != '-'
|| !ascii_isdigit(val[7])) {
return FAIL;
}
// auto:<NUM>-<NUM>
int min = val[5] - '0';
int max = val[7] - '0';
if (min < 1 || max < 2 || min > 8 || min >= max) {
return FAIL;
}
wp->w_minscwidth = min;
wp->w_maxscwidth = max;
return OK;
}
/// Check validity of options with the 'statusline' format.
@ -2072,16 +2091,13 @@ int expand_set_showcmdloc(optexpand_T *args, int *numMatches, char ***matches)
const char *did_set_signcolumn(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
char **varp = (char **)args->os_varp;
const char *oldval = args->os_oldval.string.data;
if (check_signcolumn(*varp) != OK) {
if (check_signcolumn(win) != OK) {
return e_invarg;
}
// When changing the 'signcolumn' to or from 'number', recompute the
// width of the number column if 'number' or 'relativenumber' is set.
if (((*oldval == 'n' && *(oldval + 1) == 'u')
|| (*win->w_p_scl == 'n' && *(win->w_p_scl + 1) == 'u'))
&& (win->w_p_nu || win->w_p_rnu)) {
if ((*oldval == 'n' && *(oldval + 1) == 'u') || win->w_minscwidth == SCL_NUM) {
win->w_nrwidth_line_count = 0;
}
return NULL;