aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2019-05-09 23:54:04 +0200
committerJustin M. Keyes <justinkz@gmail.com>2019-05-11 23:42:55 +0200
commit3d1ed7c959017dc8664497b26c86c9ffabf02891 (patch)
tree99a2d680a63de8d1ac63fc5abb05b04dd16518b6
parent7c9d4d971cab4525fb2245ec527736b4e9471e84 (diff)
downloadrneovim-3d1ed7c959017dc8664497b26c86c9ffabf02891.tar.gz
rneovim-3d1ed7c959017dc8664497b26c86c9ffabf02891.tar.bz2
rneovim-3d1ed7c959017dc8664497b26c86c9ffabf02891.zip
UI/ext_messages: learn more message kinds
ref #6201
-rw-r--r--runtime/doc/ui.txt50
-rw-r--r--src/nvim/ex_cmds.c7
-rw-r--r--src/nvim/ex_docmd.c7
-rw-r--r--src/nvim/message.c3
-rw-r--r--src/nvim/misc1.c1
-rw-r--r--src/nvim/vim.h1
-rw-r--r--test/functional/ui/messages_spec.lua131
-rw-r--r--test/functional/ui/screen.lua28
8 files changed, 177 insertions, 51 deletions
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index bfcd0369ad..9b0b32299a 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -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.
-
- `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"`.
-
- `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.
+ 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
+ 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
+ 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
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index d20b6f5f58..560f4e5df2 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -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;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 19bf77a2dc..9c4a3f389a 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -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 {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 4c5f357451..cb83d6482c 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -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--;
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 61fe5e74eb..0008409731 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -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();
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 767936ecee..3e0a5907be 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -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
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 697ddc1887..d49d2f0316 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -22,8 +22,129 @@ describe('ui/ext_messages', function()
[6] = {bold = true, reverse = true},
})
end)
+ after_each(function()
+ os.remove('Xtest')
+ end)
+
+ 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('supports :echoerr', function()
+ 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=[[
^ |
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 983a2f3d40..53b6642207 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -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
+ -- 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)..'\nHint: full state of "'..k..'":\n '..inspect(extstate[k]))
end
end
- if expected.mode ~= nil then
- eq(expected.mode, self.mode, "mode")
- end
- end)
- if not status then
- return tostring(res)
end
end, expected)
end