vim-patch:9.0.0245: mechanism to prevent recursive screen updating is incomplete (#27448)

Problem:    Mechanism to prevent recursive screen updating is incomplete.
Solution:   Add "redraw_not_allowed" and set it in build_stl_str_hl().
            (issue vim/vim#10952)

471c0fa3ee

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2024-02-13 06:30:35 +08:00 committed by GitHub
parent 84b6ade415
commit 984f7a9fd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 33 additions and 31 deletions

View File

@ -322,7 +322,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
// Mark this window to be redrawn later.
if (wp->w_redr_type < UPD_VALID) {
if (!redraw_not_allowed && wp->w_redr_type < UPD_VALID) {
wp->w_redr_type = UPD_VALID;
}
@ -390,9 +390,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
// Call update_screen() later, which checks out what needs to be redrawn,
// since it notices b_mod_set and then uses b_mod_*.
if (must_redraw < UPD_VALID) {
must_redraw = UPD_VALID;
}
set_must_redraw(UPD_VALID);
// when the cursor line is changed always trigger CursorMoved
if (last_cursormoved_win == curwin && curwin->w_buffer == buf

View File

@ -2647,7 +2647,7 @@ void redraw_later(win_T *wp, int type)
{
// curwin may have been set to NULL when exiting
assert(wp != NULL || exiting);
if (!exiting && wp->w_redr_type < type) {
if (!exiting && !redraw_not_allowed && wp->w_redr_type < type) {
wp->w_redr_type = type;
if (type >= UPD_NOT_VALID) {
wp->w_lines_valid = 0;
@ -2665,7 +2665,14 @@ void redraw_all_later(int type)
redraw_later(wp, type);
}
// This may be needed when switching tabs.
if (must_redraw < type) {
set_must_redraw(type);
}
/// Set "must_redraw" to "type" unless it already has a higher value
/// or it is currently not allowed.
void set_must_redraw(int type)
{
if (!redraw_not_allowed && must_redraw < type) {
must_redraw = type;
}
}
@ -2730,9 +2737,7 @@ void redraw_buf_status_later(buf_T *buf)
|| (wp == curwin && global_stl_height())
|| wp->w_winbar_height)) {
wp->w_redr_status = true;
if (must_redraw < UPD_VALID) {
must_redraw = UPD_VALID;
}
set_must_redraw(UPD_VALID);
}
}
}

View File

@ -21,6 +21,10 @@ enum {
/// ('lines' and 'rows') must not be changed.
EXTERN bool updating_screen INIT( = false);
/// While computing a statusline and the like we do not want any w_redr_type or
/// must_redraw to be set.
EXTERN bool redraw_not_allowed INIT( = false);
EXTERN match_T screen_search_hl INIT( = { 0 }); ///< used for 'hlsearch' highlight matching
#define W_ENDCOL(wp) ((wp)->w_wincol + (wp)->w_width)

View File

@ -902,9 +902,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
// not get printed in the middle of it.
msg_check();
if (p_ch == 0 && !ui_has(kUIMessages)) {
if (must_redraw < UPD_VALID) {
must_redraw = UPD_VALID;
}
set_must_redraw(UPD_VALID);
}
msg_scroll = s->save_msg_scroll;
redir_off = false;

View File

@ -2419,9 +2419,7 @@ static void inc_msg_scrolled(void)
xfree(tofree);
}
msg_scrolled++;
if (must_redraw < UPD_VALID) {
must_redraw = UPD_VALID;
}
set_must_redraw(UPD_VALID);
}
static msgchunk_T *last_msgchunk = NULL; // last displayed text
@ -3067,9 +3065,7 @@ void msg_ext_clear_later(void)
{
if (msg_ext_is_visible()) {
msg_ext_need_clear = true;
if (must_redraw < UPD_VALID) {
must_redraw = UPD_VALID;
}
set_must_redraw(UPD_VALID);
}
}

View File

@ -935,14 +935,20 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op
char buf_tmp[TMPLEN];
char win_tmp[TMPLEN];
char *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
const bool save_redraw_not_allowed = redraw_not_allowed;
const bool save_KeyTyped = KeyTyped;
// 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;
// When inside update_screen() we do not want redrawing a statusline,
// ruler, title, etc. to trigger another redraw, it may cause an endless
// loop.
if (updating_screen) {
redraw_not_allowed = true;
}
if (stl_items == NULL) {
stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len);
stl_groupitems = xmalloc(sizeof(int) * stl_items_len);
@ -1938,16 +1944,16 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op
stl_items[curitem].type = Empty;
}
if (num >= 0 || (!itemisflag && str && *str)) {
prevchar_isflag = false; // Item not NULL, but not a flag
}
// Only free the string buffer if we allocated it.
// Note: This is not needed if `str` is pointing at `tmp`
if (opt == STL_VIM_EXPR) {
XFREE_CLEAR(str);
}
if (num >= 0 || (!itemisflag && str && *str)) {
prevchar_isflag = false; // Item not NULL, but not a flag
}
// Item processed, move to the next
curitem++;
}
@ -2172,12 +2178,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op
cur_tab_rec->def.func = NULL;
}
// When inside update_screen we do not want redrawing a statusline, ruler,
// title, etc. to trigger another redraw, it may cause an endless loop.
if (updating_screen) {
must_redraw = save_must_redraw;
curwin->w_redr_type = save_redr_type;
}
redraw_not_allowed = save_redraw_not_allowed;
// 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

View File

@ -184,7 +184,7 @@ void win_config_float(win_T *wp, WinConfig fconfig)
}
win_set_inner_size(wp, true);
must_redraw = MAX(must_redraw, UPD_VALID);
set_must_redraw(UPD_VALID);
wp->w_pos_changed = true;
if (change_external || change_border) {