mirror of
https://github.com/neovim/neovim.git
synced 2026-04-14 03:26:10 +00:00
fix(events): avoid recursive loop_uv_run() from vim.ui_attach() shell message
Problem: vim.ui_attach() msg_show callback runs the risk of a recursive
loop_uv_run() when trying to display a message from a shell
command stream.
Solution: Schedule the message callback on the fast_events queue.
(cherry picked from commit fa302037f9)
This commit is contained in:
committed by
github-actions[bot]
parent
c09e82d12a
commit
c3e52bb264
@@ -283,7 +283,7 @@ void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_
|
||||
if (check_int && got_int) {
|
||||
return;
|
||||
}
|
||||
if (*s == '\n' || *s == TAB || *s == '\r') {
|
||||
if (*s == '\n' || *s == TAB || *s == '\r' || *s == BELL) {
|
||||
// Print all chars before the delimiter
|
||||
msg_outtrans_len(chunk, (int)(s - chunk), hl_id, hist);
|
||||
|
||||
@@ -291,7 +291,11 @@ void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_
|
||||
msg_clr_eos();
|
||||
*need_clear = false;
|
||||
}
|
||||
msg_putchar_hl((uint8_t)(*s), hl_id);
|
||||
if (*s == BELL) {
|
||||
vim_beep(kOptBoFlagShell);
|
||||
} else {
|
||||
msg_putchar_hl((uint8_t)(*s), hl_id);
|
||||
}
|
||||
chunk = s + 1;
|
||||
}
|
||||
s++;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "auto/config.h"
|
||||
#include "klib/kvec.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/charset.h"
|
||||
@@ -1119,6 +1120,17 @@ static void out_data_ring(const char *output, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
static void out_data_event(void **argv)
|
||||
{
|
||||
bool need_clear = true;
|
||||
int hl = (int)(intptr_t)argv[2] == STDERR_FILENO ? HLF_SE : HLF_SO;
|
||||
msg_ext_set_kind((int)(intptr_t)argv[2] == STDERR_FILENO ? "shell_err" : "shell_out");
|
||||
msg_ext_append = true;
|
||||
msg_multiline(cbuf_as_string((char *)argv[0], (size_t)argv[1]), hl, false, false, &need_clear);
|
||||
xfree(argv[0]);
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
/// Continue to append data to last screen line.
|
||||
///
|
||||
/// @param output Data to append to screen lines.
|
||||
@@ -1129,33 +1141,29 @@ static void out_data_append_to_screen(const char *output, size_t *count, int fd,
|
||||
{
|
||||
const char *p = output;
|
||||
const char *end = output + *count;
|
||||
msg_ext_set_kind(fd == STDERR_FILENO ? "shell_err" : "shell_out");
|
||||
msg_ext_append = true;
|
||||
// Note: this is not 100% precise:
|
||||
// 1. we don't check if received continuation bytes are already invalid
|
||||
// and we thus do some buffering that could be avoided
|
||||
// 2. we don't compose chars over buffer boundaries, even if we see an
|
||||
// incomplete UTF-8 sequence that could be composing with the last
|
||||
// complete sequence.
|
||||
// This will be corrected when we switch to vterm based implementation
|
||||
while (p < end) {
|
||||
if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
|
||||
msg_putchar_hl((uint8_t)(*p), fd == STDERR_FILENO ? HLF_SE : HLF_SO);
|
||||
p++;
|
||||
} else {
|
||||
// Note: this is not 100% precise:
|
||||
// 1. we don't check if received continuation bytes are already invalid
|
||||
// and we thus do some buffering that could be avoided
|
||||
// 2. we don't compose chars over buffer boundaries, even if we see an
|
||||
// incomplete UTF-8 sequence that could be composing with the last
|
||||
// complete sequence.
|
||||
// This will be corrected when we switch to vterm based implementation
|
||||
int i = *p ? utfc_ptr2len_len(p, (int)(end - p)) : 1;
|
||||
if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) {
|
||||
*count = (size_t)(p - output);
|
||||
goto end;
|
||||
}
|
||||
|
||||
msg_outtrans_len(p, i, fd == STDERR_FILENO ? HLF_SE : HLF_SO, false);
|
||||
p += i;
|
||||
int i = *p ? utfc_ptr2len_len(p, (int)*count - (int)(p - output)) : 1;
|
||||
if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) {
|
||||
*count = (size_t)(p - output);
|
||||
break;
|
||||
}
|
||||
p += i;
|
||||
}
|
||||
// Process after uv_run() to avoid recursion in vim.ui_attach() msg_show callback #38664.
|
||||
char *str = xmemdupz(output, *count);
|
||||
if (ui_has(kUIMessages)) {
|
||||
multiqueue_put(main_loop.fast_events, out_data_event,
|
||||
(void *)str, (void *)*count, (void *)(intptr_t)fd);
|
||||
} else {
|
||||
out_data_event((void *[]){ (void *)str, (void *)*count, (void *)(intptr_t)fd });
|
||||
}
|
||||
|
||||
end:
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof)
|
||||
|
||||
Reference in New Issue
Block a user