vim-patch:9.0.0844: handling 'statusline' errors is spread out (#20992)

Problem:    Handling 'statusline' errors is spread out.
Solution:   Pass the option name to the lower levels so the option can be
            reset there when an error is encountered. (Luuk van Baal,
            closes vim/vim#11467)

7b224fdf4a
This commit is contained in:
luukvbaal
2022-11-08 00:21:22 +01:00
committed by GitHub
parent 050b0e30b9
commit 8147d3df28
7 changed files with 51 additions and 72 deletions

View File

@@ -2223,7 +2223,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
buf,
sizeof(buf),
str.data,
false,
NULL,
0,
fillchar,
maxwidth,
hltab_ptr,

View File

@@ -3203,17 +3203,9 @@ void maketitle(void)
if (*p_titlestring != NUL) {
if (stl_syntax & STL_IN_TITLE) {
int use_sandbox = false;
const int called_emsg_before = called_emsg;
use_sandbox = was_set_insecurely(curwin, "titlestring", 0);
build_stl_str_hl(curwin, buf, sizeof(buf),
p_titlestring, use_sandbox,
0, maxlen, NULL, NULL);
build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring,
"titlestring", 0, 0, maxlen, NULL, NULL);
title_str = buf;
if (called_emsg > called_emsg_before) {
set_string_option_direct("titlestring", -1, "", OPT_FREE, SID_ERROR);
}
} else {
title_str = p_titlestring;
}
@@ -3317,16 +3309,8 @@ void maketitle(void)
icon_str = buf;
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
int use_sandbox = false;
const int called_emsg_before = called_emsg;
use_sandbox = was_set_insecurely(curwin, "iconstring", 0);
build_stl_str_hl(curwin, icon_str, sizeof(buf),
p_iconstring, use_sandbox,
0, 0, NULL, NULL);
if (called_emsg > called_emsg_before) {
set_string_option_direct("iconstring", -1, "", OPT_FREE, SID_ERROR);
}
build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring,
"iconstring", 0, 0, 0, NULL, NULL);
} else {
icon_str = p_iconstring;
}

View File

