From 708bd686516b420c2b65f4bc4d2c58fe43fb945e Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 13 Sep 2022 12:56:30 +0200 Subject: [PATCH] feat(ui): use msg_grid based implementation for cmdheight=0 --- runtime/doc/options.txt | 3 +- src/nvim/ex_cmds.c | 22 ++++------- src/nvim/ex_getln.c | 37 ++++--------------- src/nvim/getchar.c | 13 ++----- src/nvim/globals.h | 3 -- src/nvim/message.c | 47 +++++++++++++----------- src/nvim/normal.c | 3 +- src/nvim/ops.c | 18 +-------- src/nvim/option.c | 7 ++-- src/nvim/screen.c | 6 ++- src/nvim/statusline.c | 2 +- src/nvim/testdir/test_messages.vim | 2 +- src/nvim/ui.c | 6 --- src/nvim/ui_compositor.c | 6 ++- src/nvim/window.c | 3 +- test/functional/ui/cmdline_spec.lua | 20 +++++----- test/functional/vimscript/timer_spec.lua | 26 ++++++------- 17 files changed, 89 insertions(+), 135 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 110f7400e6..14b7eb2d71 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1337,7 +1337,8 @@ A jump table for the options with a short description can be found at |Q_op|. page can have a different value. When 'cmdheight' is zero, there is no command-line unless it is being - used. Some informative messages will not be displayed, any other + used. The command-line will cover the last line of the screen when + shown. Some informative messages will not be displayed, any other messages will cause the |hit-enter| prompt. Expect some other unexpected behavior too. diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 2cc64918a3..462212c4ce 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3616,13 +3616,6 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T } } - const bool cmdheight0 = !ui_has_messages(); - if (cmdheight0) { - // If cmdheight is 0, cmdheight must be set to 1 when we enter command line. - set_option_value("ch", 1L, NULL, 0); - redraw_statuslines(); - } - // Check for a match on each line. // If preview: limit to max('cmdwinheight', viewport). linenr_T line2 = eap->line2; @@ -3914,7 +3907,9 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T msg_no_more = false; msg_scroll = (int)i; show_cursor_info(true); - ui_cursor_goto(msg_row, msg_col); + if (!ui_has(kUIMessages)) { + ui_cursor_goto(msg_row, msg_col); + } RedrawingDisabled = temp; no_mapping++; // don't map this key @@ -4370,7 +4365,7 @@ skip: beginline(BL_WHITE | BL_FIX); } } - if (!cmdpreview && !do_sub_msg(subflags.do_count) && subflags.do_ask) { + if (!cmdpreview && !do_sub_msg(subflags.do_count) && subflags.do_ask && p_ch > 0) { msg(""); } } else { @@ -4385,7 +4380,9 @@ skip: emsg(_(e_interr)); } else if (got_match) { // did find something but nothing substituted - msg(""); + if (p_ch > 0) { + msg(""); + } } else if (subflags.do_error) { // nothing found semsg(_(e_patnotf2), get_search_pat()); @@ -4418,11 +4415,6 @@ skip: } } - if (cmdheight0) { - // Restore cmdheight - set_option_value("ch", 0L, NULL, 0); - } - kv_destroy(preview_lines.subresults); return retv; #undef ADJUST_SUB_FIRSTLNUM diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c3bdeb618d..e092ea45cf 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -599,24 +599,6 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool /// @param init_ccline clear ccline first static uint8_t *command_line_enter(int firstc, long count, int indent, bool init_ccline) { - const bool cmdheight0 = !ui_has_messages(); - - if (cmdheight0) { - const long save_so = lastwin->w_p_so; - - // If cmdheight is 0, cmdheight must be set to 1 when we enter the - // command line. Set "made_cmdheight_nonzero" and reset 'scrolloff' to - // avoid scrolling the last window. - made_cmdheight_nonzero = true; - - lastwin->w_p_so = 0; - set_option_value("ch", 1L, NULL, 0); - update_screen(UPD_VALID); // redraw the screen NOW - - made_cmdheight_nonzero = false; - lastwin->w_p_so = save_so; - } - // can be invoked recursively, identify each level static int cmdline_level = 0; cmdline_level++; @@ -865,6 +847,11 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init // If the line is too long, clear it, so ruler and shown command do // 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; + } + } msg_scroll = s->save_msg_scroll; redir_off = false; @@ -911,17 +898,6 @@ theend: ccline.cmdbuff = NULL; } - if (cmdheight0) { - made_cmdheight_nonzero = true; - - // Restore cmdheight - set_option_value("ch", 0L, NULL, 0); - // Redraw is needed for command line completion - redraw_all_later(UPD_NOT_VALID); - - made_cmdheight_nonzero = false; - } - return p; } @@ -3717,6 +3693,9 @@ void compute_cmdrow(void) cmdline_row = wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height + global_stl_height(); } + if (cmdline_row == Rows) { + cmdline_row--; + } lines_left = cmdline_row; } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index c7cfc91591..c93810df8d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1655,9 +1655,10 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) no_mapping++; allow_keys++; for (;;) { - // Position the cursor. Needed after a message that ends in a space, - // or if event processing caused a redraw. - ui_cursor_goto(msg_row, msg_col); + if (msg_col > 0) { + // Position the cursor. Needed after a message that ends in a space. + ui_cursor_goto(msg_row, msg_col); + } if (argvars[0].v_type == VAR_UNKNOWN) { // getchar(): blocking wait. @@ -1695,12 +1696,6 @@ static void getchar_common(typval_T *argvars, typval_T *rettv) no_mapping--; allow_keys--; - if (!ui_has_messages()) { - // redraw the screen after getchar() - update_screen(UPD_NOT_VALID); - clear_cmdline = true; - } - set_vim_var_nr(VV_MOUSE_WIN, 0); set_vim_var_nr(VV_MOUSE_WINID, 0); set_vim_var_nr(VV_MOUSE_LNUM, 0); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 1cd8db6266..f6669a878e 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1071,7 +1071,4 @@ EXTERN char windowsVersion[20] INIT(= { 0 }); EXTERN int exit_need_delay INIT(= 0); -// Set when 'cmdheight' is changed from zero to one temporarily. -EXTERN bool made_cmdheight_nonzero INIT(= false); - #endif // NVIM_GLOBALS_H diff --git a/src/nvim/message.c b/src/nvim/message.c index fd8aa00d7b..8bcf5a552f 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -909,7 +909,7 @@ char *msg_may_trunc(bool force, char *s) room = (Rows - cmdline_row - 1) * Columns + sc_col - 1; if ((force || (shortmess(SHM_TRUNC) && !exmode_active)) - && (int)strlen(s) - room > 0 && p_ch > 0) { + && (int)STRLEN(s) - room > 0) { int size = vim_strsize(s); // There may be room anyway when there are multibyte chars. @@ -1401,9 +1401,7 @@ void msg_start(void) need_fileinfo = false; } - const bool no_msg_area = !ui_has_messages(); - - if (need_clr_eos || (no_msg_area && redrawing_cmdline)) { + if (need_clr_eos || (p_ch == 0 && redrawing_cmdline)) { // Halfway an ":echo" command and getting an (error) message: clear // any text from the command. need_clr_eos = false; @@ -1411,12 +1409,14 @@ void msg_start(void) } if (!msg_scroll && full_screen) { // overwrite last message + if (cmdline_row >= Rows && !ui_has(kUIMessages)) { + msg_scroll_up(false, true); + msg_scrolled++; + cmdline_row = Rows - 1; + } msg_row = cmdline_row; msg_col = cmdmsg_rl ? Columns - 1 : 0; - if (no_msg_area && get_cmdprompt() == NULL) { - msg_row -= 1; - } - } else if (msg_didout || no_msg_area) { // start message on next line + } else if (msg_didout || (p_ch == 0 && !ui_has(kUIMessages))) { // start message on next line msg_putchar('\n'); did_return = true; cmdline_row = msg_row; @@ -2186,7 +2186,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) // Scroll the screen up one line. bool has_last_char = ((uint8_t)(*s) >= ' ' && !cmdmsg_rl); - msg_scroll_up(!has_last_char); + msg_scroll_up(!has_last_char, false); msg_row = Rows - 2; if (msg_col >= Columns) { // can happen after screen resize @@ -2350,7 +2350,7 @@ bool msg_use_msgsep(void) { // the full-screen scroll behavior doesn't really make sense with // 'ext_multigrid' - return (dy_flags & DY_MSGSEP) || ui_has(kUIMultigrid); + return (dy_flags & DY_MSGSEP) || p_ch == 0 || ui_has(kUIMultigrid); } bool msg_do_throttle(void) @@ -2359,7 +2359,7 @@ bool msg_do_throttle(void) } /// Scroll the screen up one line for displaying the next message line. -void msg_scroll_up(bool may_throttle) +void msg_scroll_up(bool may_throttle, bool zerocmd) { if (may_throttle && msg_do_throttle()) { msg_grid.throttled = true; @@ -2367,7 +2367,13 @@ void msg_scroll_up(bool may_throttle) msg_did_scroll = true; if (msg_use_msgsep()) { if (msg_grid_pos > 0) { - msg_grid_set_pos(msg_grid_pos - 1, true); + msg_grid_set_pos(msg_grid_pos - 1, !zerocmd); + + // When displaying the first line with cmdheight=0, we need to draw over + // the existing last line of the screen. + if (zerocmd && msg_grid.chars) { + grid_clear_line(&msg_grid, msg_grid.line_offset[0], msg_grid.cols, false); + } } else { grid_del_lines(&msg_grid, 0, 1, msg_grid.rows, 0, msg_grid.cols); memmove(msg_grid.dirty_col, msg_grid.dirty_col + 1, @@ -2378,8 +2384,7 @@ void msg_scroll_up(bool may_throttle) grid_del_lines(&msg_grid_adj, 0, 1, Rows, 0, Columns); } - grid_fill(&msg_grid_adj, Rows - 1, Rows, 0, Columns, ' ', ' ', - HL_ATTR(HLF_MSG)); + grid_fill(&msg_grid_adj, Rows - 1, Rows, 0, Columns, ' ', ' ', HL_ATTR(HLF_MSG)); } /// Send throttled message output to UI clients @@ -2958,7 +2963,7 @@ static int do_more_prompt(int typed_char) msg_grid_scroll_discount++; } // scroll up, display line at bottom - msg_scroll_up(true); + msg_scroll_up(true, false); inc_msg_scrolled(); grid_fill(&msg_grid_adj, Rows - 2, Rows - 1, 0, Columns, ' ', ' ', HL_ATTR(HLF_MSG)); @@ -3094,7 +3099,7 @@ void repeat_message(void) /// Skip this when ":silent" was used, no need to clear for redirection. void msg_clr_eos(void) { - if (msg_silent == 0 && p_ch > 0) { + if (msg_silent == 0) { msg_clr_eos_force(); } } @@ -3116,12 +3121,10 @@ void msg_clr_eos_force(void) msg_row = msg_grid_pos; } - if (ui_has_messages()) { - grid_fill(&msg_grid_adj, msg_row, msg_row + 1, msg_startcol, msg_endcol, - ' ', ' ', HL_ATTR(HLF_MSG)); - grid_fill(&msg_grid_adj, msg_row + 1, Rows, 0, Columns, - ' ', ' ', HL_ATTR(HLF_MSG)); - } + grid_fill(&msg_grid_adj, msg_row, msg_row + 1, msg_startcol, msg_endcol, + ' ', ' ', HL_ATTR(HLF_MSG)); + grid_fill(&msg_grid_adj, msg_row + 1, Rows, 0, Columns, + ' ', ' ', HL_ATTR(HLF_MSG)); redraw_cmdline = true; // overwritten the command line if (msg_row < Rows - 1 || msg_col == (cmdmsg_rl ? Columns : 0)) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 249d5b6c0b..95665053b3 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -2817,7 +2817,8 @@ void pop_showcmd(void) static void display_showcmd(void) { - if (!ui_has_messages()) { + if (p_ch == 0 && !ui_has(kUIMessages)) { + // TODO(bfredl): would be nice to show in global statusline, perhaps return; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 420f6cf840..83484859ed 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -896,7 +896,6 @@ int do_record(int c) { char_u *p; static int regname; - static bool changed_cmdheight = false; yankreg_T *old_y_previous; int retval; @@ -907,18 +906,11 @@ int do_record(int c) retval = FAIL; } else { reg_recording = c; + // TODO(bfredl): showmode based messaging is currently missing with cmdheight=0 showmode(); regname = c; retval = OK; - if (!ui_has_messages()) { - // Enable macro indicator temporarily - set_option_value("ch", 1L, NULL, 0); - update_screen(UPD_VALID); - - changed_cmdheight = true; - } - apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf); } } else { // stop recording @@ -948,7 +940,7 @@ int do_record(int c) restore_v_event(dict, &save_v_event); reg_recorded = reg_recording; reg_recording = 0; - if (ui_has(kUIMessages)) { + if (p_ch == 0 || ui_has(kUIMessages)) { showmode(); } else { msg(""); @@ -964,12 +956,6 @@ int do_record(int c) y_previous = old_y_previous; } - - if (changed_cmdheight) { - // Restore cmdheight - set_option_value("ch", 0L, NULL, 0); - redraw_all_later(UPD_CLEAR); - } } return retval; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 5adec084e6..8ef06bcba8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2570,9 +2570,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, Rows = (int)p_lines; Columns = (int)p_columns; check_screensize(); - if (cmdline_row > Rows - p_ch && Rows > p_ch) { - assert(p_ch >= 0 && Rows - p_ch <= INT_MAX); - cmdline_row = (int)(Rows - p_ch); + int new_row = (int)(Rows - MAX(p_ch, 1)); + if (cmdline_row > new_row && Rows > p_ch) { + assert(p_ch >= 0 && new_row <= INT_MAX); + cmdline_row = new_row; } } if (p_window >= Rows || !option_was_set("window")) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 0ec6834364..cdfb1e9ee1 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -442,7 +442,7 @@ void redraw_wildmenu(expand_T *xp, int num_matches, char **matches, int match, i // Put the wildmenu just above the command line. If there is // no room, scroll the screen one line up. if (cmdline_row == Rows - 1) { - msg_scroll_up(false); + msg_scroll_up(false, false); msg_scrolled++; } else { cmdline_row++; @@ -1173,7 +1173,9 @@ bool redrawing(void) /// Return true if printing messages should currently be done. bool messaging(void) { - return !(p_lz && char_avail() && !KeyTyped) && ui_has_messages(); + // TODO(bfredl): with general support for "async" messages with p_ch, + // this should be re-enabled. + return !(p_lz && char_avail() && !KeyTyped) && (p_ch > 0 || ui_has(kUIMessages)); } #define COL_RULER 17 // columns needed by standard ruler diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 94462d4073..665a72b083 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -266,7 +266,7 @@ void win_redr_ruler(win_T *wp, bool always) off = 0; } - if (!part_of_status && !ui_has_messages()) { + if (!part_of_status && p_ch == 0 && !ui_has(kUIMessages)) { return; } diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 3a607ff533..a83fcd7138 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -398,7 +398,7 @@ func Test_cmdheight_zero() " Check change/restore cmdheight when macro call feedkeys("qa", "xt") - call assert_equal(1, &cmdheight) + call assert_equal(0, &cmdheight) call feedkeys("q", "xt") call assert_equal(0, &cmdheight) diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 911eefadd8..09eedcf059 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -614,12 +614,6 @@ bool ui_has(UIExtension ext) return ui_ext[ext]; } -/// Returns true if the UI has messages area. -bool ui_has_messages(void) -{ - return p_ch > 0 || ui_has(kUIMessages); -} - Array ui_array(void) { Array all_uis = ARRAY_DICT_INIT; diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 2fb70eae8a..9f9a32036c 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -485,6 +485,10 @@ static void compose_debug(Integer startrow, Integer endrow, Integer startcol, In endcol = MIN(endcol, default_grid.cols); int attr = syn_id2attr(syn_id); + if (delay) { + debug_delay(endrow - startrow); + } + for (int row = (int)startrow; row < endrow; row++) { ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false, (const schar_T *)linebuf, @@ -610,7 +614,7 @@ static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrol if (row > msg_current_row && ui_comp_should_draw()) { compose_area(MAX(msg_current_row - 1, 0), row, 0, default_grid.cols); } else if (row < msg_current_row && ui_comp_should_draw() - && msg_current_row < Rows) { + && (msg_current_row < Rows || (scrolled && !msg_was_scrolled))) { int delta = msg_current_row - (int)row; if (msg_grid.blending) { int first_row = MAX((int)row - (scrolled?1:0), 0); diff --git a/src/nvim/window.c b/src/nvim/window.c index f6301457f3..2ccbdc10ea 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6193,8 +6193,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) // There is no point in adjusting the scroll position when exiting. Some // values might be invalid. - // Skip scroll_to_fraction() when 'cmdheight' was set to one from zero. - if (!exiting && !made_cmdheight_nonzero && valid_cursor) { + if (!exiting && valid_cursor) { scroll_to_fraction(wp, prev_height); } redraw_later(wp, UPD_NOT_VALID); // UPD_SOME_VALID?? diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index db13647cc6..40dee4186b 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1022,7 +1022,7 @@ describe('cmdheight=0', function() ~ | :^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('') screen:expect{grid=[[ ^ | @@ -1040,11 +1040,11 @@ describe('cmdheight=0', function() screen:expect{grid=[[ | ~ | - ~ | - ~ | + | + :call input("foo >") | foo >^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('') screen:expect{grid=[[ ^ | @@ -1060,8 +1060,8 @@ describe('cmdheight=0', function() command("set cmdheight=0 noruler laststatus=3 winbar=foo") feed(':split') screen:expect{grid=[[ - foo | | + :split | E36: Not enough room | Press ENTER or type comma| nd to continue^ | @@ -1079,7 +1079,7 @@ describe('cmdheight=0', function() foo | | ~ | - [No Name] | + ~ | :^ | ]]} feed('') @@ -1103,8 +1103,8 @@ describe('cmdheight=0', function() ~ | ~ | ~ | - recording @q | - ]], showmode={}} + ~ | + ]]} feed('q') screen:expect{grid=[[ ^ | @@ -1112,7 +1112,7 @@ describe('cmdheight=0', function() ~ | ~ | ~ | - ]], showmode={}} + ]], unchanged=true} end) it("when substitute text", function() @@ -1131,7 +1131,7 @@ describe('cmdheight=0', function() foo | ~ | ~ | - [No Name] [+] | + ~ | replace wi...q/l/^E/^Y)?^ | ]]} diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua index 5463cfb234..1818a71ea2 100644 --- a/test/functional/vimscript/timer_spec.lua +++ b/test/functional/vimscript/timer_spec.lua @@ -131,26 +131,15 @@ describe('timers', function() nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})") screen:expect([[ - ITEM 1 | + ^ITEM 1 | ITEM 2 | {1:~ }| {1:~ }| {1:~ }| - ^ | + | ]]) nvim_async("command", "let g:cont = 1") - screen:expect([[ - ITEM 1 | - ITEM 2 | - ITEM 3 | - {1:~ }| - {1:~ }| - ^ | - ]]) - - feed("3") - eq(51, eval("g:c2")) screen:expect([[ ^ITEM 1 | ITEM 2 | @@ -159,6 +148,17 @@ describe('timers', function() {1:~ }| | ]]) + + feed("3") + eq(51, eval("g:c2")) + screen:expect{grid=[[ + ^ITEM 1 | + ITEM 2 | + ITEM 3 | + {1:~ }| + {1:~ }| + | + ]], unchanged=true} end) it('can be stopped', function()