UI/ext_messages: learn more message kinds

ref #6201
This commit is contained in:
Justin M. Keyes 2019-05-09 23:54:04 +02:00
parent 7c9d4d971c
commit 3d1ed7c959
8 changed files with 175 additions and 49 deletions

View File

@ -672,29 +672,33 @@ of the cmdline.
["msg_show", kind, content, replace_last]
Display a message to the user.
`kind` will be one of the following
`emsg`: Internal error message
`echo`: temporary message from plugin (|:echo|)
`echomsg`: ordinary message from plugin (|:echomsg|)
`echoerr`: error message from plugin (|:echoerr|)
`return_prompt`: |press-enter| prompt after a group of messages
`quickfix`: Quickfix navigation message
`kind` can also be the empty string. The message is then some internal
informative or warning message, that hasn't yet been assigned a kind.
New message kinds can be added in later versions; clients should
handle messages of an unknown kind just like empty kind.
kind
Name indicating the message kind:
"" (empty) Unknown, report a |feature-request|
"confirm" |confirm()| or |:confirm| dialog
"confirm_sub" |:substitute| confirm dialog |:s_c|
"emsg" Error (|errors|, internal error, |:throw|, …)
"echo" |:echo| message
"echomsg" |:echomsg| message
"echoerr" |:echoerr| message
"return_prompt" |press-enter| prompt after a multiple messages
"quickfix" Quickfix navigation message
"wmsg" Warning ("search hit BOTTOM", |W10|, …)
New kinds may be added in the future; clients should treat unknown
kinds as the empty kind.
`content` will be an array of `[attr_id, text_chunk]` tuples,
building up the message text of chunks of different highlights.
No extra spacing should be added between chunks, the `text_chunk` by
itself should contain any necessary whitespace. Messages can contain
line breaks `"\n"`.
content
Array of `[attr_id, text_chunk]` tuples, building up the message
text of chunks of different highlights. No extra spacing should be
added between chunks, the `text_chunk` by itself contains any
necessary whitespace. Messages can contain line breaks "\n".
`replace_last` controls how multiple messages should be displayed.
If `replace_last` is false, this message should be displayed together
with all previous messages that are still visible. If `replace_last`
is true, this message should replace the message in the most recent
`msg_show` call, but any other visible message should still remain.
replace_last
Decides how multiple messages should be displayed:
false: Display the message together with all previous messages
that are still visible.
true: Replace the message in the most-recent `msg_show` call,
but any other visible message should still remain.
["msg_clear"]
Clear all messages currently displayed by "msg_show". (Messages sent

View File

@ -3692,10 +3692,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
i = msg_scroll;
msg_scroll = 0; /* truncate msg when
needed */
msg_no_more = TRUE;
/* write message same highlighting as for
* wait_return */
smsg_attr(HL_ATTR(HLF_R),
msg_no_more = true;
msg_ext_set_kind("confirm_sub");
smsg_attr(HL_ATTR(HLF_R), // Same highlight as wait_return().
_("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
msg_no_more = FALSE;
msg_scroll = i;

View File

@ -839,9 +839,10 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
sourcing_lnum = current_exception->throw_lnum;
current_exception->throw_name = NULL;
discard_current_exception(); /* uses IObuff if 'verbose' */
suppress_errthrow = TRUE;
force_abort = TRUE;
discard_current_exception(); // uses IObuff if 'verbose'
suppress_errthrow = true;
force_abort = true;
msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993
if (messages != NULL) {
do {

View File

@ -3008,6 +3008,8 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
} else {
keep_msg_attr = 0;
}
msg_ext_set_kind("wmsg");
if (msg_attr((const char *)message, keep_msg_attr) && msg_scrolled == 0) {
set_keep_msg(message, keep_msg_attr);
}
@ -3348,6 +3350,7 @@ void display_confirm_msg(void)
// Avoid that 'q' at the more prompt truncates the message here.
confirm_msg_used++;
if (confirm_msg != NULL) {
msg_ext_set_kind("confirm");
msg_puts_attr((const char *)confirm_msg, HL_ATTR(HLF_M));
}
confirm_msg_used--;

View File

@ -2248,6 +2248,7 @@ change_warning (
if (msg_row == Rows - 1)
msg_col = col;
msg_source(HL_ATTR(HLF_W));
msg_ext_set_kind("wmsg");
MSG_PUTS_ATTR(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
msg_clr_eos();

View File

@ -277,7 +277,6 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
// Enums need a typecast to be used as array index (for Ultrix).
#define HL_ATTR(n) highlight_attr[(int)(n)]
#define TERM_STR(n) term_strings[(int)(n)]
/// Maximum number of bytes in a multi-byte character. It can be one 32-bit
/// character of up to 6 bytes, or one 16-bit character of up to three bytes

View File

@ -22,8 +22,129 @@ describe('ui/ext_messages', function()
[6] = {bold = true, reverse = true},
})
end)
after_each(function()
os.remove('Xtest')
end)
it('supports :echoerr', function()
it('msg_show kind=confirm,confirm_sub,emsg,wmsg', function()
feed('iline 1\nline 2<esc>')
-- kind=confirm
feed(':echo confirm("test")<cr>')
screen:expect{grid=[[
line 1 |
line ^2 |
{1:~ }|
{1:~ }|
{1:~ }|
]], messages={ {
content = {{"\ntest\n[O]k: ", 4}},
kind = 'confirm',
}}}
feed('<cr><cr>')
screen:expect{grid=[[
line 1 |
line ^2 |
{1:~ }|
{1:~ }|
{1:~ }|
]], messages={ {
content = { { "\ntest\n[O]k: ", 4 } },
kind = "confirm"
}, {
content = { { "1" } },
kind = "echo"
}, {
content = { { "Press ENTER or type command to continue", 4 } },
kind = "return_prompt"
} }}
feed('<cr><cr>')
-- kind=confirm_sub
feed(':%s/i/X/gc<cr>')
screen:expect{grid=[[
l{7:i}ne 1 |
l{8:i}ne ^2 |
{1:~ }|
{1:~ }|
{1:~ }|
]], attr_ids={
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true},
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
[5] = {foreground = Screen.colors.Blue1},
[6] = {bold = true, reverse = true},
[7] = {reverse = true},
[8] = {background = Screen.colors.Yellow},
}, messages={ {
content = { { "replace with X (y/n/a/q/l/^E/^Y)?", 4 } },
kind = "confirm_sub"
} }}
feed('nq')
-- kind=wmsg (editing readonly file)
command('write Xtest')
command('set readonly nohls')
feed('G$x')
screen:expect{grid=[[
line 1 |
{IGNORE}|
{1:~ }|
{1:~ }|
{1:~ }|
]], attr_ids={
[1] = {bold = true, foreground = Screen.colors.Blue1},
[7] = {foreground = Screen.colors.Red},
}, messages={ {
content = { { "W10: Warning: Changing a readonly file", 7 } },
kind = "wmsg"
}
}}
-- kind=wmsg ('wrapscan' after search reaches EOF)
feed('uG$/i<cr>')
screen:expect{grid=[[
l^ine 1 |
line 2 |
{1:~ }|
{1:~ }|
{1:~ }|
]], attr_ids={
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true},
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
[5] = {foreground = Screen.colors.Blue1},
[6] = {bold = true, reverse = true},
[7] = {foreground = Screen.colors.Red},
}, messages={ {
content = { { "search hit BOTTOM, continuing at TOP", 7 } },
kind = "wmsg"
} }}
-- kind=emsg after :throw
feed(':throw "foo"<cr>')
screen:expect{grid=[[
l^ine 1 |
line 2 |
{1:~ }|
{1:~ }|
{1:~ }|
]], messages={ {
content = { { "Error detected while processing :", 2 } },
kind = "emsg"
}, {
content = { { "E605: Exception not caught: foo", 2 } },
kind = ""
}, {
content = { { "Press ENTER or type command to continue", 4 } },
kind = "return_prompt"
} }
}
end)
it(':echoerr', function()
feed(':echoerr "raa"<cr>')
screen:expect{grid=[[
^ |
@ -142,7 +263,7 @@ describe('ui/ext_messages', function()
}}
end)
it('supports showmode', function()
it('&showmode', function()
command('imap <f2> <cmd>echomsg "stuff"<cr>')
feed('i')
screen:expect{grid=[[
@ -230,7 +351,7 @@ describe('ui/ext_messages', function()
}}
end)
it('supports showmode with recording message', function()
it('&showmode with macro-recording message', function()
feed('qq')
screen:expect{grid=[[
^ |
@ -268,7 +389,7 @@ describe('ui/ext_messages', function()
]])
end)
it('shows recording message with noshowmode', function()
it('shows macro-recording message with &noshowmode', function()
command("set noshowmode")
feed('qq')
-- also check mode to avoid immediate success
@ -308,7 +429,7 @@ describe('ui/ext_messages', function()
]], mode="normal"}
end)
it('supports showcmd and ruler', function()
it('supports &showcmd and &ruler', function()
command('set showcmd ruler')
screen:expect{grid=[[
^ |

View File

@ -74,6 +74,7 @@
local global_helpers = require('test.helpers')
local deepcopy = global_helpers.deepcopy
local shallowcopy = global_helpers.shallowcopy
local concat_tables = global_helpers.concat_tables
local helpers = require('test.functional.helpers')(nil)
local request, run_session = helpers.request, helpers.run_session
local eq = helpers.eq
@ -413,26 +414,23 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
-- Extension features. The default expectations should cover the case of
-- UI extensions. The default expectations should cover the case of
-- the ext_ feature being disabled, or the feature currently not activated
-- (for instance no external cmdline visible). Some extensions require
-- (e.g. no external cmdline visible). Some extensions require
-- preprocessing to represent highlights in a reproducible way.
local extstate = self:_extstate_repr(attr_state)
-- convert assertion errors into invalid screen state descriptions
local status, res = pcall(function()
for _, k in ipairs(ext_keys) do
-- Empty states is considered the default and need not be mentioned
if not (expected[k] == nil and isempty(extstate[k])) then
eq(expected[k], extstate[k], k)
if expected['mode'] ~= nil then
extstate['mode'] = self.mode
end
end
if expected.mode ~= nil then
eq(expected.mode, self.mode, "mode")
end
end)
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
-- Empty states are considered the default and need not be mentioned.
if (not (expected[k] == nil and isempty(extstate[k]))) then
local status, res = pcall(eq, expected[k], extstate[k], k)
if not status then
return tostring(res)
return (tostring(res)..'\nHint: full state of "'..k..'":\n '..inspect(extstate[k]))
end
end
end
end, expected)
end