feat: cmdheight=0 #16251

Fix https://github.com/neovim/neovim/issues/1004

Limitation: All outputs need hit-enter prompt.

Related:
https://github.com/neovim/neovim/pull/6732
https://github.com/neovim/neovim/pull/4382
This commit is contained in:
Shougo
2022-06-13 18:40:51 +09:00
committed by GitHub
parent 2f71d4708e
commit 663cbe2620
13 changed files with 247 additions and 36 deletions

View File

@@ -1320,6 +1320,9 @@ A jump table for the options with a short description can be found at |Q_op|.
The value of this option is stored with the tab page, so that each tab
page can have a different value.
When 'cmdheight' is zero, it disables echo area and all outputs need
|hit-enter| prompt.
*'cmdwinheight'* *'cwh'*
'cmdwinheight' 'cwh' number (default 7)
global
@@ -4817,9 +4820,11 @@ A jump table for the options with a short description can be found at |Q_op|.
45% relative position in the file
If 'rulerformat' is set, it will determine the contents of the ruler.
Each window has its own ruler. If a window has a status line, the
ruler is shown there. Otherwise it is shown in the last line of the
screen. If the statusline is given by 'statusline' (i.e. not empty),
this option takes precedence over 'ruler' and 'rulerformat'
ruler is shown there. If a window doesn't have a status line and
'cmdheight' is 0, the ruler is not shown. Otherwise it is shown in
the last line of the screen. If the statusline is given by
'statusline' (i.e. not empty), this option takes precedence over
'ruler' and 'rulerformat'.
If the number of characters displayed is different from the number of
bytes in the text (e.g., for a TAB or a multibyte character), both
the text column (byte number) and the screen column are shown,
@@ -5525,6 +5530,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
Show (partial) command in the last line of the screen. Set this
option off if your terminal is slow.
The option is disabled if 'cmdheight' is 0.
In Visual mode the size of the selected area is shown:
- When selecting characters within a line, the number of characters.
If the number of bytes is different it is also displayed: "2-6"
@@ -5571,6 +5577,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global
If in Insert, Replace or Visual mode put a message on the last line.
The |hl-ModeMsg| highlight group determines the highlighting.
The option is disabled if 'cmdheight' is 0.
*'showtabline'* *'stal'*
'showtabline' 'stal' number (default 1)

View File

