diff options
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r-- | src/nvim/window.c | 110 |
1 files changed, 95 insertions, 15 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index 6b40ccdb84..4448b72ac0 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5064,6 +5064,17 @@ void free_wininfo(wininfo_T *wip, buf_T *bp) xfree(wip); } +// Free colorcolumns. Has syntax names. +static void free_wp_cc_cols(colorcol_T* cc) +{ + if (cc) { + for (int i = 0; cc[i].col >= 0; i ++) { + xfree(cc[i].syn_name); + } + } + xfree(cc); +} + /// Remove window 'wp' from the window list and free the structure. /// /// @param tp tab page "win" is in, NULL for current @@ -5157,7 +5168,7 @@ static void win_free(win_T *wp, tabpage_T *tp) qf_free_all(wp); - xfree(wp->w_p_cc_cols); + free_wp_cc_cols(wp->w_p_cc_cols); win_free_grid(wp, false); @@ -7399,10 +7410,21 @@ static bool frame_check_width(const frame_T *topfrp, int width) return true; } -/// Simple int comparison function for use with qsort() -static int int_cmp(const void *a, const void *b) +/// Simple colorcol_T comparison function for use with qsort(). +/// Compares the column numbers +static int colorcol_cmp(const void *a, const void *b) { - return *(const int *)a - *(const int *)b; + colorcol_T *ac = (colorcol_T*) a; + colorcol_T *bc = (colorcol_T*) b; + int ret = ac->col - bc->col; + if (ret == 0) { + // qsort() is not inherently stable, so to make it stable, + // the syn_attr field temporarily contains the original index. + // Comparing these will enforce stability. + return ac->syn_attr - bc->syn_attr; + } else { + return ret; + } } /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". @@ -7415,9 +7437,16 @@ char *check_colorcolumn(win_T *wp) } unsigned int count = 0; - int color_cols[256]; + colorcol_T color_cols[256]; + bool do_skip = false; + for (char *s = wp->w_p_cc; *s != NUL && count < 255;) { int col; + int ch = ' '; + char syn_name[256]; + int flags = 0; + syn_name[0] = 0; + if (*s == '-' || *s == '+') { // -N and +N: add to 'textwidth' col = (*s == '-') ? -1 : 1; @@ -7427,7 +7456,7 @@ char *check_colorcolumn(win_T *wp) } col = col * getdigits_int(&s, true, 0); if (wp->w_buffer->b_p_tw == 0) { - goto skip; // 'textwidth' not set, skip this item + do_skip = true; // 'textwidth' not set, skip this item } assert((col >= 0 && wp->w_buffer->b_p_tw <= INT_MAX - col @@ -7437,15 +7466,63 @@ char *check_colorcolumn(win_T *wp) && wp->w_buffer->b_p_tw + col <= INT_MAX)); col += (int)wp->w_buffer->b_p_tw; if (col < 0) { - goto skip; + do_skip = true; } } else if (ascii_isdigit(*s)) { col = getdigits_int(&s, true, 0); } else { return e_invarg; } - color_cols[count++] = col - 1; // 1-based to 0-based -skip: + + // Parse the character. + if (*s == '/') { + s ++; + ch = mb_ptr2char_adv((const char**) &s); + if (!ch) { + return e_invarg; + } + } + + // Parse the highlight group. + if (*s == '/') { + s ++; + size_t i = 0; + while(i < sizeof(syn_name) && *s && *s != '/' && *s != ',') { + syn_name[i ++] = *(s++); + } + syn_name[i] = 0; + } + + // Parse extra flags + if (*s == '/') { + s ++; + while (*s != ',' && *s) { + switch (*(s ++)) { + case 'b': + flags |= kColorcolBehind; + break; + + case 'f': + flags |= kColorcolForeground; + break; + + default: + return e_invarg; + } + } + } + + if (!do_skip) { + color_cols[count] = (colorcol_T) { + .col = col - 1, // 1-based to 0-based + .syn_attr = (int) count, // Temporarily use this for stable sorting. + .ch = ch, + .syn_name = syn_name[0] == 0 ? NULL : xstrdup(syn_name), + .flags = flags, + }; + count ++; + } + if (*s == NUL) { break; } @@ -7457,23 +7534,26 @@ skip: } } - xfree(wp->w_p_cc_cols); + free_wp_cc_cols(wp->w_p_cc_cols); if (count == 0) { wp->w_p_cc_cols = NULL; } else { - wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1)); + wp->w_p_cc_cols = xmalloc(sizeof(colorcol_T) * (count + 1)); // sort the columns for faster usage on screen redraw inside // win_line() - qsort(color_cols, count, sizeof(int), int_cmp); + qsort(color_cols, count, sizeof(colorcol_T), colorcol_cmp); int j = 0; for (unsigned int i = 0; i < count; i++) { // skip duplicates - if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) { - wp->w_p_cc_cols[j++] = color_cols[i]; + if (j == 0 || wp->w_p_cc_cols[j - 1].col != color_cols[i].col) { + wp->w_p_cc_cols[j] = color_cols[i]; + // Clear syn_attr, which was used for stable sorting. + wp->w_p_cc_cols[j ++].syn_attr = 0; } } - wp->w_p_cc_cols[j] = -1; // end marker + memset(&wp->w_p_cc_cols[j], 0, sizeof(wp->w_p_cc_cols[j])); + wp->w_p_cc_cols[j].col = -1; // end marker } return NULL; // no error |