Merge #32013 from luukvbaal/shellkind

This commit is contained in:
Justin M. Keyes
2025-01-15 02:23:44 -08:00
committed by GitHub
7 changed files with 77 additions and 20 deletions

View File

@@ -96,7 +96,7 @@ EVENTS
• `msg_show`: • `msg_show`:
• `history` argument indicating if the message was added to the history. • `history` argument indicating if the message was added to the history.
• new message kinds: "bufwrite", "completion", "list_cmd", "lua_print", • new message kinds: "bufwrite", "completion", "list_cmd", "lua_print",
"search_cmd", "undo", "verbose", wildlist". "search_cmd", "shell_out/err/ret", "undo", "verbose", wildlist".
HIGHLIGHTS HIGHLIGHTS

View File

@@ -805,6 +805,9 @@ must handle.
"quickfix" Quickfix navigation message "quickfix" Quickfix navigation message
"search_cmd" Entered search command "search_cmd" Entered search command
"search_count" Search count message ("S" flag of 'shortmess') "search_count" Search count message ("S" flag of 'shortmess')
"shell_err" |:!cmd| shell stderr output
"shell_out" |:!cmd| shell stdout output
"shell_ret" |:!cmd| shell return code
"undo" |:undo| and |:redo| message "undo" |:undo| and |:redo| message
"verbose" 'verbose' message "verbose" 'verbose' message
"wildlist" 'wildmode' "list" message "wildlist" 'wildmode' "list" message

View File

@@ -772,7 +772,8 @@ void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err)
verbose_enter(); verbose_enter();
} }
msg_multihl(hl_msg, opts->err ? "echoerr" : history ? "echomsg" : "echo", history, opts->err); char *kind = opts->verbose ? NULL : opts->err ? "echoerr" : history ? "echomsg" : "echo";
msg_multihl(hl_msg, kind, history, opts->err);
if (opts->verbose) { if (opts->verbose) {
verbose_leave(); verbose_leave();

View File

@@ -21,8 +21,8 @@ static inline Proc proc_init(Loop *loop, ProcType type, void *data)
.argv = NULL, .argv = NULL,
.exepath = NULL, .exepath = NULL,
.in = { .closed = false }, .in = { .closed = false },
.out = { .s.closed = false }, .out = { .s.closed = false, .s.fd = STDOUT_FILENO },
.err = { .s.closed = false }, .err = { .s.closed = false, .s.fd = STDERR_FILENO },
.cb = NULL, .cb = NULL,
.closed = false, .closed = false,
.internal_close_cb = NULL, .internal_close_cb = NULL,

View File

@@ -296,6 +296,12 @@ void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_
// Avoid starting a new message for each chunk and adding message to history in msg_keep(). // Avoid starting a new message for each chunk and adding message to history in msg_keep().
static bool is_multihl = false; static bool is_multihl = false;
/// Print message chunks, each with their own highlight ID.
///
/// @param hl_msg Message chunks
/// @param kind Message kind (can be NULL to avoid setting kind)
/// @param history Whether to add message to history
/// @param err Whether to print message as an error
void msg_multihl(HlMessage hl_msg, const char *kind, bool history, bool err) void msg_multihl(HlMessage hl_msg, const char *kind, bool history, bool err)
{ {
no_wait_return++; no_wait_return++;
@@ -303,7 +309,9 @@ void msg_multihl(HlMessage hl_msg, const char *kind, bool history, bool err)
msg_clr_eos(); msg_clr_eos();
bool need_clear = false; bool need_clear = false;
msg_ext_history = history; msg_ext_history = history;
msg_ext_set_kind(kind); if (kind != NULL) {
msg_ext_set_kind(kind);
}
is_multihl = true; is_multihl = true;
for (uint32_t i = 0; i < kv_size(hl_msg); i++) { for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i); HlMessageChunk chunk = kv_A(hl_msg, i);
@@ -312,7 +320,7 @@ void msg_multihl(HlMessage hl_msg, const char *kind, bool history, bool err)
} else { } else {
msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear); msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear);
} }
assert(!ui_has(kUIMessages) || msg_ext_kind == kind); assert(!ui_has(kUIMessages) || kind == NULL || msg_ext_kind == kind);
} }
if (history && kv_size(hl_msg)) { if (history && kv_size(hl_msg)) {
add_msg_hist_multihl(NULL, 0, 0, true, hl_msg); add_msg_hist_multihl(NULL, 0, 0, true, hl_msg);

View File

@@ -700,6 +700,7 @@ int os_call_shell(char *cmd, int opts, char *extra_args)
} }
if (!emsg_silent && exitcode != 0 && !(opts & kShellOptSilent)) { if (!emsg_silent && exitcode != 0 && !(opts & kShellOptSilent)) {
msg_ext_set_kind("shell_ret");
msg_puts(_("\nshell returned ")); msg_puts(_("\nshell returned "));
msg_outnum(exitcode); msg_outnum(exitcode);
msg_putchar('\n'); msg_putchar('\n');
@@ -1067,7 +1068,7 @@ static void out_data_ring(const char *output, size_t size)
} }
if (output == NULL && size == SIZE_MAX) { // Print mode if (output == NULL && size == SIZE_MAX) { // Print mode
out_data_append_to_screen(last_skipped, &last_skipped_len, true); out_data_append_to_screen(last_skipped, &last_skipped_len, STDOUT_FILENO, true);
return; return;
} }
@@ -1095,14 +1096,15 @@ static void out_data_ring(const char *output, size_t size)
/// @param output Data to append to screen lines. /// @param output Data to append to screen lines.
/// @param count Size of data. /// @param count Size of data.
/// @param eof If true, there will be no more data output. /// @param eof If true, there will be no more data output.
static void out_data_append_to_screen(const char *output, size_t *count, bool eof) static void out_data_append_to_screen(const char *output, size_t *count, int fd, bool eof)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
const char *p = output; const char *p = output;
const char *end = output + *count; const char *end = output + *count;
msg_ext_set_kind(fd == STDERR_FILENO ? "shell_err" : "shell_out");
while (p < end) { while (p < end) {
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) { if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
msg_putchar_hl((uint8_t)(*p), 0); msg_putchar_hl((uint8_t)(*p), fd == STDERR_FILENO ? HLF_E : 0);
p++; p++;
} else { } else {
// Note: this is not 100% precise: // Note: this is not 100% precise:
@@ -1118,7 +1120,7 @@ static void out_data_append_to_screen(const char *output, size_t *count, bool eo
goto end; goto end;
} }
msg_outtrans_len(p, i, 0, false); msg_outtrans_len(p, i, fd == STDERR_FILENO ? HLF_E : 0, false);
p += i; p += i;
} }
} }
@@ -1133,7 +1135,7 @@ static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *
// Save the skipped output. If it is the final chunk, we display it later. // Save the skipped output. If it is the final chunk, we display it later.
out_data_ring(ptr, count); out_data_ring(ptr, count);
} else if (count > 0) { } else if (count > 0) {
out_data_append_to_screen(ptr, &count, eof); out_data_append_to_screen(ptr, &count, stream->s.fd, eof);
} }
return count; return count;

