mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(messages): add color when showing nvim_echo in :messages history
This commit is contained in:
parent
c87a5ebbc3
commit
f4121c52b9
@ -1344,8 +1344,8 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
|
|||||||
return hl_msg;
|
return hl_msg;
|
||||||
|
|
||||||
free_exit:
|
free_exit:
|
||||||
clear_hl_msg(&hl_msg);
|
hl_msg_free(hl_msg);
|
||||||
return hl_msg;
|
return (HlMessage)KV_INITIAL_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err)
|
bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err)
|
||||||
|
@ -942,26 +942,15 @@ void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
no_wait_return++;
|
msg_multiattr(hl_msg, history ? "echomsg" : "echo", history);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (history) {
|
if (history) {
|
||||||
msg_ext_set_kind("echomsg");
|
// history takes ownership
|
||||||
add_hl_msg_hist(hl_msg);
|
return;
|
||||||
} else {
|
|
||||||
msg_ext_set_kind("echo");
|
|
||||||
}
|
}
|
||||||
no_wait_return--;
|
|
||||||
msg_end();
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
clear_hl_msg(&hl_msg);
|
hl_msg_free(hl_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a message to the Vim output buffer. Does not append "\n", the
|
/// Writes a message to the Vim output buffer. Does not append "\n", the
|
||||||
|
@ -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
|
/// @param keep set keep_msg if it doesn't scroll
|
||||||
bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
|
bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
@ -889,44 +908,34 @@ char_u *msg_may_trunc(bool force, char_u *s)
|
|||||||
return 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++) {
|
for (size_t i = 0; i < kv_size(hl_msg); i++) {
|
||||||
xfree(kv_A(*hl_msg, i).text.data);
|
xfree(kv_A(hl_msg, i).text.data);
|
||||||
}
|
}
|
||||||
kv_destroy(*hl_msg);
|
kv_destroy(hl_msg);
|
||||||
*hl_msg = (HlMessage)KV_INITIAL_VALUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LINE_BUFFER_SIZE 4096
|
#define LINE_BUFFER_SIZE 4096
|
||||||
|
|
||||||
void add_hl_msg_hist(HlMessage hl_msg)
|
void add_hl_msg_hist(HlMessage hl_msg)
|
||||||
{
|
{
|
||||||
// TODO(notomo): support multi highlighted message history
|
if (kv_size(hl_msg)) {
|
||||||
size_t pos = 0;
|
add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param[in] len Length of s or -1.
|
/// @param[in] len Length of s or -1.
|
||||||
static void add_msg_hist(const char *s, int len, int attr, bool multiline)
|
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) {
|
if (msg_hist_off || msg_silent != 0) {
|
||||||
|
hl_msg_free(multiattr);
|
||||||
return;
|
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
|
// allocate an entry and add the message at the end of the history
|
||||||
struct msg_hist *p = xmalloc(sizeof(struct msg_hist));
|
struct msg_hist *p = xmalloc(sizeof(struct msg_hist));
|
||||||
if (len < 0) {
|
if (s) {
|
||||||
len = (int)STRLEN(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;
|
||||||
}
|
}
|
||||||
// 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);
|
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
p->attr = attr;
|
p->attr = attr;
|
||||||
p->multiline = multiline;
|
p->multiline = multiline;
|
||||||
|
p->multiattr = multiattr;
|
||||||
p->kind = msg_ext_kind;
|
p->kind = msg_ext_kind;
|
||||||
if (last_msg_hist != NULL) {
|
if (last_msg_hist != NULL) {
|
||||||
last_msg_hist->next = p;
|
last_msg_hist->next = p;
|
||||||
@ -980,6 +994,7 @@ int delete_first_msg(void)
|
|||||||
last_msg_hist = NULL;
|
last_msg_hist = NULL;
|
||||||
}
|
}
|
||||||
xfree(p->msg);
|
xfree(p->msg);
|
||||||
|
hl_msg_free(p->multiattr);
|
||||||
xfree(p);
|
xfree(p);
|
||||||
--msg_hist_len;
|
--msg_hist_len;
|
||||||
return OK;
|
return OK;
|
||||||
@ -1028,14 +1043,24 @@ void ex_messages(void *const eap_p)
|
|||||||
}
|
}
|
||||||
Array entries = ARRAY_DICT_INIT;
|
Array entries = ARRAY_DICT_INIT;
|
||||||
for (; p != NULL; p = p->next) {
|
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;
|
Array entry = ARRAY_DICT_INIT;
|
||||||
ADD(entry, STRING_OBJ(cstr_to_string(p->kind)));
|
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;
|
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(entry, ARRAY_OBJ(content));
|
||||||
ADD(entries, ARRAY_OBJ(entry));
|
ADD(entries, ARRAY_OBJ(entry));
|
||||||
}
|
}
|
||||||
@ -1046,7 +1071,9 @@ void ex_messages(void *const eap_p)
|
|||||||
} else {
|
} else {
|
||||||
msg_hist_off = true;
|
msg_hist_off = true;
|
||||||
for (; p != NULL && !got_int; p = p->next) {
|
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);
|
msg_attr_keep((char *)p->msg, p->attr, false, p->multiline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ typedef struct msg_hist {
|
|||||||
const char *kind; ///< Message kind (for msg_ext)
|
const char *kind; ///< Message kind (for msg_ext)
|
||||||
int attr; ///< Message highlighting.
|
int attr; ///< Message highlighting.
|
||||||
bool multiline; ///< Multiline message.
|
bool multiline; ///< Multiline message.
|
||||||
|
HlMessage multiattr; ///< multiattr message.
|
||||||
} MessageHistoryEntry;
|
} MessageHistoryEntry;
|
||||||
|
|
||||||
/// First message
|
/// First message
|
||||||
|
@ -31,6 +31,7 @@ describe('ui/ext_messages', function()
|
|||||||
[7] = {background = Screen.colors.Yellow},
|
[7] = {background = Screen.colors.Yellow},
|
||||||
[8] = {foreground = Screen.colors.Red},
|
[8] = {foreground = Screen.colors.Red},
|
||||||
[9] = {special = Screen.colors.Red, undercurl = true},
|
[9] = {special = Screen.colors.Red, undercurl = true},
|
||||||
|
[10] = {foreground = Screen.colors.Brown};
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
after_each(function()
|
after_each(function()
|
||||||
@ -858,9 +859,53 @@ stack traceback:
|
|||||||
{1:~ }|
|
{1:~ }|
|
||||||
{1:~ }|
|
{1:~ }|
|
||||||
]]}
|
]]}
|
||||||
|
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
describe('ui/builtin messages', function()
|
describe('ui/builtin messages', function()
|
||||||
@ -869,17 +914,19 @@ describe('ui/builtin messages', function()
|
|||||||
clear()
|
clear()
|
||||||
screen = Screen.new(60, 7)
|
screen = Screen.new(60, 7)
|
||||||
screen:attach({rgb=true, ext_popupmenu=true})
|
screen:attach({rgb=true, ext_popupmenu=true})
|
||||||
screen:set_default_attr_ids({
|
screen:set_default_attr_ids {
|
||||||
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
[1] = {bold = true, foreground = Screen.colors.Blue1};
|
||||||
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
|
||||||
[3] = {bold = true, reverse = true},
|
[3] = {bold = true, reverse = true};
|
||||||
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
|
[4] = {bold = true, foreground = Screen.colors.SeaGreen4};
|
||||||
[5] = {foreground = Screen.colors.Blue1},
|
[5] = {foreground = Screen.colors.Blue1};
|
||||||
[6] = {bold = true, foreground = Screen.colors.Magenta},
|
[6] = {bold = true, foreground = Screen.colors.Magenta};
|
||||||
[7] = {background = Screen.colors.Grey20},
|
[7] = {background = Screen.colors.Grey20};
|
||||||
[8] = {reverse = true},
|
[8] = {reverse = true};
|
||||||
[9] = {background = Screen.colors.LightRed}
|
[9] = {background = Screen.colors.LightRed};
|
||||||
})
|
[10] = {background = Screen.colors.Yellow};
|
||||||
|
[11] = {foreground = Screen.colors.Brown};
|
||||||
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('supports multiline messages from rpc', function()
|
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}^ |
|
{4:Press ENTER or type command to continue}^ |
|
||||||
]]}
|
]]}
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
describe('ui/ext_messages', function()
|
describe('ui/ext_messages', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user