refactor(redraw): various simplifications

This commit is contained in:
bfredl
2022-09-27 15:24:09 +02:00
parent 6679687bb3
commit cce0840cbf
5 changed files with 79 additions and 106 deletions

View File

@@ -97,7 +97,7 @@ typedef enum {
static bool redraw_popupmenu = false; static bool redraw_popupmenu = false;
static bool msg_grid_invalid = false; static bool msg_grid_invalid = false;
static bool resizing = false; static bool resizing_autocmd = false;
static char *provider_err = NULL; static char *provider_err = NULL;
@@ -115,7 +115,7 @@ void conceal_check_cursor_line(void)
} }
} }
/// Resize the screen to Rows and Columns. /// Resize default_grid to Rows and Columns.
/// ///
/// Allocate default_grid.chars[] and other grid arrays. /// Allocate default_grid.chars[] and other grid arrays.
/// ///
@@ -125,19 +125,18 @@ void conceal_check_cursor_line(void)
/// default_grid.Columns to access items in default_grid.chars[]. Use Rows /// default_grid.Columns to access items in default_grid.chars[]. Use Rows
/// and Columns for positioning text etc. where the final size of the screen is /// and Columns for positioning text etc. where the final size of the screen is
/// needed. /// needed.
void screenalloc(void) bool default_grid_alloc(void)
{ {
static bool resizing = false;
// It's possible that we produce an out-of-memory message below, which // It's possible that we produce an out-of-memory message below, which
// will cause this function to be called again. To break the loop, just // will cause this function to be called again. To break the loop, just
// return here. // return here.
if (resizing) { if (resizing) {
return; return false;
} }
resizing = true; resizing = true;
int retry_count = 0;
retry:
// Allocation of the screen buffers is done only when the size changes and // Allocation of the screen buffers is done only when the size changes and
// when Rows and Columns have been set and we have started doing full // when Rows and Columns have been set and we have started doing full
// screen stuff. // screen stuff.
@@ -148,24 +147,9 @@ retry:
|| Columns == 0 || Columns == 0
|| (!full_screen && default_grid.chars == NULL)) { || (!full_screen && default_grid.chars == NULL)) {
resizing = false; resizing = false;
return; return false;
} }
// Note that the window sizes are updated before reallocating the arrays,
// thus we must not redraw here!
RedrawingDisabled++;
// win_new_screensize will recompute floats position, but tell the
// compositor to not redraw them yet
ui_comp_set_screen_valid(false);
if (msg_grid.chars) {
msg_grid_invalid = true;
}
win_new_screensize(); // fit the windows in the new sized screen
comp_col(); // recompute columns for shown command and ruler
// We're changing the size of the screen. // We're changing the size of the screen.
// - Allocate new arrays for default_grid // - Allocate new arrays for default_grid
// - Move lines from the old arrays into the new arrays, clear extra // - Move lines from the old arrays into the new arrays, clear extra
@@ -193,26 +177,13 @@ retry:
default_grid.col_offset = 0; default_grid.col_offset = 0;
default_grid.handle = DEFAULT_GRID_HANDLE; default_grid.handle = DEFAULT_GRID_HANDLE;
must_redraw = UPD_CLEAR; // need to clear the screen later
RedrawingDisabled--;
// Do not apply autocommands more than 3 times to avoid an endless loop
// in case applying autocommands always changes Rows or Columns.
if (starting == 0 && ++retry_count <= 3) {
apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf);
// In rare cases, autocommands may have altered Rows or Columns,
// jump back to check if we need to allocate the screen again.
goto retry;
}
resizing = false; resizing = false;
return true;
} }
void screenclear(void) void screenclear(void)
{ {
check_for_delay(false); check_for_delay(false);
screenalloc(); // allocate screen buffers if size changed
int i; int i;
@@ -281,13 +252,6 @@ void screen_resize(int width, int height)
return; return;
} }
// curwin->w_buffer can be NULL when we are closing a window and the
// buffer has already been closed and removing a scrollbar causes a resize
// event. Don't resize then, it will happen after entering another buffer.
if (curwin->w_buffer == NULL) {
return;
}
resizing_screen = true; resizing_screen = true;
Rows = height; Rows = height;
@@ -301,16 +265,54 @@ void screen_resize(int width, int height)
width = Columns; width = Columns;
p_lines = Rows; p_lines = Rows;
p_columns = Columns; p_columns = Columns;
// was invoked recursively from a VimResized autocmd, handled as a loop below
if (resizing_autocmd) {
return;
}
int retry_count = 0;
resizing_autocmd = true;
bool retry_resize = true;
while (retry_resize) {
retry_resize = default_grid_alloc();
// Do not apply autocommands more than 3 times to avoid an endless loop
// in case applying autocommands always changes Rows or Columns.
if (++retry_count > 3) {
break;
}
if (retry_resize) {
// In rare cases, autocommands may have altered Rows or Columns,
// retry to check if we need to allocate the screen again.
apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf);
}
}
resizing_autocmd = false;
ui_call_grid_resize(1, width, height); ui_call_grid_resize(1, width, height);
/// The window layout used to be adjusted here, but it now happens in // win_new_screensize will recompute floats position, but tell the
/// screenalloc() (also invoked from screenclear()). That is because the // compositor to not redraw them yet
/// recursize "resizing_screen" check above may skip this, but not screenalloc(). ui_comp_set_screen_valid(false);
if (msg_grid.chars) {
if (State != MODE_ASKMORE && State != MODE_EXTERNCMD && State != MODE_CONFIRM) { msg_grid_invalid = true;
screenclear();
} }
// Note that the window sizes are updated before reallocating the arrays,
// thus we must not redraw here!
RedrawingDisabled++;
win_new_screensize(); // fit the windows in the new sized screen
comp_col(); // recompute columns for shown command and ruler
RedrawingDisabled--;
redraw_all_later(UPD_CLEAR);
if (starting != NO_SCREEN) { if (starting != NO_SCREEN) {
maketitle(); maketitle();
@@ -320,14 +322,11 @@ void screen_resize(int width, int height)
// We only redraw when it's needed: // We only redraw when it's needed:
// - While at the more prompt or executing an external command, don't // - While at the more prompt or executing an external command, don't
// redraw, but position the cursor. // redraw, but position the cursor.
// - While editing the command line, only redraw that. // - While editing the command line, only redraw that. TODO: lies
// - in Ex mode, don't redraw anything. // - in Ex mode, don't redraw anything.
// - Otherwise, redraw right now, and position the cursor. // - Otherwise, redraw right now, and position the cursor.
// Always need to call update_screen() or screenalloc(), to make
// sure Rows/Columns and the size of the screen is correct!
if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM if (State == MODE_ASKMORE || State == MODE_EXTERNCMD || State == MODE_CONFIRM
|| exmode_active) { || exmode_active) {
screenalloc();
if (msg_grid.chars) { if (msg_grid.chars) {
msg_grid_validate(); msg_grid_validate();
} }
@@ -378,7 +377,7 @@ int update_screen(void)
// Don't do anything if the screen structures are (not yet) valid. // Don't do anything if the screen structures are (not yet) valid.
// A VimResized autocmd can invoke redrawing in the middle of a resize, // A VimResized autocmd can invoke redrawing in the middle of a resize,
// which would bypass the checks in screen_resize for popupmenu etc. // which would bypass the checks in screen_resize for popupmenu etc.
if (!default_grid.chars || resizing) { if (resizing_autocmd || !default_grid.chars) {
return FAIL; return FAIL;
} }
@@ -387,30 +386,21 @@ int update_screen(void)
diff_redraw(true); diff_redraw(true);
} }
int type = 0; // Postpone the redrawing when it's not needed and when being called
// recursively.
if (must_redraw) { if (!redrawing() || updating_screen) {
if (type < must_redraw) { // use maximal type return FAIL;
type = must_redraw;
} }
int type = must_redraw;
// must_redraw is reset here, so that when we run into some weird // must_redraw is reset here, so that when we run into some weird
// reason to redraw while busy redrawing (e.g., asynchronous // reason to redraw while busy redrawing (e.g., asynchronous
// scrolling), or update_topline() in win_update() will cause a // scrolling), or update_topline() in win_update() will cause a
// scroll, or a decoration provider requires a redraw, the screen // scroll, or a decoration provider requires a redraw, the screen
// will be redrawn later or in win_update(). // will be redrawn later or in win_update().
must_redraw = 0; must_redraw = 0;
}
// Postpone the redrawing when it's not needed and when being called
// recursively.
if (!redrawing() || updating_screen) {
must_redraw = type;
if (type > UPD_INVERTED_ALL) {
curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now
}
return FAIL;
}
updating_screen = 1; updating_screen = 1;
display_tick++; // let syntax code know we're in a next round of display_tick++; // let syntax code know we're in a next round of
@@ -526,6 +516,7 @@ int update_screen(void)
if (type == UPD_CLEAR) { // first clear screen if (type == UPD_CLEAR) { // first clear screen
screenclear(); // will reset clear_cmdline screenclear(); // will reset clear_cmdline
// and set UPD_NOT_VALID for each window
cmdline_screen_cleared(); // clear external cmdline state cmdline_screen_cleared(); // clear external cmdline state
type = UPD_NOT_VALID; type = UPD_NOT_VALID;
// must_redraw may be set indirectly, avoid another redraw later // must_redraw may be set indirectly, avoid another redraw later

View File

@@ -1721,13 +1721,6 @@ failed:
appended_lines_mark(from, linecnt); appended_lines_mark(from, linecnt);
} }
// If we were reading from the same terminal as where messages go,
// the screen will have been messed up.
// Switch on raw mode now and clear the screen.
if (read_stdin) {
screenclear();
}
if (got_int) { if (got_int) {
if (!(flags & READ_DUMMY)) { if (!(flags & READ_DUMMY)) {
filemess(curbuf, sfname, _(e_interr), 0); filemess(curbuf, sfname, _(e_interr), 0);

View File

@@ -314,7 +314,7 @@ int main(int argc, char **argv)
assert(p_ch >= 0 && Rows >= p_ch && Rows - p_ch <= INT_MAX); assert(p_ch >= 0 && Rows >= p_ch && Rows - p_ch <= INT_MAX);
cmdline_row = (int)(Rows - p_ch); cmdline_row = (int)(Rows - p_ch);
msg_row = cmdline_row; msg_row = cmdline_row;
screenalloc(); // allocate screen buffers default_grid_alloc(); // allocate screen buffers
set_init_2(headless_mode); set_init_2(headless_mode);
TIME_MSG("inits 2"); TIME_MSG("inits 2");
@@ -346,12 +346,13 @@ int main(int argc, char **argv)
ui_builtin_start(); ui_builtin_start();
} }
TIME_MSG("done waiting for UI"); TIME_MSG("done waiting for UI");
}
// prepare screen now, so external UIs can display messages // prepare screen now
starting = NO_BUFFERS; starting = NO_BUFFERS;
screenclear(); screenclear();
TIME_MSG("init screen for UI"); win_new_screensize();
} TIME_MSG("clear screen");
if (ui_client_channel_id) { if (ui_client_channel_id) {
ui_client_init(ui_client_channel_id); ui_client_init(ui_client_channel_id);
@@ -361,7 +362,7 @@ int main(int argc, char **argv)
// Default mappings (incl. menus) // Default mappings (incl. menus)
Error err = ERROR_INIT; Error err = ERROR_INIT;
Object o = nlua_exec(STATIC_CSTR_AS_STRING("return vim._init_default_mappings()"), Object o = NLUA_EXEC_STATIC("return vim._init_default_mappings()",
(Array)ARRAY_DICT_INIT, &err); (Array)ARRAY_DICT_INIT, &err);
assert(!ERROR_SET(&err)); assert(!ERROR_SET(&err));
api_clear_error(&err); api_clear_error(&err);
@@ -432,10 +433,8 @@ int main(int argc, char **argv)
p_ut = 1; p_ut = 1;
} }
//
// Read in registers, history etc, from the ShaDa file. // Read in registers, history etc, from the ShaDa file.
// This is where v:oldfiles gets filled. // This is where v:oldfiles gets filled.
//
if (*p_shada != NUL) { if (*p_shada != NUL) {
shada_read_everything(NULL, false, true); shada_read_everything(NULL, false, true);
TIME_MSG("reading ShaDa"); TIME_MSG("reading ShaDa");
@@ -474,14 +473,7 @@ int main(int argc, char **argv)
setmouse(); // may start using the mouse setmouse(); // may start using the mouse
if (exmode_active || use_remote_ui || use_builtin_ui) {
// Don't clear the screen when starting in Ex mode, or when a UI might have
// displayed messages.
redraw_later(curwin, UPD_VALID); redraw_later(curwin, UPD_VALID);
} else {
screenclear(); // clear screen
TIME_MSG("clearing screen");
}
no_wait_return = true; no_wait_return = true;

View File

@@ -1159,10 +1159,6 @@ void wait_return(int redraw)
c = CAR; // no need for a return in ex mode c = CAR; // no need for a return in ex mode
got_int = false; got_int = false;
} else { } else {
// Make sure the hit-return prompt is on screen when 'guioptions' was
// just changed.
screenalloc();
State = MODE_HITRETURN; State = MODE_HITRETURN;
setmouse(); setmouse();
cmdline_row = msg_row; cmdline_row = msg_row;

View File

@@ -2324,6 +2324,7 @@ static void do_intro_line(long row, char *mesg, int attr)
/// @param eap /// @param eap
void ex_intro(exarg_T *eap) void ex_intro(exarg_T *eap)
{ {
// TODO(bfredl): use msg_grid instead!
screenclear(); screenclear();
intro_message(true); intro_message(true);
wait_return(true); wait_return(true);