feat(option): add winborder option

Problem:
There is currently no global option to define the default border style for floating windows. This leads to repetitive code when developers need consistent styling across multiple floating windows.

Solution:
Introduce a global option winborder to specify the default border style for floating windows. When a floating window is created without explicitly specifying a border style, the value of the winborder option will be used. This simplifies configuration and ensures consistency in floating window appearance.
This commit is contained in:
glepnir 2024-08-25 18:15:03 +08:00
parent 540def7d2c
commit c14954a840
10 changed files with 196 additions and 49 deletions

View File

@ -3238,20 +3238,12 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
`eob` flag of 'fillchars' to a space char, and clearing `eob` flag of 'fillchars' to a space char, and clearing
the |hl-EndOfBuffer| region in 'winhighlight'. the |hl-EndOfBuffer| region in 'winhighlight'.
• border: Style of (optional) window border. This can either • border: Style of (optional) window border. This can either
be a string or an array. The string values are be a string or an array. The string values are the same as
• "none": No border (default). those described in 'winborder'. If it is an array, it
• "single": A single line box. should have a length of eight or any divisor of eight. The
• "double": A double line box. array will specify the eight chars building up the border
• "rounded": Like "single", but with rounded corners in a clockwise fashion starting with the top-left corner.
("╭" etc.). As an example, the double box style could be specified as: >
• "solid": Adds padding by a single whitespace cell.
• "shadow": A drop shadow effect by blending with the
background.
• If it is an array, it should have a length of eight or
any divisor of eight. The array will specify the eight
chars building up the border in a clockwise fashion
starting with the top-left corner. As an example, the
double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
< <
If the number of chars are less than eight, they will be If the number of chars are less than eight, they will be

View File