View File

@@ -319,9 +319,7 @@ describe('ui/ext_messages', function()
-- kind=echoerr for nvim_echo() err -- kind=echoerr for nvim_echo() err
feed(':call nvim_echo([["Error"], ["Message", "Special"]], 1, #{ err:1 })<CR>') feed(':call nvim_echo([["Error"], ["Message", "Special"]], 1, #{ err:1 })<CR>')
screen:expect({ screen:expect({
cmdline = { { cmdline = { { abort = false } },
abort = false,
} },
messages = { messages = {
{ {
content = { { 'Error', 9, 6 }, { 'Message', 16, 99 } }, content = { { 'Error', 9, 6 }, { 'Message', 16, 99 } },
@@ -331,11 +329,23 @@ describe('ui/ext_messages', function()
}, },
}) })
-- kind=verbose for nvim_echo() verbose
feed(':call nvim_echo([["Verbose Message"]], 1, #{ verbose:1 })<CR>')
screen:expect({
cmdline = { { abort = false } },
messages = {
{
content = { { 'Verbose Message' } },
history = true,
kind = 'verbose',
},
},
})
-- kind=verbose for :verbose messages
feed(':1verbose filter Diff[AC] hi<CR>') feed(':1verbose filter Diff[AC] hi<CR>')
screen:expect({ screen:expect({
cmdline = { { cmdline = { { abort = false } },
abort = false,
} },
messages = { messages = {
{ {
content = { content = {
@@ -380,6 +390,41 @@ describe('ui/ext_messages', function()
}, },
}, },
}) })
-- kind=shell for :!cmd messages
local cmd = t.is_os('win') and 'echo stdout& echo stderr>&2& exit 3'
or '{ echo stdout; echo stderr >&2; exit 3; }'
feed(('<CR>:!%s<CR>'):format(cmd))
screen:expect({
cmdline = { { abort = false } },
messages = {
{
content = { { (':!%s\r\n[No write since last change]\n'):format(cmd) } },
history = false,
kind = '',
},
{
content = { { ('stdout%s\n'):format(t.is_os('win') and '\r' or '') } },
history = false,
kind = 'shell_out',
},
{
content = { { ('stderr%s\n'):format(t.is_os('win') and '\r' or ''), 9, 6 } },
history = false,
kind = 'shell_err',
},
{
content = { { '\nshell returned 3\n\n' } },
history = false,
kind = 'shell_ret',
},
{
content = { { 'Press ENTER or type command to continue', 6, 18 } },
history = false,
kind = 'return_prompt',
},
},
})
end) end)
it(':echoerr', function() it(':echoerr', function()
@@ -1088,9 +1133,7 @@ describe('ui/ext_messages', function()
^ | ^ |
{1:~ }|*4 {1:~ }|*4
]], ]],
cmdline = { { cmdline = { { abort = false } },
abort = false,
} },
}) })
eq(0, eval('&cmdheight')) eq(0, eval('&cmdheight'))
end) end)