mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
api: nvim_echo
This commit is contained in:
parent
1785ac3e37
commit
8e86f5e460
@ -663,6 +663,17 @@ nvim_del_var({name}) *nvim_del_var()*
|
||||
Parameters: ~
|
||||
{name} Variable name
|
||||
|
||||
nvim_echo({chunks}, {history}, {opts}) *nvim_echo()*
|
||||
Echo a message.
|
||||
|
||||
Parameters: ~
|
||||
{chunks} A list of [text, hl_group] arrays, each
|
||||
representing a text chunk with specified
|
||||
highlight. `hl_group` element can be omitted
|
||||
for no highlight.
|
||||
{history} if true, add to |message-history|.
|
||||
{opts} Optional parameters. Reserved for future use.
|
||||
|
||||
nvim_err_write({str}) *nvim_err_write()*
|
||||
Writes a message to the Vim error buffer. Does not append
|
||||
"\n", the message is buffered (won't display) until a linefeed
|
||||
|
@ -1645,6 +1645,43 @@ bool api_object_to_bool(Object obj, const char *what,
|
||||
}
|
||||
}
|
||||
|
||||
HlMessage parse_hl_msg(Array chunks, Error *err)
|
||||
{
|
||||
HlMessage hl_msg = KV_INITIAL_VALUE;
|
||||
for (size_t i = 0; i < chunks.size; i++) {
|
||||
if (chunks.items[i].type != kObjectTypeArray) {
|
||||
api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
|
||||
goto free_exit;
|
||||
}
|
||||
Array chunk = chunks.items[i].data.array;
|
||||
if (chunk.size == 0 || chunk.size > 2
|
||||
|| chunk.items[0].type != kObjectTypeString
|
||||
|| (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Chunk is not an array with one or two strings");
|
||||
goto free_exit;
|
||||
}
|
||||
|
||||
String str = copy_string(chunk.items[0].data.string);
|
||||
|
||||
int attr = 0;
|
||||
if (chunk.size == 2) {
|
||||
String hl = chunk.items[1].data.string;
|
||||
if (hl.size > 0) {
|
||||
int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
|
||||
attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
|
||||
}
|
||||
}
|
||||
kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr }));
|
||||
}
|
||||
|
||||
return hl_msg;
|
||||
|
||||
free_exit:
|
||||
clear_hl_msg(&hl_msg);
|
||||
return hl_msg;
|
||||
}
|
||||
|
||||
const char *describe_ns(NS ns_id)
|
||||
{
|
||||
String name;
|
||||
|
@ -990,6 +990,47 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
|
||||
set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
|
||||
}
|
||||
|
||||
/// Echo a message.
|
||||
///
|
||||
/// @param chunks A list of [text, hl_group] arrays, each representing a
|
||||
/// text chunk with specified highlight. `hl_group` element
|
||||
/// can be omitted for no highlight.
|
||||
/// @param history if true, add to |message-history|.
|
||||
/// @param opts Optional parameters. Reserved for future use.
|
||||
void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err)
|
||||
FUNC_API_SINCE(7)
|
||||
{
|
||||
HlMessage hl_msg = parse_hl_msg(chunks, err);
|
||||
if (ERROR_SET(err)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (opts.size > 0) {
|
||||
api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
|
||||
goto error;
|
||||
}
|
||||
|
||||
no_wait_return++;
|
||||
bool need_clear = true;
|
||||
msg_start();
|
||||
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,
|
||||
false, &need_clear);
|
||||
}
|
||||
if (history) {
|
||||
msg_ext_set_kind("echomsg");
|
||||
add_hl_msg_hist(hl_msg);
|
||||
} else {
|
||||
msg_ext_set_kind("echo");
|
||||
}
|
||||
no_wait_return--;
|
||||
msg_end();
|
||||
|
||||
error:
|
||||
clear_hl_msg(&hl_msg);
|
||||
}
|
||||
|
||||
/// Writes a message to the Vim output buffer. Does not append "\n", the
|
||||
/// message is buffered (won't display) until a linefeed is written.
|
||||
///
|
||||
|
@ -890,6 +890,40 @@ char_u *msg_may_trunc(int force, char_u *s)
|
||||
return s;
|
||||
}
|
||||
|
||||
void clear_hl_msg(HlMessage *hl_msg)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
/// @param[in] len Length of s or -1.
|
||||
static void add_msg_hist(const char *s, int len, int attr, bool multiline)
|
||||
{
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "nvim/macros.h"
|
||||
#include "nvim/types.h"
|
||||
#include "nvim/grid_defs.h"
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/lib/kvec.h"
|
||||
|
||||
/*
|
||||
* Types of dialogs passed to do_dialog().
|
||||
@ -75,6 +77,13 @@
|
||||
/// Like #MSG_PUTS_ATTR, but if middle part of long messages will be replaced
|
||||
#define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a))
|
||||
|
||||
typedef struct {
|
||||
String text;
|
||||
int attr;
|
||||
} HlMessageChunk;
|
||||
|
||||
typedef kvec_t(HlMessageChunk) HlMessage;
|
||||
|
||||
/// Message history for `:messages`
|
||||
typedef struct msg_hist {
|
||||
struct msg_hist *next; ///< Next message.
|
||||
|
@ -2002,4 +2002,63 @@ describe('API', function()
|
||||
}, meths.get_option_info'showcmd')
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_echo', function()
|
||||
local screen
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
screen = Screen.new(40, 8)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
[0] = {bold=true, foreground=Screen.colors.Blue},
|
||||
[1] = {bold = true, foreground = Screen.colors.SeaGreen},
|
||||
[2] = {bold = true, reverse = true},
|
||||
[3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement
|
||||
[4] = {foreground = Screen.colors.SlateBlue}, -- Special
|
||||
})
|
||||
command('highlight Statement gui=bold guifg=Brown')
|
||||
command('highlight Special guifg=SlateBlue')
|
||||
end)
|
||||
|
||||
it('can show highlighted line', function()
|
||||
nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {})
|
||||
screen:expect{grid=[[
|
||||
^ |
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
msg_a{3:msg_b}{4:msg_c} |
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can show highlighted multiline', function()
|
||||
nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {})
|
||||
screen:expect{grid=[[
|
||||
|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{0:~ }|
|
||||
{2: }|
|
||||
{3:msg_a} |
|
||||
{3:msg_a}{4:msg_b} |
|
||||
{1:Press ENTER or type command to continue}^ |
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can save message history', function()
|
||||
nvim('command', 'set cmdheight=2') -- suppress Press ENTER
|
||||
nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {})
|
||||
eq("msg\nmsgmsg", meths.exec('messages', true))
|
||||
end)
|
||||
|
||||
it('can disable saving message history', function()
|
||||
nvim('command', 'set cmdheight=2') -- suppress Press ENTER
|
||||
nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {})
|
||||
eq("", meths.exec("messages", true))
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user