@@ -522,7 +522,6 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const
if (*p_header != NUL) {
linenr_T tmp_lnum, tmp_topline, tmp_botline;
int use_sandbox = false;
// Need to (temporarily) set current line number and first/last line
// number on the 'window'. Since we don't know how long the page is,
@@ -536,9 +535,8 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const
curwin->w_botline = lnum + 63;
printer_page_num = pagenum;
use_sandbox = was_set_insecurely(curwin, "printheader", 0);
build_stl_str_hl(curwin, (char *)tbuf, (size_t)width + IOSIZE,
(char *)p_header, use_sandbox,
(char *)p_header, "printheader", 0,
' ', width, NULL, NULL);
// Reset line numbers

View File

@@ -999,16 +999,7 @@ void draw_tabline(void)
// Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
int saved_did_emsg = did_emsg;
// Check for an error. If there is one we would loop in redrawing the
// screen. Avoid that by making 'tabline' empty.
did_emsg = false;
win_redr_custom(NULL, false, false);
if (did_emsg) {
set_string_option_direct("tabline", -1, "", OPT_FREE, SID_ERROR);
}
did_emsg |= saved_did_emsg;
} else {
FOR_ALL_TABS(tp) {
tabcount++;

View File

@@ -214,11 +214,7 @@ void win_redr_ruler(win_T *wp, bool always)
}
if (*p_ruf && p_ch > 0 && !ui_has(kUIMessages)) {
const int called_emsg_before = called_emsg;
win_redr_custom(wp, false, true);
if (called_emsg > called_emsg_before) {
set_string_option_direct("rulerformat", -1, "", OPT_FREE, SID_ERROR);
}
return;
}
@@ -389,7 +385,6 @@ int fillchar_status(int *attr, win_T *wp)
void redraw_custom_statusline(win_T *wp)
{
static bool entered = false;
int saved_did_emsg = did_emsg;
// When called recursively return. This can happen when the statusline
// contains an expression that triggers a redraw.
@@ -398,17 +393,7 @@ void redraw_custom_statusline(win_T *wp)
}
entered = true;
did_emsg = false;
win_redr_custom(wp, false, false);
if (did_emsg) {
// When there is an error disable the statusline, otherwise the
// display is messed up with errors and a redraw triggers the problem
// again and again.
set_string_option_direct("statusline", -1, "",
OPT_FREE | (*wp->w_p_stl != NUL
? OPT_LOCAL : OPT_GLOBAL), SID_ERROR);
}
did_emsg |= saved_did_emsg;
entered = false;
}
@@ -429,9 +414,10 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
char buf[MAXPATHL];
char *stl;
char *p;
char *opt_name;
int opt_scope = 0;
stl_hlrec_t *hltab;
StlClickRecord *tabtab;
int use_sandbox = false;
win_T *ewp;
int p_crb_save;
bool is_stl_global = global_stl_height() > 0;
@@ -454,9 +440,11 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
fillchar = ' ';
attr = HL_ATTR(HLF_TPF);
maxwidth = Columns;
use_sandbox = was_set_insecurely(wp, "tabline", 0);
opt_name = "tabline";
} else if (draw_winbar) {
opt_name = "winbar";
stl = ((*wp->w_p_wbr != NUL) ? wp->w_p_wbr : p_wbr);
opt_scope = ((*wp->w_p_wbr != NUL) ? OPT_LOCAL : 0);
row = -1; // row zero is first row of text
col = 0;
grid = &wp->w_grid;
@@ -469,7 +457,6 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
fillchar = wp->w_p_fcs_chars.wbr;
attr = (wp == curwin) ? win_hl_attr(wp, HLF_WBR) : win_hl_attr(wp, HLF_WBRNC);
maxwidth = wp->w_width_inner;
use_sandbox = was_set_insecurely(wp, "winbar", 0);
stl_clear_click_defs(wp->w_winbar_click_defs, (long)wp->w_winbar_click_defs_size);
wp->w_winbar_click_defs = stl_alloc_click_defs(wp->w_winbar_click_defs, maxwidth,
&wp->w_winbar_click_defs_size);
@@ -483,6 +470,7 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
if (draw_ruler) {
stl = p_ruf;
opt_name = "rulerformat";
// advance past any leading group spec - implicit in ru_col
if (*stl == '%') {
if (*++stl == '-') {
@@ -509,15 +497,10 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
fillchar = ' ';
attr = HL_ATTR(HLF_MSG);
}
use_sandbox = was_set_insecurely(wp, "rulerformat", 0);
} else {
if (*wp->w_p_stl != NUL) {
stl = wp->w_p_stl;
} else {
stl = p_stl;
}
use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
opt_name = "statusline";
stl = ((*wp->w_p_stl != NUL) ? wp->w_p_stl : p_stl);
opt_scope = ((*wp->w_p_stl != NUL) ? OPT_LOCAL : 0);
}
col += is_stl_global ? 0 : wp->w_wincol;
@@ -536,9 +519,8 @@ void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
// Make a copy, because the statusline may include a function call that
// might change the option value and free the memory.
stl = xstrdup(stl);
width =
build_stl_str_hl(ewp, buf, sizeof(buf), stl, use_sandbox,
fillchar, maxwidth, &hltab, &tabtab);
width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name,
opt_scope, fillchar, maxwidth, &hltab, &tabtab);
xfree(stl);
ewp->w_p_crb = p_crb_save;
@@ -611,15 +593,16 @@ theend:
/// Note: This should not be NameBuff
/// @param outlen The length of the output buffer
/// @param fmt The statusline format string
/// @param use_sandbox Use a sandboxed environment when evaluating fmt
/// @param opt_name The option name corresponding to "fmt"
/// @param opt_scope The scope corresponding to "opt_name"
/// @param fillchar Character to use when filling empty space in the statusline
/// @param maxwidth The maximum width to make the statusline
/// @param hltab HL attributes (can be NULL)
/// @param tabtab Tab clicks definition (can be NULL).
///
/// @return The final width of the statusline
int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_sandbox, int fillchar,
int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_name, int opt_scope,
int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@@ -634,6 +617,10 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
char *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
// TODO(Bram): find out why using called_emsg_before makes tests fail, does it
// matter?
// const int called_emsg_before = called_emsg;
const int did_emsg_before = did_emsg;
if (stl_items == NULL) {
stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len);
@@ -647,6 +634,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
stl_separator_locations = xmalloc(sizeof(int) * stl_items_len);
}
// if "fmt" was set insecurely it needs to be evaluated in the sandbox
// "opt_name" will be NULL when caller is nvim_eval_statusline()
const int use_sandbox = opt_name ? was_set_insecurely(wp, opt_name, opt_scope)
: false;
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
if (fmt[0] == '%' && fmt[1] == '!') {
@@ -1769,5 +1761,15 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_san
curwin->w_redr_type = save_redr_type;
}
// Check for an error. If there is one the display will be messed up and
// might loop redrawing. Avoid that by making the corresponding option
// empty.
// TODO(Bram): find out why using called_emsg_before makes tests fail, does it
// matter?
// if (called_emsg > called_emsg_before)
if (opt_name && did_emsg > did_emsg_before) {
set_string_option_direct(opt_name, -1, "", OPT_FREE | opt_scope, SID_ERROR);
}
return width;
}

View File

@@ -35,11 +35,12 @@ describe('ffi.cdef', function()
int build_stl_str_hl(
win_T *wp,
char_u *out,
char *out,
size_t outlen,
char_u *fmt,
int use_sandbox,
char_u fillchar,
char *fmt,
char *opt_name,
int opt_scope,
int fillchar,
int maxwidth,
stl_hlrec_t **hltab,
StlClickRecord **tabtab
@@ -48,9 +49,10 @@ describe('ffi.cdef', function()
return ffi.C.build_stl_str_hl(
ffi.C.find_window_by_handle(0, ffi.new('Error')),
ffi.new('char_u[1024]'),
ffi.new('char[1024]'),
1024,
ffi.cast('char_u*', 'StatusLineOfLength20'),
ffi.cast('char*', 'StatusLineOfLength20'),
nil,
0,
0,
0,

View File

@@ -233,7 +233,8 @@ describe('buffer functions', function()
output_buffer,
buffer_byte_size,
to_cstr(pat),
false,
NULL,
0,
fillchar,
maximum_cell_count,
NULL,