@@ -108,11 +108,9 @@ typedef enum {
kCmdRedrawAll,
} CmdRedraw;
/*
* Variables shared between getcmdline(), redrawcmdline() and others.
* These need to be saved when using CTRL-R |, that's why they are in a
* structure.
*/
// Variables shared between getcmdline(), redrawcmdline() and others.
// These need to be saved when using CTRL-R |, that's why they are in a
// structure.
struct cmdline_info {
char_u *cmdbuff; // pointer to command line buffer
int cmdbufflen; // length of cmdbuff
@@ -139,6 +137,7 @@ struct cmdline_info {
bool special_shift; ///< shift of last putcmdline char
CmdRedraw redraw_state; ///< needed redraw for external cmdline
};
/// Last value of prompt_id, incremented when doing new prompt
static unsigned last_prompt_id = 0;
@@ -689,6 +688,14 @@ 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)
{
bool cmdheight0 = p_ch < 1 && !ui_has(kUIMessages) && vpeekc() == NUL;
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();
}
// can be invoked recursively, identify each level
static int cmdline_level = 0;
cmdline_level++;
@@ -976,6 +983,11 @@ theend:
ccline.cmdbuff = NULL;
}
if (cmdheight0) {
// Restore cmdheight
set_option_value("ch", 0L, NULL, 0);
}
return p;
}
@@ -2670,6 +2682,12 @@ char *getcmdline_prompt(const char firstc, const char *const prompt, const int a
return ret;
}
// Return current cmdline prompt
char_u *get_cmdprompt(void)
{
return ccline.cmdprompt;
}
/*
* Return TRUE when the text must not be changed and we can't switch to
* another window or buffer. Used when editing the command line etc.
@@ -3777,7 +3795,7 @@ void redrawcmd(void)
msg_no_more = TRUE;
draw_cmdline(0, ccline.cmdlen);
msg_clr_eos();
msg_no_more = FALSE;
msg_no_more = false;
ccline.cmdspos = cmd_screencol(ccline.cmdpos);

View File

@@ -18,6 +18,7 @@
#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
#include "nvim/garray.h"
@@ -163,6 +164,7 @@ void msg_grid_validate(void)
{
grid_assign_handle(&msg_grid);
bool should_alloc = msg_use_grid();
int max_rows = Rows - p_ch;
if (should_alloc && (msg_grid.rows != Rows || msg_grid.cols != Columns
|| !msg_grid.chars)) {
// TODO(bfredl): eventually should be set to "invalid". I e all callers
@@ -174,7 +176,7 @@ void msg_grid_validate(void)
msg_grid.dirty_col = xcalloc(Rows, sizeof(*msg_grid.dirty_col));
// Tricky: allow resize while pager is active
int pos = msg_scrolled ? msg_grid_pos : Rows - p_ch;
int pos = msg_scrolled ? msg_grid_pos : max_rows;
ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols,
false, true);
ui_call_grid_resize(msg_grid.handle, msg_grid.cols, msg_grid.rows);
@@ -184,7 +186,7 @@ void msg_grid_validate(void)
msg_grid.focusable = false;
msg_grid_adj.target = &msg_grid;
if (!msg_scrolled) {
msg_grid_set_pos(Rows - p_ch, false);
msg_grid_set_pos(max_rows, false);
}
} else if (!should_alloc && msg_grid.chars) {
ui_comp_remove_grid(&msg_grid);
@@ -195,8 +197,8 @@ void msg_grid_validate(void)
msg_grid_adj.row_offset = 0;
msg_grid_adj.target = &default_grid;
redraw_cmdline = true;
} else if (msg_grid.chars && !msg_scrolled && msg_grid_pos != Rows - p_ch) {
msg_grid_set_pos(Rows - p_ch, false);
} else if (msg_grid.chars && !msg_scrolled && msg_grid_pos != max_rows) {
msg_grid_set_pos(max_rows, false);
}
if (msg_grid.chars && cmdline_row < msg_grid_pos) {
@@ -1386,7 +1388,9 @@ void msg_start(void)
need_fileinfo = false;
}
if (need_clr_eos) {
bool no_msg_area = !ui_has(kUIMessages) && p_ch < 1;
if (need_clr_eos || (no_msg_area && redrawing_cmdline)) {
// Halfway an ":echo" command and getting an (error) message: clear
// any text from the command.
need_clr_eos = false;
@@ -1395,10 +1399,11 @@ void msg_start(void)
if (!msg_scroll && full_screen) { // overwrite last message
msg_row = cmdline_row;
msg_col =
cmdmsg_rl ? Columns - 1 :
0;
} else if (msg_didout) { // start message on next line
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
msg_putchar('\n');
did_return = true;
cmdline_row = msg_row;
@@ -3055,7 +3060,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) {
if (msg_silent == 0 && p_ch > 0) {
msg_clr_eos_force();
}
}
@@ -3077,10 +3082,11 @@ void msg_clr_eos_force(void)
msg_row = msg_grid_pos;
}
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));
if (p_ch > 0) {
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)) {

View File

@@ -2747,6 +2747,10 @@ void pop_showcmd(void)
static void display_showcmd(void)
{
if (p_ch < 1 && !ui_has(kUIMessages)) {
return;
}
int len;
len = (int)STRLEN(showcmd_buf);
showcmd_is_clear = (len == 0);

View File

@@ -6041,6 +6041,10 @@ void cursor_pos_info(dict_T *dict)
// Don't shorten this message, the user asked for it.
p = p_shm;
p_shm = (char_u *)"";
if (p_ch < 1) {
msg_start();
msg_scroll = true;
}
msg((char *)IObuff);
p_shm = p;
}

View File

@@ -4365,7 +4365,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
errmsg = e_positive;
}
} else if (pp == &p_ch) {
int minval = ui_has(kUIMessages) ? 0 : 1;
int minval = 0;
if (value < minval) {
errmsg = e_positive;
}

View File

@@ -6132,6 +6132,10 @@ void unshowmode(bool force)
// Clear the mode message.
void clearmode(void)
{
if (p_ch <= 0 && !ui_has(kUIMessages)) {
return;
}
const int save_msg_row = msg_row;
const int save_msg_col = msg_col;
@@ -6500,7 +6504,6 @@ static void win_redr_ruler(win_T *wp, bool always)
if (*p_ruf) {
int save_called_emsg = called_emsg;
called_emsg = false;
win_redr_custom(wp, false, true);
if (called_emsg) {
@@ -6558,6 +6561,10 @@ static void win_redr_ruler(win_T *wp, bool always)
off = 0;
}
if (!part_of_status && p_ch < 1 && !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) {
@@ -6770,7 +6777,7 @@ void screen_resize(int width, int height)
Columns = width;
check_shellsize();
int max_p_ch = Rows - min_rows() + 1;
if (!ui_has(kUIMessages) && p_ch > max_p_ch) {
if (!ui_has(kUIMessages) && p_ch > 0 && p_ch > max_p_ch) {
p_ch = max_p_ch ? max_p_ch : 1;
}
height = Rows;

View File

@@ -887,6 +887,7 @@ func Test_floatwin_splitmove()
endfunc
func Test_window_resize()
throw 'Skipped: Nvim supports cmdheight=0'
" Vertical :resize (absolute, relative, min and max size).
vsplit
vert resize 8
@@ -1028,9 +1029,14 @@ func Test_win_move_statusline()
call assert_equal(h0, winheight(0))
call assert_equal(1, &cmdheight)
endfor
" Nvim supports cmdheight=0
set cmdheight=0
call assert_true(win_move_statusline(0, 1))
call assert_equal(h0, winheight(0))
call assert_equal(1, &cmdheight)
"call assert_equal(h0, winheight(0))
"call assert_equal(1, &cmdheight)
call assert_equal(h0 + 1, winheight(0))
call assert_equal(0, &cmdheight)
set cmdheight&
" check win_move_statusline from bottom window on top window ID
let id = win_getid(1)
for offset in range(5)

View File

@@ -907,7 +907,7 @@ void ui_ext_win_position(win_T *wp)
int comp_col = (int)col - (east ? wp->w_width_outer : 0);
comp_row += grid->comp_row;
comp_col += grid->comp_col;
comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - 1), 0);
comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - (p_ch > 0 ? 1 : 0)), 0);
comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0);
wp->w_winrow = comp_row;
wp->w_wincol = comp_col;
@@ -1144,6 +1144,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & WSP_ROOM) {
needed += p_wh - wmh1 + oldwin->w_winbar_height;
}
if (p_ch < 1) {
needed += 1; // Adjust for cmdheight=0.
}
if (flags & (WSP_BOT | WSP_TOP)) {
minheight = frame_minheight(topframe, NOWIN) + need_status;
available = topframe->fr_height;
@@ -5501,7 +5504,7 @@ void win_setheight_win(int height, win_T *win)
}
}
cmdline_row = row;
p_ch = MAX(Rows - cmdline_row, ui_has(kUIMessages) ? 0 : 1);
p_ch = MAX(Rows - cmdline_row, 0);
curtab->tp_ch_used = p_ch;
msg_row = row;
msg_col = 0;
@@ -5949,9 +5952,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
up = false;
// Only dragging the last status line can reduce p_ch.
room = Rows - cmdline_row;
if (curfr->fr_next == NULL) {
room -= 1;
} else {
if (curfr->fr_next != NULL) {
room -= p_ch + global_stl_height();
}
if (room < 0) {
@@ -6008,7 +6009,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
clear_cmdline = true;
}
cmdline_row = row;
p_ch = MAX(Rows - cmdline_row, ui_has(kUIMessages) ? 0 : 1);
p_ch = MAX(Rows - cmdline_row, 0);
curtab->tp_ch_used = p_ch;
redraw_all_later(SOME_VALID);
showmode();

View File

@@ -54,7 +54,7 @@ describe(':set validation', function()
should_fail('iminsert', 3, 'E474')
should_fail('imsearch', 3, 'E474')
should_fail('titlelen', -1, 'E487')
should_fail('cmdheight', 0, 'E487')
should_fail('cmdheight', -1, 'E487')
should_fail('updatecount', -1, 'E487')
should_fail('textwidth', -1, 'E487')
should_fail('tabstop', 0, 'E487')

View File

@@ -5,6 +5,8 @@ local source = helpers.source
local command = helpers.command
local assert_alive = helpers.assert_alive
local uname = helpers.uname
local eval = helpers.eval
local eq = helpers.eq
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -858,3 +860,156 @@ describe("cmdline height", function()
assert_alive()
end)
end)
describe('cmdheight=0', function()
local screen
before_each(function()
clear()
screen = Screen.new(25, 5)
screen:attach()
end)
it("with cmdheight=1 noruler laststatus=2", function()
command("set cmdheight=1 noruler laststatus=2")
screen:expect{grid=[[
^ |
~ |
~ |
[No Name] |
|
]]}
end)
it("with cmdheight=0 noruler laststatus=2", function()
command("set cmdheight=0 noruler laststatus=2")
screen:expect{grid=[[
^ |
~ |
~ |
~ |
[No Name] |
]]}
end)
it("with cmdheight=0 ruler laststatus=0", function()
command("set cmdheight=0 ruler laststatus=0")
screen:expect{grid=[[
^ |
~ |
~ |
~ |
~ |
]]}
end)
it("with cmdheight=0 ruler laststatus=0", function()
command("set cmdheight=0 noruler laststatus=0 showmode")
feed('i')
screen:expect{grid=[[
^ |
~ |
~ |
~ |
~ |
]], showmode={}}
feed('<Esc>')
eq(0, eval('&cmdheight'))
end)
it("with showmode", function()
command("set cmdheight=1 noruler laststatus=0 showmode")
feed('i')
screen:expect{grid=[[
^ |
~ |
~ |
~ |
-- INSERT -- |
]]}
feed('<Esc>')
eq(1, eval('&cmdheight'))
end)
it("when using command line", function()
command("set cmdheight=0 noruler laststatus=0")
feed(':')
screen:expect{grid=[[
|
~ |
~ |
~ |
:^ |
]]}
eq(1, eval('&cmdheight'))
feed('<cr>')
screen:expect{grid=[[
^ |
~ |
~ |
~ |
~ |
]], showmode={}}
eq(0, eval('&cmdheight'))
end)
it("when using input()", function()
command("set cmdheight=0 noruler laststatus=0")
feed(':call input("foo >")<cr>')
screen:expect{grid=[[
|
~ |
~ |
~ |
foo >^ |
]]}
eq(1, eval('&cmdheight'))
feed('<cr>')
screen:expect{grid=[[
^ |
~ |
~ |
~ |
~ |
]], showmode={}}
eq(0, eval('&cmdheight'))
end)
it("with winbar and splits", function()
command("set cmdheight=0 noruler laststatus=3 winbar=foo")
feed(':split<CR>')
screen:expect{grid=[[
foo |
|
E36: Not enough room |
Press ENTER or type comma|
nd to continue^ |
]]}
feed('<CR>')
screen:expect{grid=[[
foo |
^ |
~ |
~ |
[No Name] |
]]}
feed(':')
screen:expect{grid=[[
foo |
|
~ |
[No Name] |
:^ |
]]}
feed('<Esc>')
screen:expect{grid=[[
foo |
^ |
~ |
~ |
[No Name] |
]], showmode={}}
eq(0, eval('&cmdheight'))
assert_alive()
end)
end)

View File

@@ -737,7 +737,6 @@ describe('ui/ext_messages', function()
]])
eq(0, eval('&cmdheight'))
-- normally this would be an error
feed(':set cmdheight=0')
screen:expect{grid=[[
^ |

View File

@@ -313,5 +313,9 @@ describe('global statusline', function()
eq(2, meths.get_option('cmdheight'))
meths.input_mouse('left', 'drag', '', 0, 14, 10)
eq(1, meths.get_option('cmdheight'))
meths.input_mouse('left', 'drag', '', 0, 15, 10)
eq(0, meths.get_option('cmdheight'))
meths.input_mouse('left', 'drag', '', 0, 14, 10)
eq(1, meths.get_option('cmdheight'))
end)
end)