mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #22547 from luukvbaal/statusline
perf(statusline): UI elements are always redrawn on K_EVENT
This commit is contained in:
commit
46d4d420e5
@ -1279,13 +1279,14 @@ struct window_S {
|
||||
bool w_redr_border; // if true border must be redrawn
|
||||
bool w_redr_statuscol; // if true 'statuscolumn' must be redrawn
|
||||
|
||||
// remember what is shown in the ruler for this window (if 'ruler' set)
|
||||
pos_T w_ru_cursor; // cursor position shown in ruler
|
||||
colnr_T w_ru_virtcol; // virtcol shown in ruler
|
||||
linenr_T w_ru_topline; // topline shown in ruler
|
||||
linenr_T w_ru_line_count; // line count used for ruler
|
||||
int w_ru_topfill; // topfill shown in ruler
|
||||
char w_ru_empty; // true if ruler shows 0-1 (empty line)
|
||||
// remember what is shown in the 'statusline'-format elements
|
||||
pos_T w_stl_cursor; // cursor position when last redrawn
|
||||
colnr_T w_stl_virtcol; // virtcol when last redrawn
|
||||
linenr_T w_stl_topline; // topline when last redrawn
|
||||
linenr_T w_stl_line_count; // line count when last redrawn
|
||||
int w_stl_topfill; // topfill when last redrawn
|
||||
char w_stl_empty; // true if elements show 0-1 (empty line)
|
||||
int w_stl_state; // State when last redrawn
|
||||
|
||||
int w_alt_fnum; // alternate file (for # and CTRL-^)
|
||||
|
||||
|
@ -92,6 +92,7 @@
|
||||
#include "nvim/profile.h"
|
||||
#include "nvim/regexp.h"
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/state.h"
|
||||
#include "nvim/statusline.h"
|
||||
#include "nvim/syntax.h"
|
||||
#include "nvim/terminal.h"
|
||||
@ -733,28 +734,53 @@ void show_cursor_info(bool always)
|
||||
return;
|
||||
}
|
||||
|
||||
win_check_ns_hl(curwin);
|
||||
if ((*p_stl != NUL || *curwin->w_p_stl != NUL)
|
||||
&& (curwin->w_status_height || global_stl_height())) {
|
||||
redraw_custom_statusline(curwin);
|
||||
} else {
|
||||
win_redr_ruler(curwin, always);
|
||||
}
|
||||
if (*p_wbr != NUL || *curwin->w_p_wbr != NUL) {
|
||||
win_redr_winbar(curwin);
|
||||
int state = get_real_state();
|
||||
int empty_line = (State & MODE_INSERT) == 0
|
||||
&& *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false) == NUL;
|
||||
|
||||
// Only draw when something changed.
|
||||
validate_virtcol_win(curwin);
|
||||
if (always
|
||||
|| curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum
|
||||
|| curwin->w_cursor.col != curwin->w_stl_cursor.col
|
||||
|| curwin->w_virtcol != curwin->w_stl_virtcol
|
||||
|| curwin->w_cursor.coladd != curwin->w_stl_cursor.coladd
|
||||
|| curwin->w_topline != curwin->w_stl_topline
|
||||
|| curwin->w_buffer->b_ml.ml_line_count != curwin->w_stl_line_count
|
||||
|| curwin->w_topfill != curwin->w_stl_topfill
|
||||
|| empty_line != curwin->w_stl_empty
|
||||
|| state != curwin->w_stl_state) {
|
||||
win_check_ns_hl(curwin);
|
||||
if ((*p_stl != NUL || *curwin->w_p_stl != NUL)
|
||||
&& (curwin->w_status_height || global_stl_height())) {
|
||||
redraw_custom_statusline(curwin);
|
||||
} else {
|
||||
win_redr_ruler(curwin);
|
||||
}
|
||||
if (*p_wbr != NUL || *curwin->w_p_wbr != NUL) {
|
||||
win_redr_winbar(curwin);
|
||||
}
|
||||
|
||||
if (need_maketitle
|
||||
|| (p_icon && (stl_syntax & STL_IN_ICON))
|
||||
|| (p_title && (stl_syntax & STL_IN_TITLE))) {
|
||||
maketitle();
|
||||
}
|
||||
|
||||
win_check_ns_hl(NULL);
|
||||
// Redraw the tab pages line if needed.
|
||||
if (redraw_tabline) {
|
||||
draw_tabline();
|
||||
}
|
||||
}
|
||||
|
||||
if (need_maketitle
|
||||
|| (p_icon && (stl_syntax & STL_IN_ICON))
|
||||
|| (p_title && (stl_syntax & STL_IN_TITLE))) {
|
||||
maketitle();
|
||||
}
|
||||
|
||||
win_check_ns_hl(NULL);
|
||||
// Redraw the tab pages line if needed.
|
||||
if (redraw_tabline) {
|
||||
draw_tabline();
|
||||
}
|
||||
curwin->w_stl_cursor = curwin->w_cursor;
|
||||
curwin->w_stl_virtcol = curwin->w_virtcol;
|
||||
curwin->w_stl_empty = (char)empty_line;
|
||||
curwin->w_stl_topline = curwin->w_topline;
|
||||
curwin->w_stl_line_count = curwin->w_buffer->b_ml.ml_line_count;
|
||||
curwin->w_stl_topfill = curwin->w_topfill;
|
||||
curwin->w_stl_state = state;
|
||||
}
|
||||
|
||||
static void redraw_win_signcol(win_T *wp)
|
||||
|
@ -907,6 +907,9 @@ theend:
|
||||
ui_call_cmdline_hide(ccline.level);
|
||||
msg_ext_clear_later();
|
||||
}
|
||||
if (!cmd_silent) {
|
||||
status_redraw_all(); // redraw to show mode change
|
||||
}
|
||||
|
||||
cmdline_level--;
|
||||
|
||||
|
@ -92,6 +92,7 @@
|
||||
#include "nvim/spell.h"
|
||||
#include "nvim/spellfile.h"
|
||||
#include "nvim/spellsuggest.h"
|
||||
#include "nvim/statusline.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/tag.h"
|
||||
#include "nvim/terminal.h"
|
||||
@ -2251,8 +2252,13 @@ static char *set_bool_option(const int opt_idx, char *const varp, const int valu
|
||||
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
|
||||
BOOLEAN_OBJ(*varp));
|
||||
}
|
||||
|
||||
comp_col(); // in case 'ruler' or 'showcmd' changed
|
||||
if ((int *)varp == &p_ru || (int *)varp == &p_sc) {
|
||||
// in case 'ruler' or 'showcmd' changed
|
||||
comp_col();
|
||||
if ((int *)varp == &p_ru) {
|
||||
win_redr_ruler(curwin);
|
||||
}
|
||||
}
|
||||
if (curwin->w_curswant != MAXCOL
|
||||
&& (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
|
||||
curwin->w_set_curswant = true;
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "nvim/spell.h"
|
||||
#include "nvim/spellfile.h"
|
||||
#include "nvim/spellsuggest.h"
|
||||
#include "nvim/statusline.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/tag.h"
|
||||
#include "nvim/ui.h"
|
||||
@ -1220,6 +1221,7 @@ static void did_set_statusline(win_T *win, char **varp, char **gvarp, char **err
|
||||
}
|
||||
if (varp == &p_ruf && *errmsg == NULL) {
|
||||
comp_col();
|
||||
win_redr_ruler(curwin);
|
||||
}
|
||||
// add / remove window bars for 'winbar'
|
||||
if (gvarp == &p_wbr) {
|
||||
|
@ -611,7 +611,7 @@ int showmode(void)
|
||||
// the ruler is after the mode message and must be redrawn
|
||||
win_T *last = lastwin_nofloating();
|
||||
if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
|
||||
win_redr_ruler(last, true);
|
||||
win_redr_ruler(last);
|
||||
}
|
||||
|
||||
redraw_cmdline = false;
|
||||
|
@ -162,7 +162,7 @@ void win_redr_status(win_T *wp)
|
||||
(int)((size_t)this_ru_col - strlen(NameBuff) - 1), attr);
|
||||
}
|
||||
|
||||
win_redr_ruler(wp, true);
|
||||
win_redr_ruler(wp);
|
||||
|
||||
// Draw the 'showcmd' information if 'showcmdloc' == "statusline".
|
||||
if (p_sc && *p_sloc == 's') {
|
||||
@ -443,7 +443,7 @@ void win_redr_winbar(win_T *wp)
|
||||
entered = false;
|
||||
}
|
||||
|
||||
void win_redr_ruler(win_T *wp, bool always)
|
||||
void win_redr_ruler(win_T *wp)
|
||||
{
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
static bool did_show_ext_ruler = false;
|
||||
@ -473,138 +473,116 @@ void win_redr_ruler(win_T *wp, bool always)
|
||||
}
|
||||
|
||||
// Check if not in Insert mode and the line is empty (will show "0-1").
|
||||
int empty_line = false;
|
||||
if ((State & MODE_INSERT) == 0 && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, false) == NUL) {
|
||||
empty_line = true;
|
||||
int empty_line = (State & MODE_INSERT) == 0
|
||||
&& *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false) == NUL;
|
||||
|
||||
int width;
|
||||
int row;
|
||||
int fillchar;
|
||||
int attr;
|
||||
int off;
|
||||
bool part_of_status = false;
|
||||
|
||||
if (wp->w_status_height) {
|
||||
row = W_ENDROW(wp);
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
off = wp->w_wincol;
|
||||
width = wp->w_width;
|
||||
part_of_status = true;
|
||||
} else if (is_stl_global) {
|
||||
row = Rows - (int)p_ch - 1;
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
off = 0;
|
||||
width = Columns;
|
||||
part_of_status = true;
|
||||
} else {
|
||||
row = Rows - 1;
|
||||
fillchar = ' ';
|
||||
attr = HL_ATTR(HLF_MSG);
|
||||
width = Columns;
|
||||
off = 0;
|
||||
}
|
||||
|
||||
// Only draw the ruler when something changed.
|
||||
validate_virtcol_win(wp);
|
||||
if (redraw_cmdline
|
||||
|| always
|
||||
|| wp->w_cursor.lnum != wp->w_ru_cursor.lnum
|
||||
|| wp->w_cursor.col != wp->w_ru_cursor.col
|
||||
|| wp->w_virtcol != wp->w_ru_virtcol
|
||||
|| wp->w_cursor.coladd != wp->w_ru_cursor.coladd
|
||||
|| wp->w_topline != wp->w_ru_topline
|
||||
|| wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
|
||||
|| wp->w_topfill != wp->w_ru_topfill
|
||||
|| empty_line != wp->w_ru_empty) {
|
||||
int width;
|
||||
int row;
|
||||
int fillchar;
|
||||
int attr;
|
||||
int off;
|
||||
bool part_of_status = false;
|
||||
if (!part_of_status && p_ch == 0 && !ui_has(kUIMessages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wp->w_status_height) {
|
||||
row = W_ENDROW(wp);
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
off = wp->w_wincol;
|
||||
width = wp->w_width;
|
||||
part_of_status = true;
|
||||
} else if (is_stl_global) {
|
||||
row = Rows - (int)p_ch - 1;
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
off = 0;
|
||||
width = Columns;
|
||||
part_of_status = true;
|
||||
} else {
|
||||
row = Rows - 1;
|
||||
fillchar = ' ';
|
||||
attr = HL_ATTR(HLF_MSG);
|
||||
width = Columns;
|
||||
off = 0;
|
||||
}
|
||||
|
||||
if (!part_of_status && p_ch == 0 && !ui_has(kUIMessages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In list mode virtcol needs to be recomputed
|
||||
colnr_T virtcol = wp->w_virtcol;
|
||||
if (wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL) {
|
||||
wp->w_p_list = false;
|
||||
getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
|
||||
wp->w_p_list = true;
|
||||
}
|
||||
// In list mode virtcol needs to be recomputed
|
||||
colnr_T virtcol = wp->w_virtcol;
|
||||
if (wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL) {
|
||||
wp->w_p_list = false;
|
||||
getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
|
||||
wp->w_p_list = true;
|
||||
}
|
||||
|
||||
#define RULER_BUF_LEN 70
|
||||
char buffer[RULER_BUF_LEN];
|
||||
char buffer[RULER_BUF_LEN];
|
||||
|
||||
// Some sprintfs return the length, some return a pointer.
|
||||
// To avoid portability problems we use strlen() here.
|
||||
vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",",
|
||||
(wp->w_buffer->b_ml.ml_flags &
|
||||
ML_EMPTY) ? (int64_t)0L : (int64_t)wp->w_cursor.lnum);
|
||||
size_t len = strlen(buffer);
|
||||
col_print(buffer + len, RULER_BUF_LEN - len,
|
||||
empty_line ? 0 : (int)wp->w_cursor.col + 1,
|
||||
(int)virtcol + 1);
|
||||
// Some sprintfs return the length, some return a pointer.
|
||||
// To avoid portability problems we use strlen() here.
|
||||
vim_snprintf(buffer, RULER_BUF_LEN, "%" PRId64 ",",
|
||||
(wp->w_buffer->b_ml.ml_flags &
|
||||
ML_EMPTY) ? (int64_t)0L : (int64_t)wp->w_cursor.lnum);
|
||||
size_t len = strlen(buffer);
|
||||
col_print(buffer + len, RULER_BUF_LEN - len,
|
||||
empty_line ? 0 : (int)wp->w_cursor.col + 1,
|
||||
(int)virtcol + 1);
|
||||
|
||||
// Add a "50%" if there is room for it.
|
||||
// On the last line, don't print in the last column (scrolls the
|
||||
// screen up on some terminals).
|
||||
int i = (int)strlen(buffer);
|
||||
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
|
||||
int o = i + vim_strsize(buffer + i + 1);
|
||||
if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
|
||||
// Add a "50%" if there is room for it.
|
||||
// On the last line, don't print in the last column (scrolls the
|
||||
// screen up on some terminals).
|
||||
int i = (int)strlen(buffer);
|
||||
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
|
||||
int o = i + vim_strsize(buffer + i + 1);
|
||||
if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
|
||||
o++;
|
||||
}
|
||||
int this_ru_col = ru_col - (Columns - width);
|
||||
if (this_ru_col < 0) {
|
||||
this_ru_col = 0;
|
||||
}
|
||||
// Never use more than half the window/screen width, leave the other half
|
||||
// for the filename.
|
||||
if (this_ru_col < (width + 1) / 2) {
|
||||
this_ru_col = (width + 1) / 2;
|
||||
}
|
||||
if (this_ru_col + o < width) {
|
||||
// Need at least 3 chars left for get_rel_pos() + NUL.
|
||||
while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) {
|
||||
i += utf_char2bytes(fillchar, buffer + i);
|
||||
o++;
|
||||
}
|
||||
int this_ru_col = ru_col - (Columns - width);
|
||||
if (this_ru_col < 0) {
|
||||
this_ru_col = 0;
|
||||
get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
|
||||
}
|
||||
|
||||
if (ui_has(kUIMessages) && !part_of_status) {
|
||||
MAXSIZE_TEMP_ARRAY(content, 1);
|
||||
MAXSIZE_TEMP_ARRAY(chunk, 2);
|
||||
ADD_C(chunk, INTEGER_OBJ(attr));
|
||||
ADD_C(chunk, STRING_OBJ(cstr_as_string(buffer)));
|
||||
ADD_C(content, ARRAY_OBJ(chunk));
|
||||
ui_call_msg_ruler(content);
|
||||
did_show_ext_ruler = true;
|
||||
} else {
|
||||
if (did_show_ext_ruler) {
|
||||
ui_call_msg_ruler((Array)ARRAY_DICT_INIT);
|
||||
did_show_ext_ruler = false;
|
||||
}
|
||||
// Never use more than half the window/screen width, leave the other half
|
||||
// for the filename.
|
||||
if (this_ru_col < (width + 1) / 2) {
|
||||
this_ru_col = (width + 1) / 2;
|
||||
}
|
||||
if (this_ru_col + o < width) {
|
||||
// Need at least 3 chars left for get_rel_pos() + NUL.
|
||||
while (this_ru_col + o < width && RULER_BUF_LEN > i + 4) {
|
||||
i += utf_char2bytes(fillchar, buffer + i);
|
||||
o++;
|
||||
// Truncate at window boundary.
|
||||
o = 0;
|
||||
for (i = 0; buffer[i] != NUL; i += utfc_ptr2len(buffer + i)) {
|
||||
o += utf_ptr2cells(buffer + i);
|
||||
if (this_ru_col + o > width) {
|
||||
buffer[i] = NUL;
|
||||
break;
|
||||
}
|
||||
get_rel_pos(wp, buffer + i, RULER_BUF_LEN - i);
|
||||
}
|
||||
|
||||
if (ui_has(kUIMessages) && !part_of_status) {
|
||||
MAXSIZE_TEMP_ARRAY(content, 1);
|
||||
MAXSIZE_TEMP_ARRAY(chunk, 2);
|
||||
ADD_C(chunk, INTEGER_OBJ(attr));
|
||||
ADD_C(chunk, STRING_OBJ(cstr_as_string(buffer)));
|
||||
ADD_C(content, ARRAY_OBJ(chunk));
|
||||
ui_call_msg_ruler(content);
|
||||
did_show_ext_ruler = true;
|
||||
} else {
|
||||
if (did_show_ext_ruler) {
|
||||
ui_call_msg_ruler((Array)ARRAY_DICT_INIT);
|
||||
did_show_ext_ruler = false;
|
||||
}
|
||||
// Truncate at window boundary.
|
||||
o = 0;
|
||||
for (i = 0; buffer[i] != NUL; i += utfc_ptr2len(buffer + i)) {
|
||||
o += utf_ptr2cells(buffer + i);
|
||||
if (this_ru_col + o > width) {
|
||||
buffer[i] = NUL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ScreenGrid *grid = part_of_status ? &default_grid : &msg_grid_adj;
|
||||
grid_puts(grid, buffer, row, this_ru_col + off, attr);
|
||||
grid_fill(grid, row, row + 1,
|
||||
this_ru_col + off + (int)strlen(buffer), off + width, fillchar,
|
||||
fillchar, attr);
|
||||
}
|
||||
|
||||
wp->w_ru_cursor = wp->w_cursor;
|
||||
wp->w_ru_virtcol = wp->w_virtcol;
|
||||
wp->w_ru_empty = (char)empty_line;
|
||||
wp->w_ru_topline = wp->w_topline;
|
||||
wp->w_ru_line_count = wp->w_buffer->b_ml.ml_line_count;
|
||||
wp->w_ru_topfill = wp->w_topfill;
|
||||
ScreenGrid *grid = part_of_status ? &default_grid : &msg_grid_adj;
|
||||
grid_puts(grid, buffer, row, this_ru_col + off, attr);
|
||||
grid_fill(grid, row, row + 1,
|
||||
this_ru_col + off + (int)strlen(buffer), off + width, fillchar,
|
||||
fillchar, attr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ local meths = helpers.meths
|
||||
local exec = helpers.exec
|
||||
local exec_lua = helpers.exec_lua
|
||||
local eval = helpers.eval
|
||||
local sleep = helpers.sleep
|
||||
|
||||
describe('statusline clicks', function()
|
||||
local screen
|
||||
@ -589,3 +590,35 @@ it('showcmdloc=statusline does not show if statusline is too narrow', function()
|
||||
feed('1234')
|
||||
screen:expect_unchanged()
|
||||
end)
|
||||
|
||||
it('K_EVENT does not trigger a statusline redraw unnecessarily', function()
|
||||
clear()
|
||||
local screen = Screen.new(40, 8)
|
||||
screen:attach()
|
||||
-- does not redraw on vim.schedule (#17937)
|
||||
command([[
|
||||
set laststatus=2
|
||||
let g:counter = 0
|
||||
func Status()
|
||||
let g:counter += 1
|
||||
lua vim.schedule(function() end)
|
||||
return g:counter
|
||||
endfunc
|
||||
set statusline=%!Status()
|
||||
]])
|
||||
sleep(50)
|
||||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||||
-- also in insert mode
|
||||
feed('i')
|
||||
sleep(50)
|
||||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||||
-- does not redraw on timer call (#14303)
|
||||
command([[
|
||||
let g:counter = 0
|
||||
func Timer(timer)
|
||||
endfunc
|
||||
call timer_start(1, 'Timer', {'repeat': 100})
|
||||
]])
|
||||
sleep(50)
|
||||
eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user