@ -7105,6 +7105,18 @@ A jump table for the options with a short description can be found at |Q_op|.
UI-dependent. Works best with RGB colors. 'termguicolors' UI-dependent. Works best with RGB colors. 'termguicolors'
*'winborder'*
'winborder' string (default "")
global
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("╭" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
*'window'* *'wi'* *'window'* *'wi'*
'window' 'wi' number (default screen height - 1) 'window' 'wi' number (default screen height - 1)
global global

View File

@ -1806,14 +1806,8 @@ function vim.api.nvim_open_term(buffer, opts) end
--- 'fillchars' to a space char, and clearing the --- 'fillchars' to a space char, and clearing the
--- `hl-EndOfBuffer` region in 'winhighlight'. --- `hl-EndOfBuffer` region in 'winhighlight'.
--- - border: Style of (optional) window border. This can either be a string --- - border: Style of (optional) window border. This can either be a string
--- or an array. The string values are --- or an array. The string values are the same as those described in 'winborder'.
--- - "none": No border (default). --- If it is an array, it should have a length of eight or any divisor of
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
--- - If it is an array, it should have a length of eight or any divisor of
--- eight. The array will specify the eight chars building up the border --- eight. The array will specify the eight chars building up the border
--- in a clockwise fashion starting with the top-left corner. As an --- in a clockwise fashion starting with the top-left corner. As an
--- example, the double box style could be specified as: --- example, the double box style could be specified as:

View File

@ -7778,6 +7778,19 @@ vim.o.winbl = vim.o.winblend
vim.wo.winblend = vim.o.winblend vim.wo.winblend = vim.o.winblend
vim.wo.winbl = vim.wo.winblend vim.wo.winbl = vim.wo.winblend
--- Defines the default border style of floating windows. The default value
--- is empty, which is equivalent to "none". Valid values include:
--- - "none": No border.
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
---
--- @type string
vim.o.winborder = ""
vim.go.winborder = vim.o.winborder
--- Window height used for `CTRL-F` and `CTRL-B` when there is only one --- Window height used for `CTRL-F` and `CTRL-B` when there is only one
--- window and the value is smaller than 'lines' minus one. The screen --- window and the value is smaller than 'lines' minus one. The screen
--- will scroll 'window' minus two lines, with a minimum of one. --- will scroll 'window' minus two lines, with a minimum of one.

View File

@ -160,14 +160,8 @@
/// 'fillchars' to a space char, and clearing the /// 'fillchars' to a space char, and clearing the
/// |hl-EndOfBuffer| region in 'winhighlight'. /// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string /// - border: Style of (optional) window border. This can either be a string
/// or an array. The string values are /// or an array. The string values are the same as those described in 'winborder'.
/// - "none": No border (default). /// If it is an array, it should have a length of eight or any divisor of
/// - "single": A single line box.
/// - "double": A double line box.
/// - "rounded": Like "single", but with rounded corners ("╭" etc.).
/// - "solid": Adds padding by a single whitespace cell.
/// - "shadow": A drop shadow effect by blending with the background.
/// - If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border /// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an /// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as: /// example, the double box style could be specified as:
@ -937,11 +931,11 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err)
char chars[8][MAX_SCHAR_SIZE]; char chars[8][MAX_SCHAR_SIZE];
bool shadow_color; bool shadow_color;
} defaults[] = { } defaults[] = {
{ "double", { "", "", "", "", "", "", "", "" }, false }, { opt_winborder_values[0], { "", "", "", "", "", "", "", "" }, false },
{ "single", { "", "", "", "", "", "", "", "" }, false }, { opt_winborder_values[1], { "", "", "", "", "", "", "", "" }, false },
{ "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true }, { opt_winborder_values[2], { "", "", " ", " ", " ", " ", " ", "" }, true },
{ "rounded", { "", "", "", "", "", "", "", "" }, false }, { opt_winborder_values[3], { "", "", "", "", "", "", "", "" }, false },
{ "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false }, { opt_winborder_values[4], { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ NULL, { { NUL } }, false }, { NULL, { { NUL } }, false },
}; };
@ -1282,12 +1276,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
} }
} }
if (HAS_KEY_X(config, border)) { if (HAS_KEY_X(config, border) || *p_winbd != NUL) {
if (is_split) { if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'"); api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
goto fail; goto fail;
} }
parse_border_style(config->border, fconfig, err); Object style = config->border.type != kObjectTypeNil ? config->border : CSTR_AS_OBJ(p_winbd);
parse_border_style(style, fconfig, err);
if (ERROR_SET(err)) { if (ERROR_SET(err)) {
goto fail; goto fail;
} }

View File

@ -608,6 +608,7 @@ EXTERN OptInt p_wcm; ///< 'wildcharm'
EXTERN int p_wic; ///< 'wildignorecase' EXTERN int p_wic; ///< 'wildignorecase'
EXTERN char *p_wim; ///< 'wildmode' EXTERN char *p_wim; ///< 'wildmode'
EXTERN int p_wmnu; ///< 'wildmenu' EXTERN int p_wmnu; ///< 'wildmenu'
EXTERN char *p_winbd; ///< 'winborder'
EXTERN OptInt p_wh; ///< 'winheight' EXTERN OptInt p_wh; ///< 'winheight'
EXTERN OptInt p_wmh; ///< 'winminheight' EXTERN OptInt p_wmh; ///< 'winminheight'
EXTERN OptInt p_wmw; ///< 'winminwidth' EXTERN OptInt p_wmw; ///< 'winminwidth'

View File

@ -10167,6 +10167,26 @@ return {
short_desc = N_('Controls transparency level for floating windows'), short_desc = N_('Controls transparency level for floating windows'),
type = 'number', type = 'number',
}, },
{
defaults = { if_true = '' },
cb = 'did_set_winborder',
values = { 'double', 'single', 'shadow', 'rounded', 'solid', 'none' },
desc = [=[
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
]=],
full_name = 'winborder',
scope = { 'global' },
short_desc = N_('border of floating window'),
type = 'string',
varname = 'p_winbd',
},
{ {
abbreviation = 'wi', abbreviation = 'wi',
cb = 'did_set_window', cb = 'did_set_window',

View File

@ -2518,6 +2518,15 @@ const char *did_set_winhighlight(optset_T *args)
return NULL; return NULL;
} }
/// The 'winborder' option is changed.
const char *did_set_winborder(optset_T *args)
{
if (check_opt_strings(p_winbd, opt_winborder_values, true) != OK) {
return e_invarg;
}
return NULL;
}
int expand_set_winhighlight(optexpand_T *args, int *numMatches, char ***matches) int expand_set_winhighlight(optexpand_T *args, int *numMatches, char ***matches)
{ {
return expand_set_opt_generic(args, get_highlight_name, numMatches, matches); return expand_set_opt_generic(args, get_highlight_name, numMatches, matches);

View File

@ -9514,6 +9514,116 @@ describe('float window', function()
}) })
end end
end) end)
it('#winborder option', function()
local buf = api.nvim_create_buf(false,false)
local config = {relative='editor', width=4, height=4, row=2, col=2}
command('set winborder=single')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 4
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[4] = {1001, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[4] = {win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[4] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1001
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose')
command('set winborder=double')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 5
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[5] = {1002, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[5] = {win = 1002, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[5] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1002
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose!')
end)
end end
describe('with ext_multigrid', function() describe('with ext_multigrid', function()

View File

@ -75,6 +75,7 @@ let test_values = {
\ 'shada': [['', '''50', '"30'], ['xxx']], \ 'shada': [['', '''50', '"30'], ['xxx']],
\ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'], \ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'],
\ ['xxx', 'C0,C1,xxx']], \ ['xxx', 'C0,C1,xxx']],
\ 'winborder': [['rounded', 'none', 'single', 'solid'], ['xxx']],
\ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'], \ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'],
\ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']], \ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']],
\ \