aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2021-03-26 00:45:27 +0100
committerBjörn Linse <bjorn.linse@gmail.com>2021-04-04 18:32:31 +0200
commita4d3804837e865ca11d2fd0701d23f7eda4da4e4 (patch)
tree30821b71b5f77edd8b2d195c41f09dc8a8e19231
parent76f5c72860b237d66c949dcdeb6967047810b956 (diff)
downloadrneovim-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.c33
-rw-r--r--src/nvim/api/vim.c4
-rw-r--r--src/nvim/buffer_defs.h3
-rw-r--r--src/nvim/highlight.c9
-rw-r--r--src/nvim/option.c9
-rw-r--r--src/nvim/screen.c64
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/syntax.h2
-rw-r--r--src/nvim/window.c19
-rw-r--r--test/functional/ui/float_spec.lua114
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};