aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r--src/nvim/window.c110
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