diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2021-03-26 00:45:27 +0100 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2021-04-04 18:32:31 +0200 |
commit | a4d3804837e865ca11d2fd0701d23f7eda4da4e4 (patch) | |
tree | 30821b71b5f77edd8b2d195c41f09dc8a8e19231 | |
parent | 76f5c72860b237d66c949dcdeb6967047810b956 (diff) | |
download | rneovim-a4d3804837e865ca11d2fd0701d23f7eda4da4e4.tar.gz rneovim-a4d3804837e865ca11d2fd0701d23f7eda4da4e4.tar.bz2 rneovim-a4d3804837e865ca11d2fd0701d23f7eda4da4e4.zip |
Border: allow to enable/disable specific border edges
-rw-r--r-- | src/nvim/api/private/helpers.c | 33 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 4 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 3 | ||||
-rw-r--r-- | src/nvim/highlight.c | 9 | ||||
-rw-r--r-- | src/nvim/option.c | 9 | ||||
-rw-r--r-- | src/nvim/screen.c | 64 | ||||
-rw-r--r-- | src/nvim/syntax.c | 2 | ||||
-rw-r--r-- | src/nvim/syntax.h | 2 | ||||
-rw-r--r-- | src/nvim/window.c | 19 | ||||
-rw-r--r-- | test/functional/ui/float_spec.lua | 114 |
10 files changed, 211 insertions, 48 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 382244d6b3..c73a9195c3 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1760,10 +1760,12 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) struct { const char *name; schar_T chars[8]; + bool shadow_color; } defaults[] = { - { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" } }, - { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" } }, - { NULL, { { NUL } } }, + { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false }, + { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" }, false }, + { "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true }, + { NULL, { { NUL } } , false }, }; schar_T *chars = fconfig->border_chars; @@ -1807,13 +1809,16 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) api_set_error(err, kErrorTypeValidation, "invalid border char"); return; } - if (!string.size - || mb_string2cells_len((char_u *)string.data, string.size) != 1) { + if (string.size + && mb_string2cells_len((char_u *)string.data, string.size) > 1) { api_set_error(err, kErrorTypeValidation, "border chars must be one cell"); + return; } size_t len = MIN(string.size, sizeof(*chars)-1); - memcpy(chars[i], string.data, len); + if (len) { + memcpy(chars[i], string.data, len); + } chars[i][len] = NUL; hl_ids[i] = hl_id; } @@ -1822,6 +1827,13 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) memcpy(hl_ids+size, hl_ids, sizeof(*hl_ids) * size); size <<= 1; } + if ((chars[7][0] && chars[1][0] && !chars[0][0]) + || (chars[1][0] && chars[3][0] && !chars[2][0]) + || (chars[3][0] && chars[5][0] && !chars[4][0]) + || (chars[5][0] && chars[7][0] && !chars[6][0])) { + api_set_error(err, kErrorTypeValidation, + "corner between used edges must be specified"); + } } else if (style.type == kObjectTypeString) { String str = style.data.string; if (str.size == 0 || strequal(str.data, "none")) { @@ -1832,6 +1844,15 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) if (strequal(str.data, defaults[i].name)) { memcpy(chars, defaults[i].chars, sizeof(defaults[i].chars)); memset(hl_ids, 0, 8 * sizeof(*hl_ids)); + if (defaults[i].shadow_color) { + int hl_blend = SYN_GROUP_STATIC("FloatShadow"); + int hl_through = SYN_GROUP_STATIC("FloatShadowThrough"); + hl_ids[2] = hl_through; + hl_ids[3] = hl_blend; + hl_ids[4] = hl_blend; + hl_ids[5] = hl_blend; + hl_ids[6] = hl_through; + } return; } } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3ae944de4d..baf0bed49a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1421,6 +1421,7 @@ void nvim_chan_send(Integer chan, String data, Error *err) /// - "none" No border. This is the default /// - "single" a single line box /// - "double" a double line box +/// - "shadow" a drop shadow effect by blending with the background. /// If it is an array it should be an array of eight items or any divisor of /// eight. The array will specifify the eight chars building up the border /// in a clockwise fashion starting with the top-left corner. As, an @@ -1431,6 +1432,9 @@ void nvim_chan_send(Integer chan, String data, Error *err) /// [ "/", "-", "\\", "|" ] /// or all chars the same as: /// [ "x" ] +/// An empty string can be used to turn off a specific border, for instance: +/// [ "", "", "", ">", "", "", "", "<" ] +/// will only make vertical borders but not horizontal ones. /// By default `FloatBorder` highlight is used which links to `VertSplit` /// when not defined. It could also be specified by character: /// [ {"+", "MyCorner"}, {"x", "MyBorder"} ] diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index b36b7beab8..b57e58929e 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1085,6 +1085,7 @@ typedef struct { bool focusable; WinStyle style; bool border; + bool shadow; schar_T border_chars[8]; int border_hl_ids[8]; int border_attr[8]; @@ -1266,7 +1267,7 @@ struct window_S { int w_height_request; int w_width_request; - int w_border_adj; + int w_border_adj[4]; // top, right, bottom, left // outer size of window grid, including border int w_height_outer; int w_width_outer; diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 329c448cf0..79801262cb 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -8,6 +8,7 @@ #include "nvim/highlight_defs.h" #include "nvim/map.h" #include "nvim/message.h" +#include "nvim/option.h" #include "nvim/popupmnu.h" #include "nvim/screen.h" #include "nvim/syntax.h" @@ -342,16 +343,24 @@ void update_window_hl(win_T *wp, bool invalid) wp->w_hl_attrs[hlf] = attr; } + wp->w_float_config.shadow = false; if (wp->w_floating && wp->w_float_config.border) { for (int i = 0; i < 8; i++) { int attr = wp->w_hl_attrs[HLF_BORDER]; if (wp->w_float_config.border_hl_ids[i]) { attr = hl_get_ui_attr(HLF_BORDER, wp->w_float_config.border_hl_ids[i], false); + HlAttrs a = syn_attr2entry(attr); + if (a.hl_blend) { + wp->w_float_config.shadow = true; + } } wp->w_float_config.border_attr[i] = attr; } } + + // shadow might cause blending + check_blending(wp); } /// Gets HL_UNDERLINE highlight. diff --git a/src/nvim/option.c b/src/nvim/option.c index 4c43521f4d..914b92618c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3437,6 +3437,12 @@ skip: return NULL; // no error } +void check_blending(win_T *wp) +{ + wp->w_grid_alloc.blending = + wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow); +} + /// Handle setting 'listchars' or 'fillchars'. /// Assume monocell characters @@ -4380,7 +4386,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, // 'floatblend' curwin->w_p_winbl = MAX(MIN(curwin->w_p_winbl, 100), 0); curwin->w_hl_needs_update = true; - curwin->w_grid_alloc.blending = curwin->w_p_winbl > 0; + check_blending(curwin); } @@ -5895,6 +5901,7 @@ void didset_window_options(win_T *wp) set_chars_option(wp, &wp->w_p_fcs, true); set_chars_option(wp, &wp->w_p_lcs, true); parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl + check_blending(wp); wp->w_grid_alloc.blending = wp->w_p_winbl > 0; } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index db033ee1ed..24bef27ca1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5454,32 +5454,50 @@ static void win_redr_border(win_T *wp) schar_T *chars = wp->w_float_config.border_chars; int *attrs = wp->w_float_config.border_attr; - int endrow = grid->Rows-1, endcol = grid->Columns-1; - grid_puts_line_start(grid, 0); - grid_put_schar(grid, 0, 0, chars[0], attrs[0]); - for (int i = 1; i < endcol; i++) { - grid_put_schar(grid, 0, i, chars[1], attrs[1]); - } - grid_put_schar(grid, 0, endcol, chars[2], attrs[2]); - grid_puts_line_flush(false); + int *adj = wp->w_border_adj; + int irow = wp->w_height_inner, icol = wp->w_width_inner; - for (int i = 1; i < endrow; i++) { - grid_puts_line_start(grid, i); - grid_put_schar(grid, i, 0, chars[7], attrs[7]); - grid_puts_line_flush(false); - grid_puts_line_start(grid, i); - grid_put_schar(grid, i, endcol, chars[3], attrs[3]); + if (adj[0]) { + grid_puts_line_start(grid, 0); + if (adj[3]) { + grid_put_schar(grid, 0, 0, chars[0], attrs[0]); + } + for (int i = 0; i < icol; i++) { + grid_put_schar(grid, 0, i+adj[3], chars[1], attrs[1]); + } + if (adj[1]) { + grid_put_schar(grid, 0, icol+adj[3], chars[2], attrs[2]); + } grid_puts_line_flush(false); } - grid_puts_line_start(grid, endrow); - grid_put_schar(grid, endrow, 0, chars[6], attrs[6]); - for (int i = 1; i < endcol; i++) { - grid_put_schar(grid, endrow, i, chars[5], attrs[5]); + for (int i = 0; i < irow; i++) { + if (adj[3]) { + grid_puts_line_start(grid, i+adj[0]); + grid_put_schar(grid, i+adj[0], 0, chars[7], attrs[7]); + grid_puts_line_flush(false); + } + if (adj[1]) { + int ic = (i == 0 && !adj[0] && chars[2][0]) ? 2 : 3; + grid_puts_line_start(grid, i+adj[0]); + grid_put_schar(grid, i+adj[0], icol+adj[3], chars[ic], attrs[ic]); + grid_puts_line_flush(false); + } + } + + if (adj[2]) { + grid_puts_line_start(grid, irow+adj[0]); + if (adj[3]) { + grid_put_schar(grid, irow+adj[0], 0, chars[6], attrs[6]); + } + for (int i = 0; i < icol; i++) { + int ic = (i == 0 && !adj[3] && chars[6][0]) ? 6 : 5; + grid_put_schar(grid, irow+adj[0], i+adj[3], chars[ic], attrs[ic]); + } + grid_put_schar(grid, irow+adj[0], icol+adj[3], chars[4], attrs[4]); + grid_puts_line_flush(false); } - grid_put_schar(grid, endrow, endcol, chars[4], attrs[4]); - grid_puts_line_flush(false); } // Low-level functions to manipulate invidual character cells on the @@ -6247,7 +6265,7 @@ void win_grid_alloc(win_T *wp) grid_alloc(grid_allocated, total_rows, total_cols, wp->w_grid_alloc.valid, false); grid_allocated->valid = true; - if (wp->w_border_adj) { + if (wp->w_floating && wp->w_float_config.border) { wp->w_redr_border = true; } was_resized = true; @@ -6267,8 +6285,8 @@ void win_grid_alloc(win_T *wp) if (want_allocation) { grid->target = grid_allocated; - grid->row_offset = wp->w_border_adj; - grid->col_offset = wp->w_border_adj; + grid->row_offset = wp->w_border_adj[0]; + grid->col_offset = wp->w_border_adj[3]; } else { grid->target = &default_grid; grid->row_offset = wp->w_winrow; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index f1eb7879b0..825aef1465 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -6047,6 +6047,8 @@ static const char *highlight_init_both[] = { "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", "default link FloatBorder VertSplit", + "default FloatShadow blend=80 guibg=Black", + "default FloatShadowThrough blend=100 guibg=Black", "RedrawDebugNormal cterm=reverse gui=reverse", "RedrawDebugClear ctermbg=Yellow guibg=Yellow", "RedrawDebugComposed ctermbg=Green guibg=Green", diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h index 9fbad74f64..38f848f178 100644 --- a/src/nvim/syntax.h +++ b/src/nvim/syntax.h @@ -27,6 +27,8 @@ #define HL_CONCEAL 0x20000 /* can be concealed */ #define HL_CONCEALENDS 0x40000 /* can be concealed */ +#define SYN_GROUP_STATIC(s) syn_check_group((char_u *)S_LEN(s)) + typedef struct { char *name; RgbValue color; diff --git a/src/nvim/window.c b/src/nvim/window.c index 859f4353b3..c482d265ff 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -668,7 +668,11 @@ void win_config_float(win_T *wp, FloatConfig fconfig) } bool change_external = fconfig.external != wp->w_float_config.external; - bool change_border = fconfig.border != wp->w_float_config.border; + bool change_border = (fconfig.border != wp->w_float_config.border + || memcmp(fconfig.border_hl_ids, + wp->w_float_config.border_hl_ids, + sizeof fconfig.border_hl_ids)); + wp->w_float_config = fconfig; @@ -5731,9 +5735,16 @@ void win_set_inner_size(win_T *wp) terminal_check_size(wp->w_buffer->terminal); } - wp->w_border_adj = wp->w_floating && wp->w_float_config.border ? 1 : 0; - wp->w_height_outer = wp->w_height_inner + 2 * wp->w_border_adj; - wp->w_width_outer = wp->w_width_inner + 2 * wp->w_border_adj; + bool has_border = wp->w_floating && wp->w_float_config.border; + for (int i = 0; i < 4; i++) { + wp->w_border_adj[i] = + has_border && wp->w_float_config.border_chars[2 * i+1][0]; + } + + wp->w_height_outer = (wp->w_height_inner + + wp->w_border_adj[0] + wp->w_border_adj[2]); + wp->w_width_outer = (wp->w_width_inner + + wp->w_border_adj[1] + wp->w_border_adj[3]); } /// Set the width of a window. diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 664b8e7ab7..965b9f160c 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -42,6 +42,10 @@ describe('float window', function() [20] = {bold = true, foreground = Screen.colors.Brown}, [21] = {background = Screen.colors.Gray90}, [22] = {background = Screen.colors.LightRed}, + [23] = {foreground = Screen.colors.Black, background = Screen.colors.White}; + [24] = {foreground = Screen.colors.Black, background = Screen.colors.Grey80}; + [25] = {blend = 100, background = Screen.colors.Gray0}; + [26] = {blend = 80, background = Screen.colors.Gray0}; } it('behavior', function() @@ -644,7 +648,6 @@ describe('float window', function() end meths.win_set_config(win, {border="single"}) - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -689,7 +692,6 @@ describe('float window', function() -- support: ascii char, UTF-8 char, composed char, highlight per char meths.win_set_config(win, {border={"x", {"å", "ErrorMsg"}, {"\\"}, {"n̈̊", "Search"}}}) - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -710,10 +712,10 @@ describe('float window', function() ## grid 3 | ## grid 5 - {5:xååååååååå\}| - {5:n̈̊}{1: halloj! }{5:n̈̊}| - {5:n̈̊}{1: BORDAA }{5:n̈̊}| - {5:\åååååååååx}| + {5:x}{7:ååååååååå}{5:\}| + {17:n̈̊}{1: halloj! }{17:n̈̊}| + {17:n̈̊}{1: BORDAA }{17:n̈̊}| + {5:\}{7:ååååååååå}{5:x}| ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ @@ -772,6 +774,97 @@ describe('float window', function() | ]]} end + + meths.win_set_config(win, {border={"", "", "", ">", "", "", "", "<"}}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:<}{1: halloj! }{5:>}| + {5:<}{1: BORDAA }{5:>}| + ]], float_pos={ + [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:<}{1: halloj! }{5:>}{0: }| + {0:~ }{5:<}{1: BORDAA }{5:>}{0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + + insert [[ + neeed some dummy + background text + to show the effect + of color blending + of border shadow + ]] + + meths.win_set_config(win, {border="shadow"}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + neeed some dummy | + background text | + to show the effect | + of color blending | + of border shadow | + ^ | + ## grid 3 + | + ## grid 5 + {1: halloj! }{25: }| + {1: BORDAA }{26: }| + {25: }{26: }| + ]], float_pos={ + [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + neeed some dummy | + background text | + to {1: halloj! }{23:e}ffect | + of {1: BORDAA }{24:n}ding | + of {23:b}{24:order sha}dow | + ^ | + | + ]]} + end end) it('with border show popupmenu', function() @@ -835,7 +928,6 @@ describe('float window', function() end feed 'i<c-x><c-p>' - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -873,12 +965,8 @@ describe('float window', function() {1: abb }| {13: acc }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 1, 0, 5, true }, - [6] = { { - id = -1 - }, "NW", 5, 4, 0, false } + [5] = { { id = 1002 }, "NW", 1, 0, 5, true }, + [6] = { { id = -1 }, "NW", 5, 4, 0, false } }, win_viewport={ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3}; |