mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Border: allow to enable/disable specific border edges
This commit is contained in:
parent
76f5c72860
commit
a4d3804837
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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"} ]
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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};
|
||||
|
Loading…
Reference in New Issue
Block a user