aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-06-11 23:06:05 +0200
committerGitHub <noreply@github.com>2022-06-11 23:06:05 +0200
commit502f03fc064d1eb427d214521d5cb9f5425a15b4 (patch)
tree5f235062bb5f0d0729787ad263b292f40f51f355
parentc87a5ebbc31c56867f9d6f6d27bb8b7ddecc837e (diff)
parentf4121c52b95d4b79c0de95412c8447614a2f8960 (diff)
downloadrneovim-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.c4
-rw-r--r--src/nvim/api/vim.c21
-rw-r--r--src/nvim/message.c107
-rw-r--r--src/nvim/message.h1
-rw-r--r--test/functional/ui/messages_spec.lua106
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()