diff --git a/src/nvim/message.c b/src/nvim/message.c index 62a5e42cbe..694f8835fd 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -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++; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index f1eec952fb..799ac33d78 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -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)