Border: allow to enable/disable specific border edges

This commit is contained in:
Björn Linse
2021-03-26 00:45:27 +01:00
parent 76f5c72860
commit a4d3804837
10 changed files with 211 additions and 48 deletions

View File

@@ -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;
}
}

View File

@@ -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"} ]

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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",

View File

@@ -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;

View File

@@ -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.