From 718896032196b51684926039746f9288750e9585 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sat, 27 Aug 2022 20:52:08 -0600 Subject: feat(colorcolchar): add the option "colorcol" to the fillchars setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option will let neovim draw a character in the colorcolumn when there is no other character occupying that spot. For example, I'm someone who likes the elegance of seeing a 1px wide line at the 80 character mark, rather than a rectangle the width of a cell at that mark. To accomplish this, I run :set colorcol=80 :set fillchars=colorcol:│ of course ':' and '.' are good ASCII alteratives. --- runtime/doc/options.txt | 5 ++++- src/nvim/buffer_defs.h | 1 + src/nvim/drawline.c | 2 ++ src/nvim/screen.c | 1 + test/functional/ui/highlight_spec.lua | 7 ++++--- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 9e396dd3e8..15de976737 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1350,7 +1350,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'colorcolumn' 'cc' string (default "") local to window 'colorcolumn' is a comma-separated list of screen columns that are - highlighted with ColorColumn |hl-ColorColumn|. Useful to align + highlighted with ColorColumn |hl-ColorColumn| and drawn using the + colocol option from 'fillchars'. Useful to align text. Will make screen redrawing slower. The screen column can be an absolute number, or a number preceded with '+' or '-', which is added to or subtracted from 'textwidth'. > @@ -2478,6 +2479,7 @@ A jump table for the options with a short description can be found at |Q_op|. diff '-' deleted lines of the 'diff' option msgsep ' ' message separator 'display' eob '~' empty lines at the end of a buffer + colorcol:c ' ' character to display in the colorcolumn Any one that is omitted will fall back to the default. For "stl" and "stlnc" the space will be used when there is highlighting, '^' or '=' @@ -2515,6 +2517,7 @@ A jump table for the options with a short description can be found at |Q_op|. fold Folded |hl-Folded| diff DiffDelete |hl-DiffDelete| eob EndOfBuffer |hl-EndOfBuffer| + colorcol:c ColorColumn |hl-ColorColumn| *'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'* 'fixendofline' 'fixeol' boolean (default on) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 58bdd2c0a8..f276ac771d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1219,6 +1219,7 @@ struct window_S { int diff; int msgsep; int eob; + int colorcol; } w_p_fcs_chars; /* diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 9132d6666e..b97d323ef2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2334,6 +2334,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col_attr = cuc_attr; } else if (draw_color_col && VCOL_HLC == *color_cols) { col_attr = mc_attr; + c = wp->w_p_fcs_chars.colorcol; + schar_from_char(linebuf_char[off], c); } col_attr = hl_combine_attr(col_attr, line_attr); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 9c1064d608..eb4eef6e31 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1328,6 +1328,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool apply) { &wp->w_p_fcs_chars.diff, "diff", '-' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.eob, "eob", '~' }, + { &wp->w_p_fcs_chars.colorcol, "colorcol", ' ' }, }; struct chars_tab lcs_tab[] = { diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4e3d62509c..b0b2920ae9 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -856,13 +856,14 @@ describe('CursorLine and CursorLineNr highlights', function() | ]]) + command('set fillchars=colorcol:|') command('set colorcolumn=3') feed('i ') screen:expect([[ - {1:{} {7: } | + {1:{} {7:|} | "{2:a}{7:"} : {3:abc} {3:// 10;} | - {1:}} {7: } | - {5: ^ }{7: }{5: }| + {1:}} {7:|} | + {5: ^ }{7:|}{5: }| | ]]) end) -- cgit From 33c115d92a47fb62b06d27074bd7270d30c1e637 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sun, 21 Aug 2022 12:02:45 -0600 Subject: feat(colorcolchar): fix typo for colorcolchar documentation --- runtime/doc/options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 15de976737..d41f1cf1cd 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1351,7 +1351,7 @@ A jump table for the options with a short description can be found at |Q_op|. local to window 'colorcolumn' is a comma-separated list of screen columns that are highlighted with ColorColumn |hl-ColorColumn| and drawn using the - colocol option from 'fillchars'. Useful to align + "colorcol" option from 'fillchars'. Useful to align text. Will make screen redrawing slower. The screen column can be an absolute number, or a number preceded with '+' or '-', which is added to or subtracted from 'textwidth'. > -- cgit From 2a1e15d2a76d1e0a0a177d87f233e7ceecb25ade Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sun, 21 Aug 2022 12:32:25 -0600 Subject: feat(colorcolchar): rename colorcol in fillchars to colorc Rename the colorcol option in fillchars to the more terse colorc. --- runtime/doc/options.txt | 8 ++++---- src/nvim/buffer_defs.h | 2 +- src/nvim/drawline.c | 2 +- src/nvim/screen.c | 2 +- test/functional/ui/highlight_spec.lua | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d41f1cf1cd..73ab36ba0e 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1351,10 +1351,10 @@ A jump table for the options with a short description can be found at |Q_op|. local to window 'colorcolumn' is a comma-separated list of screen columns that are highlighted with ColorColumn |hl-ColorColumn| and drawn using the - "colorcol" option from 'fillchars'. Useful to align - text. Will make screen redrawing slower. - The screen column can be an absolute number, or a number preceded with - '+' or '-', which is added to or subtracted from 'textwidth'. > + "colorc" option from 'fillchars'. Useful to align text. Will make + screen redrawing slower. The screen column can be an absolute number, + or a number preceded with '+' or '-', which is added to or subtracted + from 'textwidth'. > :set cc=+1 " highlight column after 'textwidth' :set cc=+1,+2,+3 " highlight three columns after 'textwidth' diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index f276ac771d..7e47496291 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1219,7 +1219,7 @@ struct window_S { int diff; int msgsep; int eob; - int colorcol; + int colorc; } w_p_fcs_chars; /* diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index b97d323ef2..85ea033eb0 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2334,7 +2334,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col_attr = cuc_attr; } else if (draw_color_col && VCOL_HLC == *color_cols) { col_attr = mc_attr; - c = wp->w_p_fcs_chars.colorcol; + c = wp->w_p_fcs_chars.colorc; schar_from_char(linebuf_char[off], c); } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index eb4eef6e31..954068a388 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1328,7 +1328,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool apply) { &wp->w_p_fcs_chars.diff, "diff", '-' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.eob, "eob", '~' }, - { &wp->w_p_fcs_chars.colorcol, "colorcol", ' ' }, + { &wp->w_p_fcs_chars.colorc, "colorc", ' ' }, }; struct chars_tab lcs_tab[] = { diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index b0b2920ae9..87c632c6e0 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -856,7 +856,7 @@ describe('CursorLine and CursorLineNr highlights', function() | ]]) - command('set fillchars=colorcol:|') + command('set fillchars=colorc:|') command('set colorcolumn=3') feed('i ') screen:expect([[ -- cgit From f8bddb98545c09a5b861e9d4e0f4edd1e920a4b3 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Wed, 24 Aug 2022 11:41:47 -0600 Subject: feat(colorcolchar): fix highlight_spec.lua Problem was interpreting a '|' as next command, causing vim to interpret set fillchars+=colorcol:| incorrectly --- test/functional/ui/highlight_spec.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 87c632c6e0..1cfbd09852 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -856,14 +856,14 @@ describe('CursorLine and CursorLineNr highlights', function() | ]]) - command('set fillchars=colorc:|') + command('set fillchars=colorc:.') command('set colorcolumn=3') feed('i ') screen:expect([[ - {1:{} {7:|} | + {1:{} {7:.} | "{2:a}{7:"} : {3:abc} {3:// 10;} | - {1:}} {7:|} | - {5: ^ }{7:|}{5: }| + {1:}} {7:.} | + {5: ^ }{7:.}{5: }| | ]]) end) -- cgit From de6bcd7e7b3290b6d164293f414dcc13461abdd6 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Wed, 24 Aug 2022 11:45:07 -0600 Subject: feat(colorcolchar): revert "feat: rename colorcol in fillchars to colorc" This reverts commit 234959abbfcf075cb09304b00fc391780580056d and renames the option 'colorc' -> 'colorcol' again. --- runtime/doc/options.txt | 8 ++++---- src/nvim/buffer_defs.h | 2 +- src/nvim/drawline.c | 2 +- src/nvim/screen.c | 2 +- test/functional/ui/highlight_spec.lua | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 73ab36ba0e..d41f1cf1cd 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1351,10 +1351,10 @@ A jump table for the options with a short description can be found at |Q_op|. local to window 'colorcolumn' is a comma-separated list of screen columns that are highlighted with ColorColumn |hl-ColorColumn| and drawn using the - "colorc" option from 'fillchars'. Useful to align text. Will make - screen redrawing slower. The screen column can be an absolute number, - or a number preceded with '+' or '-', which is added to or subtracted - from 'textwidth'. > + "colorcol" option from 'fillchars'. Useful to align + text. Will make screen redrawing slower. + The screen column can be an absolute number, or a number preceded with + '+' or '-', which is added to or subtracted from 'textwidth'. > :set cc=+1 " highlight column after 'textwidth' :set cc=+1,+2,+3 " highlight three columns after 'textwidth' diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 7e47496291..f276ac771d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1219,7 +1219,7 @@ struct window_S { int diff; int msgsep; int eob; - int colorc; + int colorcol; } w_p_fcs_chars; /* diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 85ea033eb0..b97d323ef2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2334,7 +2334,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col_attr = cuc_attr; } else if (draw_color_col && VCOL_HLC == *color_cols) { col_attr = mc_attr; - c = wp->w_p_fcs_chars.colorc; + c = wp->w_p_fcs_chars.colorcol; schar_from_char(linebuf_char[off], c); } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 954068a388..eb4eef6e31 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1328,7 +1328,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool apply) { &wp->w_p_fcs_chars.diff, "diff", '-' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.eob, "eob", '~' }, - { &wp->w_p_fcs_chars.colorc, "colorc", ' ' }, + { &wp->w_p_fcs_chars.colorcol, "colorcol", ' ' }, }; struct chars_tab lcs_tab[] = { diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 1cfbd09852..695cdf522a 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -856,7 +856,7 @@ describe('CursorLine and CursorLineNr highlights', function() | ]]) - command('set fillchars=colorc:.') + command('set fillchars=colorcol:.') command('set colorcolumn=3') feed('i ') screen:expect([[ -- cgit From 4066fa85abef16fa23c30e94dc4d2bfb3b9c4545 Mon Sep 17 00:00:00 2001 From: Joshua Rahm Date: Sun, 28 Aug 2022 17:11:44 -0600 Subject: feat(colorcolchar): update runtime/doc/options.txt Co-authored-by: zeertzjq --- runtime/doc/options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d41f1cf1cd..6d7c034869 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2479,7 +2479,7 @@ A jump table for the options with a short description can be found at |Q_op|. diff '-' deleted lines of the 'diff' option msgsep ' ' message separator 'display' eob '~' empty lines at the end of a buffer - colorcol:c ' ' character to display in the colorcolumn + colorcol ' ' character to display in the colorcolumn Any one that is omitted will fall back to the default. For "stl" and "stlnc" the space will be used when there is highlighting, '^' or '=' -- cgit From daa55ee86df76dee028947db527a4f999569f5f8 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 31 Jan 2023 23:07:51 +0000 Subject: feat(colorcolchar): remove existing colorcolumnchar in the fillchars. Make way for more flexibility --- src/nvim/buffer_defs.h | 1 - src/nvim/drawline.c | 2 +- src/nvim/screen.c | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 78ac10a7d6..f01edd1ad2 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1175,7 +1175,6 @@ struct window_S { int diff; int msgsep; int eob; - int colorcol; int lastline; } w_p_fcs_chars; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 28f19a95e0..66e24e960f 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2521,7 +2521,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col_attr = cuc_attr; } else if (draw_color_col && VCOL_HLC == *color_cols) { col_attr = mc_attr; - c = wp->w_p_fcs_chars.colorcol; + c = ' '; schar_from_char(linebuf_char[off], c); } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ba65a335e6..ebff52cd69 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -885,7 +885,6 @@ char *set_chars_option(win_T *wp, char **varp, bool apply) { &wp->w_p_fcs_chars.diff, "diff", '-' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.eob, "eob", '~' }, - { &wp->w_p_fcs_chars.colorcol, "colorcol", ' ' }, { &wp->w_p_fcs_chars.lastline, "lastline", '@' }, }; -- cgit From a2e3d22928e127385277c472fef6aff96d238ff2 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 31 Jan 2023 23:08:29 +0000 Subject: feat(colorcolchar): make the colorcolumn more flexible This PR creates the ability to optionally decorate the colorcolumn(s) in other ways. Specifically it adds the ability to set: * The highlight group to highlight a colorcolumn with * A character to draw in a colorcolumn * whether the colorcolumn should mix its highlighting with the character in the column. The new syntax for colorcolumn is: set colorcolumn=[+|-][/[/[/]]] By default the char is ' ', and the hl_group is 'ColorColumn' This PR does not change the existing semantics, just adds to them. --- src/nvim/buffer_defs.h | 17 +++++++++- src/nvim/drawline.c | 27 +++++++-------- src/nvim/drawscreen.c | 13 ++++++++ src/nvim/window.c | 91 ++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 120 insertions(+), 28 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index f01edd1ad2..dfcbb28c69 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -93,6 +93,21 @@ typedef uint64_t disptick_T; // display tick type #include "nvim/syntax_defs.h" #include "nvim/terminal.h" +typedef enum { + kColorcolBehind = 1 +} 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 @@ -1335,7 +1350,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 long w_p_siso; // 'sidescrolloff' local value long w_p_so; // 'scrolloff' local value diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 66e24e960f..ee6af01942 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -84,12 +84,12 @@ typedef struct { /// 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 @@ -660,7 +660,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, 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 bool has_spell = false; // this buffer has spell checking #define SPWORDLEN 150 char nextline[SPWORDLEN * 2]; // text with start of the next line @@ -2483,15 +2483,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (draw_color_col) { // determine rightmost colorcolumn to possibly draw - for (i = 0; color_cols[i] >= 0; i++) { - if (rightmost_vcol < color_cols[i]) { - rightmost_vcol = color_cols[i]; + for (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 (diff_hlf == HLF_TXD) { @@ -2519,9 +2518,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) { col_attr = cuc_attr; - } else if (draw_color_col && VCOL_HLC == *color_cols) { - col_attr = mc_attr; - c = ' '; + } else if (draw_color_col && VCOL_HLC == color_cols->col) { + col_attr = color_cols->syn_attr; + c = color_cols->ch; schar_from_char(linebuf_char[off], c); } @@ -2609,9 +2608,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && lnum != wp->w_cursor.lnum) { vcol_save_attr = char_attr; char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), char_attr); - } else if (draw_color_col && VCOL_HLC == *color_cols) { + } else if (draw_color_col && VCOL_HLC == color_cols->col) { vcol_save_attr = char_attr; - char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), char_attr); + if (!(color_cols->flags & kColorcolBehind)) { + char_attr = hl_combine_attr(color_cols->syn_attr, char_attr); + } } } diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 04c342e068..f5f72b711f 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1016,6 +1016,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 05f84b5a91..cf5d0013a3 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5061,6 +5061,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 @@ -5154,7 +5165,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); @@ -7395,10 +7406,11 @@ 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; + return ((const colorcol_T *)a)->col - ((const colorcol_T *)b)->col; } /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". @@ -7411,9 +7423,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; @@ -7423,7 +7442,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 @@ -7433,15 +7452,58 @@ 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; + + default: + return e_invarg; + } + } + } + + if (!do_skip) { + color_cols[count++] = (colorcol_T) { + .col = col - 1, // 1-based to 0-based + .syn_attr = 0, + .ch = ch, + .syn_name = syn_name[0] == 0 ? NULL : xstrdup(syn_name), + .flags = flags, + }; + } + if (*s == NUL) { break; } @@ -7453,23 +7515,24 @@ 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]) { + if (j == 0 || wp->w_p_cc_cols[j - 1].col != color_cols[i].col) { wp->w_p_cc_cols[j++] = color_cols[i]; } } - 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 -- cgit From 5bb0758567e953f15335d284f31ae14947339c7a Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 31 Jan 2023 23:43:46 +0000 Subject: feat(colorcolchar): make colorcol qsort() stable by including index --- src/nvim/window.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/nvim/window.c b/src/nvim/window.c index cf5d0013a3..5e99cec015 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -7410,7 +7410,17 @@ static bool frame_check_width(const frame_T *topfrp, int width) /// Compares the column numbers static int colorcol_cmp(const void *a, const void *b) { - return ((const colorcol_T *)a)->col - ((const colorcol_T *)b)->col; + 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". @@ -7495,13 +7505,14 @@ char *check_colorcolumn(win_T *wp) } if (!do_skip) { - color_cols[count++] = (colorcol_T) { - .col = col - 1, // 1-based to 0-based - .syn_attr = 0, + 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) { @@ -7528,7 +7539,9 @@ char *check_colorcolumn(win_T *wp) for (unsigned int i = 0; i < count; i++) { // skip duplicates if (j == 0 || wp->w_p_cc_cols[j - 1].col != color_cols[i].col) { - wp->w_p_cc_cols[j++] = color_cols[i]; + 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; } } memset(&wp->w_p_cc_cols[j], 0, sizeof(wp->w_p_cc_cols[j])); -- cgit From d9c904f85a23a496df4eb6be42aa43f007b22d50 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Thu, 2 Feb 2023 17:47:11 +0000 Subject: feat(colorcolchar): implement 'foreground' flag This flag, denoted by an 'f', will force the character over the colorcolumn to take on the colorcolumn's highlight, discarding any highlight the character would have had otherwise. This is the inverse of the 'background' flag, where the colorcolumn will take the highlight of the character discarding any highlight it otherwise would have had. --- src/nvim/buffer_defs.h | 3 ++- src/nvim/drawline.c | 5 ++++- src/nvim/window.c | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index dfcbb28c69..5ae6f55ad8 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -94,7 +94,8 @@ typedef uint64_t disptick_T; // display tick type #include "nvim/terminal.h" typedef enum { - kColorcolBehind = 1 + kColorcolBehind = 1, + kColorcolForeground = 2, } colorcol_flags_T; // Structure to define data associated with a colorcolumn. diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index ee6af01942..031ad39f75 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -2610,7 +2610,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), char_attr); } else if (draw_color_col && VCOL_HLC == color_cols->col) { vcol_save_attr = char_attr; - if (!(color_cols->flags & kColorcolBehind)) { + + if (color_cols->flags & kColorcolForeground) { + char_attr = hl_combine_attr(char_attr, color_cols->syn_attr); + } else if (!(color_cols->flags & kColorcolBehind)) { char_attr = hl_combine_attr(color_cols->syn_attr, char_attr); } } diff --git a/src/nvim/window.c b/src/nvim/window.c index 5e99cec015..16405f87b6 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -7498,6 +7498,10 @@ char *check_colorcolumn(win_T *wp) flags |= kColorcolBehind; break; + case 'f': + flags |= kColorcolForeground; + break; + default: return e_invarg; } -- cgit