mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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--; | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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=[[ | ||||
|       ^                         | | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes