Browse files

Merge pull request #7466 from bfredl/ext_messages

ui: implement ext_messages to externalize all messages in msg area
  • Loading branch information...
bfredl committed Feb 10, 2019
2 parents 3ff1228 + 51fc543 commit b3ce0019a78ee85d44513344ce52d9da43077231
@@ -32,6 +32,7 @@ a dictionary with these (optional) keys:
`ext_tabline` Externalize the tabline. |ui-tabline|
`ext_cmdline` Externalize the cmdline. |ui-cmdline|
`ext_wildmenu` Externalize the wildmenu. |ui-wildmenu|
`ext_messages` Externalize messages. |ui-messages|
`ext_linegrid` Use new revision of the grid events. |ui-linegrid|
`ext_multigrid` Use per-window grid based events. |ui-multigrid|
`ext_hlstate` Use detailed highlight state. |ui-hlstate|
@@ -572,7 +573,7 @@ Only sent if `ext_tabline` option is set in |ui-options|
Cmdline Events *ui-cmdline*

Only sent if `ext_cmdline` option is set in |ui-options|
Only sent if `ext_cmdline` option is set in |ui-options|.

["cmdline_show", content, pos, firstc, prompt, indent, level]
content: List of [attrs, string]
@@ -644,5 +645,70 @@ Only sent if `ext_wildmenu` option is set in |ui-options|
Hide the wildmenu.

Message Events *ui-messages*

Only sent if `ext_messages` option is set in |ui-options|. This option implies
`ext_linegrid` and `ext_cmdline` also being set. |ui-linegrid| and |ui-cmdline| events
will thus also be sent.

This extension allows the UI to control the display of messages that otherwise
would have been displayed in the message/cmdline area in the bottom of the

Activating this extension means that Nvim will allocate no screen space for
the cmdline or messages, and 'cmdheight' will be set to zero. Attempting to
change 'cmdheight' will silently be ignored. |ui-cmdline| events will be used
to represent the state 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.

Clear all messages currently displayed by "msg_show". (Messages sent
by other "msg_" events below will not be affected).

["msg_showmode", content]
Shows 'showmode' and |recording| messages. `content` has the same
format as in "msg_show". This event is sent with empty `content` to
hide the last message.

["msg_showcmd", content]
Shows 'showcmd' messages. `content` has the same format as in "msg_show".
This event is sent with empty `content` to hide the last message.

["msg_ruler", content]
Used to display 'ruler' when there is no space for the ruler in a
statusline. `content` has the same format as in "msg_show". This event is
sent with empty `content` to hide the last message.

["msg_history_show", entries]
Sent when |:messages| command is invoked. History is sent as a list of
entries, where each entry is a `[kind, content]` tuple.

@@ -712,6 +712,12 @@ String cbuf_to_string(const char *buf, size_t size)

String cstrn_to_string(const char *str, size_t maxsize)
return cbuf_to_string(str, strnlen(str, maxsize));

/// Creates a String using the given C string. Unlike
/// cstr_to_string this function DOES NOT copy the C string.
@@ -726,6 +732,18 @@ String cstr_as_string(char *str) FUNC_ATTR_PURE
return (String){ .data = str, .size = strlen(str) };

/// Return the owned memory of a ga as a String
/// Reinitializes the ga to a valid empty state.
String ga_take_string(garray_T *ga)
String str = { .data = (char *)ga->ga_data, .size = (size_t)ga->ga_len };
ga->ga_data = NULL;
ga->ga_len = 0;
ga->ga_maxlen = 0;
return str;

/// Collects `n` buffer lines into array `l`, optionally replacing newlines
/// with NUL.
@@ -132,6 +132,13 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->ui_ext[kUILinegrid] = true;

if (ui->ui_ext[kUIMessages]) {
// This uses attribute indicies, so ext_linegrid is needed.
ui->ui_ext[kUILinegrid] = true;
// Cmdline uses the messages area, so it should be externalized too.
ui->ui_ext[kUICmdline] = true;

UIData *data = xmalloc(sizeof(UIData));
data->channel_id = channel_id;
data->buffer = (Array)ARRAY_DICT_INIT;
@@ -141,4 +141,17 @@ void wildmenu_select(Integer selected)
void wildmenu_hide(void)

void msg_show(String kind, Array content, Boolean replace_last)
void msg_clear(void)
void msg_showcmd(Array content)
void msg_showmode(Array content)
void msg_ruler(Array content)
void msg_history_show(Array entries)
msg_puts_attr(" ", echo_attr);
char *tofree = encode_tv2echo(&rettv, NULL);
msg_multiline_attr(tofree, echo_attr);
if (*tofree != NUL) {
msg_multiline_attr(tofree, echo_attr);

if (eap->cmdidx == CMD_echomsg) {
MSG_ATTR(ga.ga_data, echo_attr);
} else if (eap->cmdidx == CMD_echoerr) {
/* We don't want to abort following commands, restore did_emsg. */
save_did_emsg = did_emsg;
EMSG((char_u *)ga.ga_data);
if (!force_abort)
did_emsg = save_did_emsg;
@@ -308,6 +308,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
redrawcmdprompt(); // draw prompt or indent
if (!msg_scroll) {
s->xpc.xp_context = EXPAND_NOTHING;
s->xpc.xp_backslash = XP_BS_NONE;
@@ -496,6 +499,12 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)

if (ui_has(kUICmdline)) {
if (msg_ext_is_visible()) {
msg_ext_did_cmdline = true;
if (must_redraw < VALID) {
must_redraw = VALID;

@@ -3613,7 +3622,7 @@ nextwild (
return FAIL;

if (!ui_has(kUIWildmenu)) {
if (!(ui_has(kUICmdline) || ui_has(kUIWildmenu))) {
MSG_PUTS("..."); // show that we are busy
@@ -18,6 +18,7 @@ typedef struct growarray {
} garray_T;

#define GA_EMPTY_INIT_VALUE { 0, 0, 0, 1, NULL }
#define GA_INIT(itemsize, growsize) { 0, 0, (itemsize), (growsize), NULL }

#define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0)

Oops, something went wrong.

0 comments on commit b3ce001

Please sign in to comment.