mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
fix(api): fix crash/leak with float title/footer on error (#30543)
This commit is contained in:
@@ -854,19 +854,11 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type,
|
|||||||
int *width;
|
int *width;
|
||||||
switch (bordertext_type) {
|
switch (bordertext_type) {
|
||||||
case kBorderTextTitle:
|
case kBorderTextTitle:
|
||||||
if (fconfig->title) {
|
|
||||||
clear_virttext(&fconfig->title_chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_present = &fconfig->title;
|
is_present = &fconfig->title;
|
||||||
chunks = &fconfig->title_chunks;
|
chunks = &fconfig->title_chunks;
|
||||||
width = &fconfig->title_width;
|
width = &fconfig->title_width;
|
||||||
break;
|
break;
|
||||||
case kBorderTextFooter:
|
case kBorderTextFooter:
|
||||||
if (fconfig->footer) {
|
|
||||||
clear_virttext(&fconfig->footer_chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_present = &fconfig->footer;
|
is_present = &fconfig->footer;
|
||||||
chunks = &fconfig->footer_chunks;
|
chunks = &fconfig->footer_chunks;
|
||||||
width = &fconfig->footer_width;
|
width = &fconfig->footer_width;
|
||||||
@@ -878,6 +870,7 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type,
|
|||||||
*is_present = false;
|
*is_present = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
kv_init(*chunks);
|
||||||
kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data),
|
kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data),
|
||||||
.hl_id = -1 }));
|
.hl_id = -1 }));
|
||||||
*width = (int)mb_string2cells(bordertext.data.string.data);
|
*width = (int)mb_string2cells(bordertext.data.string.data);
|
||||||
@@ -1055,13 +1048,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (config->relative.size > 0) {
|
if (config->relative.size > 0) {
|
||||||
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col))
|
if (config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col))
|
||||||
&& !HAS_KEY_X(config, bufpos)) {
|
&& !HAS_KEY_X(config, bufpos)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "'relative' requires 'row'/'col' or 'bufpos'");
|
api_set_error(err, kErrorTypeValidation, "'relative' requires 'row'/'col' or 'bufpos'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
has_relative = true;
|
has_relative = true;
|
||||||
@@ -1076,39 +1069,39 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
} else if (wp == NULL) { // new win
|
} else if (wp == NULL) { // new win
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation,
|
||||||
"Must specify 'relative' or 'external' when creating a float");
|
"Must specify 'relative' or 'external' when creating a float");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, vertical)) {
|
if (HAS_KEY_X(config, vertical)) {
|
||||||
if (!is_split) {
|
if (!is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'");
|
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, split)) {
|
if (HAS_KEY_X(config, split)) {
|
||||||
if (!is_split) {
|
if (!is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'");
|
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (!parse_config_split(config->split, &fconfig->split)) {
|
if (!parse_config_split(config->split, &fconfig->split)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, anchor)) {
|
if (HAS_KEY_X(config, anchor)) {
|
||||||
if (!parse_float_anchor(config->anchor, &fconfig->anchor)) {
|
if (!parse_float_anchor(config->anchor, &fconfig->anchor)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, row)) {
|
if (HAS_KEY_X(config, row)) {
|
||||||
if (!has_relative || is_split) {
|
if (!has_relative || is_split) {
|
||||||
generate_api_error(wp, "row", err);
|
generate_api_error(wp, "row", err);
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
fconfig->row = config->row;
|
fconfig->row = config->row;
|
||||||
}
|
}
|
||||||
@@ -1116,7 +1109,7 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (HAS_KEY_X(config, col)) {
|
if (HAS_KEY_X(config, col)) {
|
||||||
if (!has_relative || is_split) {
|
if (!has_relative || is_split) {
|
||||||
generate_api_error(wp, "col", err);
|
generate_api_error(wp, "col", err);
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
fconfig->col = config->col;
|
fconfig->col = config->col;
|
||||||
}
|
}
|
||||||
@@ -1124,11 +1117,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (HAS_KEY_X(config, bufpos)) {
|
if (HAS_KEY_X(config, bufpos)) {
|
||||||
if (!has_relative || is_split) {
|
if (!has_relative || is_split) {
|
||||||
generate_api_error(wp, "bufpos", err);
|
generate_api_error(wp, "bufpos", err);
|
||||||
return false;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) {
|
if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HAS_KEY_X(config, row)) {
|
if (!HAS_KEY_X(config, row)) {
|
||||||
@@ -1145,11 +1138,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
fconfig->width = (int)config->width;
|
fconfig->width = (int)config->width;
|
||||||
} else {
|
} else {
|
||||||
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
|
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else if (!reconf && !is_split) {
|
} else if (!reconf && !is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
|
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, height)) {
|
if (HAS_KEY_X(config, height)) {
|
||||||
@@ -1157,23 +1150,23 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
fconfig->height = (int)config->height;
|
fconfig->height = (int)config->height;
|
||||||
} else {
|
} else {
|
||||||
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
|
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else if (!reconf && !is_split) {
|
} else if (!reconf && !is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
|
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relative_is_win || is_split) {
|
if (relative_is_win || is_split) {
|
||||||
if (reconf && relative_is_win) {
|
if (reconf && relative_is_win) {
|
||||||
win_T *target_win = find_window_by_handle(config->win, err);
|
win_T *target_win = find_window_by_handle(config->win, err);
|
||||||
if (!target_win) {
|
if (!target_win) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_win == wp) {
|
if (target_win == wp) {
|
||||||
api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself");
|
api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fconfig->window = curwin->handle;
|
fconfig->window = curwin->handle;
|
||||||
@@ -1186,11 +1179,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (has_relative) {
|
if (has_relative) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation,
|
||||||
"'win' key is only valid with relative='win' and relative=''");
|
"'win' key is only valid with relative='win' and relative=''");
|
||||||
return false;
|
goto fail;
|
||||||
} else if (!is_split) {
|
} else if (!is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation,
|
||||||
"non-float with 'win' requires at least 'split' or 'vertical'");
|
"non-float with 'win' requires at least 'split' or 'vertical'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1199,11 +1192,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (has_relative && fconfig->external) {
|
if (has_relative && fconfig->external) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation,
|
||||||
"Only one of 'relative' and 'external' must be used");
|
"Only one of 'relative' and 'external' must be used");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (fconfig->external && !ui_has(kUIMultigrid)) {
|
if (fconfig->external && !ui_has(kUIMultigrid)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows");
|
api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,78 +1207,78 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
if (HAS_KEY_X(config, zindex)) {
|
if (HAS_KEY_X(config, zindex)) {
|
||||||
if (is_split) {
|
if (is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'zindex'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'zindex'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (config->zindex > 0) {
|
if (config->zindex > 0) {
|
||||||
fconfig->zindex = (int)config->zindex;
|
fconfig->zindex = (int)config->zindex;
|
||||||
} else {
|
} else {
|
||||||
api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
|
api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, title)) {
|
if (HAS_KEY_X(config, title)) {
|
||||||
if (is_split) {
|
if (is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
// title only work with border
|
// title only work with border
|
||||||
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
||||||
api_set_error(err, kErrorTypeException, "title requires border to be set");
|
api_set_error(err, kErrorTypeException, "title requires border to be set");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_bordertext(config->title, kBorderTextTitle, fconfig, err);
|
parse_bordertext(config->title, kBorderTextTitle, fconfig, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles unset 'title_pos' same as empty string
|
// handles unset 'title_pos' same as empty string
|
||||||
if (!parse_bordertext_pos(config->title_pos, kBorderTextTitle, fconfig, err)) {
|
if (!parse_bordertext_pos(config->title_pos, kBorderTextTitle, fconfig, err)) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (HAS_KEY_X(config, title_pos)) {
|
if (HAS_KEY_X(config, title_pos)) {
|
||||||
api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
|
api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, footer)) {
|
if (HAS_KEY_X(config, footer)) {
|
||||||
if (is_split) {
|
if (is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
// footer only work with border
|
// footer only work with border
|
||||||
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
||||||
api_set_error(err, kErrorTypeException, "footer requires border to be set");
|
api_set_error(err, kErrorTypeException, "footer requires border to be set");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_bordertext(config->footer, kBorderTextFooter, fconfig, err);
|
parse_bordertext(config->footer, kBorderTextFooter, fconfig, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles unset 'footer_pos' same as empty string
|
// handles unset 'footer_pos' same as empty string
|
||||||
if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) {
|
if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (HAS_KEY_X(config, footer_pos)) {
|
if (HAS_KEY_X(config, footer_pos)) {
|
||||||
api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set");
|
api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, border)) {
|
if (HAS_KEY_X(config, border)) {
|
||||||
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'");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
parse_border_style(config->border, fconfig, err);
|
parse_border_style(config->border, fconfig, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1296,14 +1289,14 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
fconfig->style = kWinStyleMinimal;
|
fconfig->style = kWinStyleMinimal;
|
||||||
} else {
|
} else {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, noautocmd)) {
|
if (HAS_KEY_X(config, noautocmd)) {
|
||||||
if (wp) {
|
if (wp) {
|
||||||
api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be used with existing windows");
|
api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be used with existing windows");
|
||||||
return false;
|
goto fail;
|
||||||
}
|
}
|
||||||
fconfig->noautocmd = config->noautocmd;
|
fconfig->noautocmd = config->noautocmd;
|
||||||
}
|
}
|
||||||
@@ -1317,5 +1310,14 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (wp == NULL || fconfig->title_chunks.items != wp->w_config.title_chunks.items) {
|
||||||
|
clear_virttext(&fconfig->title_chunks);
|
||||||
|
}
|
||||||
|
if (wp == NULL || fconfig->footer_chunks.items != wp->w_config.footer_chunks.items) {
|
||||||
|
clear_virttext(&fconfig->footer_chunks);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
#undef HAS_KEY_X
|
#undef HAS_KEY_X
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/autocmd.h"
|
#include "nvim/autocmd.h"
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer_defs.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
#include "nvim/errors.h"
|
#include "nvim/errors.h"
|
||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
@@ -202,6 +203,12 @@ void win_config_float(win_T *wp, WinConfig fconfig)
|
|||||||
wp->w_config.border_hl_ids,
|
wp->w_config.border_hl_ids,
|
||||||
sizeof fconfig.border_hl_ids) != 0);
|
sizeof fconfig.border_hl_ids) != 0);
|
||||||
|
|
||||||
|
if (fconfig.title_chunks.items != wp->w_config.title_chunks.items) {
|
||||||
|
clear_virttext(&wp->w_config.title_chunks);
|
||||||
|
}
|
||||||
|
if (fconfig.footer_chunks.items != wp->w_config.footer_chunks.items) {
|
||||||
|
clear_virttext(&wp->w_config.footer_chunks);
|
||||||
|
}
|
||||||
wp->w_config = fconfig;
|
wp->w_config = fconfig;
|
||||||
|
|
||||||
bool has_border = wp->w_floating && wp->w_config.border;
|
bool has_border = wp->w_floating && wp->w_config.border;
|
||||||
|
@@ -164,7 +164,7 @@ describe('API/win', function()
|
|||||||
eq('typing\n some dumb text', curbuf_contents())
|
eq('typing\n some dumb text', curbuf_contents())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('does not leak memory when using invalid window ID with invalid pos', function()
|
it('no memory leak when using invalid window ID with invalid pos', function()
|
||||||
eq('Invalid window id: 1', pcall_err(api.nvim_win_set_cursor, 1, { 'b\na' }))
|
eq('Invalid window id: 1', pcall_err(api.nvim_win_set_cursor, 1, { 'b\na' }))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -1809,6 +1809,38 @@ describe('API/win', function()
|
|||||||
eq(topdir .. '/Xacd', fn.getcwd())
|
eq(topdir .. '/Xacd', fn.getcwd())
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('no memory leak with valid title and invalid footer', function()
|
||||||
|
eq(
|
||||||
|
'title/footer must be string or array',
|
||||||
|
pcall_err(api.nvim_open_win, 0, false, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
height = 5,
|
||||||
|
width = 5,
|
||||||
|
border = 'single',
|
||||||
|
title = { { 'TITLE' } },
|
||||||
|
footer = 0,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('no memory leak with invalid title and valid footer', function()
|
||||||
|
eq(
|
||||||
|
'title/footer must be string or array',
|
||||||
|
pcall_err(api.nvim_open_win, 0, false, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
height = 5,
|
||||||
|
width = 5,
|
||||||
|
border = 'single',
|
||||||
|
title = 0,
|
||||||
|
footer = { { 'FOOTER' } },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set_config', function()
|
describe('set_config', function()
|
||||||
@@ -2801,5 +2833,48 @@ describe('API/win', function()
|
|||||||
command('redraw!')
|
command('redraw!')
|
||||||
assert_alive()
|
assert_alive()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('no crash or memory leak', function()
|
||||||
|
local win
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
win = api.nvim_open_win(0, false, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
height = 5,
|
||||||
|
width = 5,
|
||||||
|
border = 'single',
|
||||||
|
title = { { 'OLD_TITLE' } },
|
||||||
|
footer = { { 'OLD_FOOTER' } },
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('with valid title and invalid footer', function()
|
||||||
|
eq(
|
||||||
|
'title/footer must be string or array',
|
||||||
|
pcall_err(api.nvim_win_set_config, win, {
|
||||||
|
title = { { 'NEW_TITLE' } },
|
||||||
|
footer = 0,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
command('redraw!')
|
||||||
|
assert_alive()
|
||||||
|
eq({ { 'OLD_TITLE' } }, api.nvim_win_get_config(win).title)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('with invalid title and valid footer', function()
|
||||||
|
eq(
|
||||||
|
'title/footer must be string or array',
|
||||||
|
pcall_err(api.nvim_win_set_config, win, {
|
||||||
|
title = 0,
|
||||||
|
footer = { { 'NEW_FOOTER' } },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
command('redraw!')
|
||||||
|
assert_alive()
|
||||||
|
eq({ { 'OLD_FOOTER' } }, api.nvim_win_get_config(win).footer)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user