diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-06-11 23:06:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-11 23:06:05 +0200 |
commit | 502f03fc064d1eb427d214521d5cb9f5425a15b4 (patch) | |
tree | 5f235062bb5f0d0729787ad263b292f40f51f355 | |
parent | c87a5ebbc31c56867f9d6f6d27bb8b7ddecc837e (diff) | |
parent | f4121c52b95d4b79c0de95412c8447614a2f8960 (diff) | |
download | rneovim-502f03fc064d1eb427d214521d5cb9f5425a15b4.tar.gz rneovim-502f03fc064d1eb427d214521d5cb9f5425a15b4.tar.bz2 rneovim-502f03fc064d1eb427d214521d5cb9f5425a15b4.zip |
Merge pull request #18919 from bfredl/multiattr
fix(messages): add color when showing nvim_echo in :messages history
-rw-r--r-- | src/nvim/api/private/helpers.c | 4 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 21 | ||||
-rw-r--r-- | src/nvim/message.c | 107 | ||||
-rw-r--r-- | src/nvim/message.h | 1 | ||||
-rw-r--r-- | test/functional/ui/messages_spec.lua | 106 |
5 files changed, 169 insertions, 70 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 1ddaf63743..bdbbe9aa88 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1344,8 +1344,8 @@ HlMessage parse_hl_msg(Array chunks, Error *err) return hl_msg; free_exit: - clear_hl_msg(&hl_msg); - return hl_msg; + hl_msg_free(hl_msg); + return (HlMessage)KV_INITIAL_VALUE; } bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1e44250ec3..5f7162cdd6 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -942,26 +942,15 @@ void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err) goto error; } - no_wait_return++; - msg_start(); - msg_clr_eos(); - bool need_clear = false; - for (uint32_t i = 0; i < kv_size(hl_msg); i++) { - HlMessageChunk chunk = kv_A(hl_msg, i); - msg_multiline_attr((const char *)chunk.text.data, chunk.attr, - true, &need_clear); - } + msg_multiattr(hl_msg, history ? "echomsg" : "echo", history); + if (history) { - msg_ext_set_kind("echomsg"); - add_hl_msg_hist(hl_msg); - } else { - msg_ext_set_kind("echo"); + // history takes ownership + return; } - no_wait_return--; - msg_end(); error: - clear_hl_msg(&hl_msg); + hl_msg_free(hl_msg); } /// Writes a message to the Vim output buffer. Does not append "\n", the diff --git a/src/nvim/message.c b/src/nvim/message.c index 8085b90ddd..f250f6de58 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -264,6 +264,25 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea } } +void msg_multiattr(HlMessage hl_msg, const char *kind, bool history) +{ + no_wait_return++; + msg_start(); + msg_clr_eos(); + bool need_clear = false; + for (uint32_t i = 0; i < kv_size(hl_msg); i++) { + HlMessageChunk chunk = kv_A(hl_msg, i); + msg_multiline_attr((const char *)chunk.text.data, chunk.attr, + true, &need_clear); + } + msg_ext_set_kind(kind); + if (history && kv_size(hl_msg)) { + add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg); + } + no_wait_return--; + msg_end(); +} + /// @param keep set keep_msg if it doesn't scroll bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline) FUNC_ATTR_NONNULL_ALL @@ -889,44 +908,34 @@ char_u *msg_may_trunc(bool force, char_u *s) return s; } -void clear_hl_msg(HlMessage *hl_msg) +void hl_msg_free(HlMessage hl_msg) { - for (size_t i = 0; i < kv_size(*hl_msg); i++) { - xfree(kv_A(*hl_msg, i).text.data); + for (size_t i = 0; i < kv_size(hl_msg); i++) { + xfree(kv_A(hl_msg, i).text.data); } - kv_destroy(*hl_msg); - *hl_msg = (HlMessage)KV_INITIAL_VALUE; + kv_destroy(hl_msg); } #define LINE_BUFFER_SIZE 4096 void add_hl_msg_hist(HlMessage hl_msg) { - // TODO(notomo): support multi highlighted message history - size_t pos = 0; - char buf[LINE_BUFFER_SIZE]; - for (uint32_t i = 0; i < kv_size(hl_msg); i++) { - HlMessageChunk chunk = kv_A(hl_msg, i); - for (uint32_t j = 0; j < chunk.text.size; j++) { - if (pos == LINE_BUFFER_SIZE - 1) { - buf[pos] = NUL; - add_msg_hist((const char *)buf, -1, MSG_HIST, true); - pos = 0; - continue; - } - buf[pos++] = chunk.text.data[j]; - } - } - if (pos != 0) { - buf[pos] = NUL; - add_msg_hist((const char *)buf, -1, MSG_HIST, true); + if (kv_size(hl_msg)) { + add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg); } } /// @param[in] len Length of s or -1. static void add_msg_hist(const char *s, int len, int attr, bool multiline) { + add_msg_hist_multiattr(s, len, attr, multiline, (HlMessage)KV_INITIAL_VALUE); +} + +static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multiline, + HlMessage multiattr) +{ if (msg_hist_off || msg_silent != 0) { + hl_msg_free(multiattr); return; } @@ -937,21 +946,26 @@ static void add_msg_hist(const char *s, int len, int attr, bool multiline) // allocate an entry and add the message at the end of the history struct msg_hist *p = xmalloc(sizeof(struct msg_hist)); - if (len < 0) { - len = (int)STRLEN(s); - } - // remove leading and trailing newlines - while (len > 0 && *s == '\n') { - ++s; - --len; - } - while (len > 0 && s[len - 1] == '\n') { - len--; + if (s) { + if (len < 0) { + len = (int)STRLEN(s); + } + // remove leading and trailing newlines + while (len > 0 && *s == '\n') { + s++; + len--; + } + while (len > 0 && s[len - 1] == '\n') { + len--; + } + p->msg = (char_u *)xmemdupz(s, (size_t)len); + } else { + p->msg = NULL; } - p->msg = (char_u *)xmemdupz(s, (size_t)len); p->next = NULL; p->attr = attr; p->multiline = multiline; + p->multiattr = multiattr; p->kind = msg_ext_kind; if (last_msg_hist != NULL) { last_msg_hist->next = p; @@ -980,6 +994,7 @@ int delete_first_msg(void) last_msg_hist = NULL; } xfree(p->msg); + hl_msg_free(p->multiattr); xfree(p); --msg_hist_len; return OK; @@ -1028,14 +1043,24 @@ void ex_messages(void *const eap_p) } Array entries = ARRAY_DICT_INIT; for (; p != NULL; p = p->next) { - if (p->msg != NULL && p->msg[0] != NUL) { + if (kv_size(p->multiattr) || (p->msg && p->msg[0])) { Array entry = ARRAY_DICT_INIT; ADD(entry, STRING_OBJ(cstr_to_string(p->kind))); - Array content_entry = ARRAY_DICT_INIT; - ADD(content_entry, INTEGER_OBJ(p->attr)); - ADD(content_entry, STRING_OBJ(cstr_to_string((char *)(p->msg)))); Array content = ARRAY_DICT_INIT; - ADD(content, ARRAY_OBJ(content_entry)); + if (kv_size(p->multiattr)) { + for (uint32_t i = 0; i < kv_size(p->multiattr); i++) { + HlMessageChunk chunk = kv_A(p->multiattr, i); + Array content_entry = ARRAY_DICT_INIT; + ADD(content_entry, INTEGER_OBJ(chunk.attr)); + ADD(content_entry, STRING_OBJ(copy_string(chunk.text))); + ADD(content, ARRAY_OBJ(content_entry)); + } + } else if (p->msg && p->msg[0]) { + Array content_entry = ARRAY_DICT_INIT; + ADD(content_entry, INTEGER_OBJ(p->attr)); + ADD(content_entry, STRING_OBJ(cstr_to_string((char *)(p->msg)))); + ADD(content, ARRAY_OBJ(content_entry)); + } ADD(entry, ARRAY_OBJ(content)); ADD(entries, ARRAY_OBJ(entry)); } @@ -1046,7 +1071,9 @@ void ex_messages(void *const eap_p) } else { msg_hist_off = true; for (; p != NULL && !got_int; p = p->next) { - if (p->msg != NULL) { + if (kv_size(p->multiattr)) { + msg_multiattr(p->multiattr, p->kind, false); + } else if (p->msg != NULL) { msg_attr_keep((char *)p->msg, p->attr, false, p->multiline); } } diff --git a/src/nvim/message.h b/src/nvim/message.h index b402ee8b60..2de2890213 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -44,6 +44,7 @@ typedef struct msg_hist { const char *kind; ///< Message kind (for msg_ext) int attr; ///< Message highlighting. bool multiline; ///< Multiline message. + HlMessage multiattr; ///< multiattr message. } MessageHistoryEntry; /// First message diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index ee49ae7a09..a6cf96c87e 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -31,6 +31,7 @@ describe('ui/ext_messages', function() [7] = {background = Screen.colors.Yellow}, [8] = {foreground = Screen.colors.Red}, [9] = {special = Screen.colors.Red, undercurl = true}, + [10] = {foreground = Screen.colors.Brown}; }) end) after_each(function() @@ -858,9 +859,53 @@ stack traceback: {1:~ }| {1:~ }| ]]} - end) + it('supports nvim_echo messages with multiple attrs', function() + async_meths.echo({{'wow, ',"Search"}, {"such\n\nvery ", "ErrorMsg"}, {"color", "LineNr"}}, true, {}) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ + { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "" } + }} + + feed ':ls<cr>' + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ + { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "echomsg" } + }} + + feed ':messages<cr>' + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={ + { content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" } + }, msg_history={ + { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "echomsg" } + }} + + feed '<cr>' + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) end) describe('ui/builtin messages', function() @@ -869,17 +914,19 @@ describe('ui/builtin messages', function() clear() screen = Screen.new(60, 7) screen:attach({rgb=true, ext_popupmenu=true}) - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [3] = {bold = true, reverse = true}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [5] = {foreground = Screen.colors.Blue1}, - [6] = {bold = true, foreground = Screen.colors.Magenta}, - [7] = {background = Screen.colors.Grey20}, - [8] = {reverse = true}, - [9] = {background = Screen.colors.LightRed} - }) + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue1}; + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; + [3] = {bold = true, reverse = true}; + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}; + [5] = {foreground = Screen.colors.Blue1}; + [6] = {bold = true, foreground = Screen.colors.Magenta}; + [7] = {background = Screen.colors.Grey20}; + [8] = {reverse = true}; + [9] = {background = Screen.colors.LightRed}; + [10] = {background = Screen.colors.Yellow}; + [11] = {foreground = Screen.colors.Brown}; + } end) it('supports multiline messages from rpc', function() @@ -1115,6 +1162,41 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim {4:Press ENTER or type command to continue}^ | ]]} end) + + it('supports nvim_echo messages with multiple attrs', function() + async_meths.echo({{'wow, ',"Search"}, {"such\n\nvery ", "ErrorMsg"}, {"color", "LineNr"}}, true, {}) + screen:expect{grid=[[ + | + {1:~ }| + {3: }| + {10:wow, }{2:such} | + | + {2:very }{11:color} | + {4:Press ENTER or type command to continue}^ | + ]]} + + feed '<cr>' + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed ':messages<cr>' + screen:expect{grid=[[ + | + {1:~ }| + {3: }| + {10:wow, }{2:such} | + | + {2:very }{11:color} | + {4:Press ENTER or type command to continue}^ | + ]]} + end) end) describe('ui/ext_messages', function() |