diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer_defs.h | 18 | ||||
-rw-r--r-- | src/nvim/drawline.c | 29 | ||||
-rw-r--r-- | src/nvim/drawscreen.c | 13 | ||||
-rw-r--r-- | src/nvim/window.c | 110 |
4 files changed, 142 insertions, 28 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index e59539f900..0d8d8d581f 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -92,6 +92,22 @@ typedef uint64_t disptick_T; // display tick type #include "nvim/syntax_defs.h" #include "nvim/terminal.h" +typedef enum { + kColorcolBehind = 1, + kColorcolForeground = 2, +} colorcol_flags_T; + +// Structure to define data associated with a colorcolumn. +typedef struct { + int col; // The column number to highlight. + int ch; // The character to draw in the column. + + char* syn_name; // The highlight group name. Must be free'd. + int syn_attr; // The attribute. Will be set before a redraw. + + int flags; // Additional flags +} colorcol_T; + // The taggy struct is used to store the information about a :tag command. typedef struct taggy { char *tagname; // tag name @@ -1256,7 +1272,7 @@ struct window_S { uint32_t w_p_wbr_flags; // flags for 'winbar' uint32_t w_p_fde_flags; // flags for 'foldexpr' uint32_t w_p_fdt_flags; // flags for 'foldtext' - int *w_p_cc_cols; // array of columns to highlight or NULL + colorcol_T *w_p_cc_cols; // array of columns to highlight or NULL uint8_t w_p_culopt_flags; // flags for cursorline highlighting int w_briopt_min; // minimum width for breakindent diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index e0887ed1d0..c2f0eb9e0e 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -165,12 +165,12 @@ void drawline_free_all_mem(void) /// Advance **color_cols /// /// @return true when there are columns to draw. -static bool advance_color_col(int vcol, int **color_cols) +static bool advance_color_col(int vcol, colorcol_T **color_cols) { - while (**color_cols >= 0 && vcol > **color_cols) { + while ((*color_cols)->col >= 0 && vcol > (*color_cols)->col) { (*color_cols)++; } - return **color_cols >= 0; + return (*color_cols)->col >= 0; } /// Used when 'cursorlineopt' contains "screenline": compute the margins between @@ -1025,7 +1025,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl int save_did_emsg; int eol_hl_off = 0; // 1 if highlighted char after EOL bool draw_color_col = false; // highlight colorcolumn - int *color_cols = NULL; // pointer to according columns array + colorcol_T *color_cols = NULL; // pointer to according columns array #define SPWORDLEN 150 char nextline[SPWORDLEN * 2]; // text with start of the next line int nextlinecol = 0; // column where nextline[] starts @@ -2665,15 +2665,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl if (draw_color_col) { // determine rightmost colorcolumn to possibly draw - for (int i = 0; color_cols[i] >= 0; i++) { - if (rightmost_vcol < color_cols[i]) { - rightmost_vcol = color_cols[i]; + for (int i = 0; color_cols[i].col >= 0; i++) { + if (rightmost_vcol < color_cols[i].col) { + rightmost_vcol = color_cols[i].col; } } } int cuc_attr = win_hl_attr(wp, HLF_CUC); - int mc_attr = win_hl_attr(wp, HLF_MC); int diff_attr = 0; if (wlv.diff_hlf == HLF_TXD) { @@ -2700,8 +2699,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl if (wp->w_p_cuc && VCOL_HLC == wp->w_virtcol) { col_attr = cuc_attr; - } else if (draw_color_col && VCOL_HLC == *color_cols) { - col_attr = hl_combine_attr(wlv.line_attr_lowprio, mc_attr); + } else if (draw_color_col && VCOL_HLC == color_cols->col) { + col_attr = color_cols->syn_attr; + linebuf_char[wlv.off] = schar_from_char(color_cols->ch); } col_attr = hl_combine_attr(col_attr, wlv.line_attr); @@ -2795,9 +2795,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl && lnum != wp->w_cursor.lnum) { vcol_save_attr = wlv.char_attr; wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), wlv.char_attr); - } else if (draw_color_col && VCOL_HLC == *color_cols) { + } else if (draw_color_col && VCOL_HLC == color_cols->col) { vcol_save_attr = wlv.char_attr; - wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), wlv.char_attr); + + if (color_cols->flags & kColorcolForeground) { + wlv.char_attr = hl_combine_attr(wlv.char_attr, color_cols->syn_attr); + } else if (!(color_cols->flags & kColorcolBehind)) { + wlv.char_attr = hl_combine_attr(color_cols->syn_attr, wlv.char_attr); + } } } diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 6cc623cb72..9995ab8345 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1475,6 +1475,19 @@ static void win_update(win_T *wp, DecorProviders *providers) return; } + // Link colorcolumn syn_attrs to syn_names. Needs to be done at a redraw + // as the syn names are volitile and can change. + if (wp->w_p_cc_cols) { + for (int i = 0; wp->w_p_cc_cols[i].col >= 0; ++ i) { + const char* syn_name = wp->w_p_cc_cols[i].syn_name; + if (syn_name == NULL) { + wp->w_p_cc_cols[i].syn_attr = win_hl_attr(wp, HLF_MC); + } else { + wp->w_p_cc_cols[i].syn_attr = syn_name2attr(syn_name); + } + } + } + buf_T *buf = wp->w_buffer; // reset got_int, otherwise regexp won't work diff --git a/src/nvim/window.c b/src/nvim/window.c index bcf245ef93..1a2ce13aba 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4969,6 +4969,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 @@ -5062,7 +5073,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); @@ -7308,10 +7319,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". @@ -7324,9 +7346,16 @@ const char *check_colorcolumn(win_T *wp) } unsigned 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; @@ -7336,7 +7365,7 @@ const 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 @@ -7346,15 +7375,63 @@ const 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; } @@ -7366,23 +7443,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 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 |