fix(messages): proper multiline Lua print() messages #31205

Problem:  Separate message emitted for each newline present in Lua
          print() arguments.
Solution: Make msg_multiline() handle NUL bytes. Refactor print() to use
          msg_multiline(). Refactor vim.print() to use print().
This commit is contained in:
luukvbaal
2024-11-17 19:21:50 +01:00
committed by GitHub
parent 6ea45031d5
commit e025f5a5b3
9 changed files with 64 additions and 77 deletions

View File

@@ -7881,7 +7881,7 @@ void ex_echo(exarg_T *eap)
char *tofree = encode_tv2echo(&rettv, NULL);
if (*tofree != NUL) {
msg_ext_set_kind("echo");
msg_multiline(tofree, echo_hl_id, true, false, &need_clear);
msg_multiline(cstr_as_string(tofree), echo_hl_id, true, false, &need_clear);
}
xfree(tofree);
}

View File

@@ -189,7 +189,7 @@ void do_ascii(exarg_T *eap)
transchar(c), buf1, buf2, cval, cval, cval);
}
msg_multiline(IObuff, 0, true, false, &need_clear);
msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data); // needed for overlong ascii?
}
@@ -224,7 +224,7 @@ void do_ascii(exarg_T *eap)
c, c, c);
}
msg_multiline(IObuff, 0, true, false, &need_clear);
msg_multiline(cstr_as_string(IObuff), 0, true, false, &need_clear);
off += (size_t)utf_ptr2len(data + off); // needed for overlong ascii?
}

View File

@@ -954,41 +954,10 @@ static void nlua_common_free_all_mem(lua_State *lstate)
static void nlua_print_event(void **argv)
{
char *str = argv[0];
const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL
for (size_t i = 0; i < len;) {
if (got_int) {
break;
}
const size_t start = i;
while (i < len) {
switch (str[i]) {
case NUL:
str[i] = NL;
i++;
continue;
case NL:
// TODO(bfredl): use proper multiline msg? Probably should implement
// print() in lua in terms of nvim_message(), when it is available.
str[i] = NUL;
i++;
break;
default:
i++;
continue;
}
break;
}
msg(str + start, 0);
if (msg_silent == 0) {
msg_didout = true; // Make blank lines work properly
}
}
if (len && str[len - 1] == NUL) { // Last was newline
msg("", 0);
}
xfree(str);
HlMessage msg = KV_INITIAL_VALUE;
HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 };
kv_push(msg, chunk);
msg_multihl(msg, "lua_print", true);
}
/// Print as a Vim message

View File

@@ -249,35 +249,33 @@ bool msg(const char *s, const int hl_id)
return msg_hl_keep(s, hl_id, false, false);
}
/// Similar to msg_outtrans, but support newlines and tabs.
void msg_multiline(const char *s, int hl_id, bool check_int, bool hist, bool *need_clear)
/// Similar to msg_outtrans_len, but support newlines and tabs.
void msg_multiline(String str, int hl_id, bool check_int, bool hist, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
const char *next_spec = s;
while (next_spec != NULL) {
const char *s = str.data;
const char *chunk = s;
while ((size_t)(s - str.data) < str.size) {
if (check_int && got_int) {
return;
}
next_spec = strpbrk(s, "\t\n\r");
if (*s == '\n' || *s == TAB || *s == '\r') {
// Print all chars before the delimiter
msg_outtrans_len(chunk, (int)(s - chunk), hl_id, hist);
if (next_spec != NULL) {
// Printing all char that are before the char found by strpbrk
msg_outtrans_len(s, (int)(next_spec - s), hl_id, hist);
if (*next_spec != TAB && *need_clear) {
if (*s != TAB && *need_clear) {
msg_clr_eos();
*need_clear = false;
}
msg_putchar_hl((uint8_t)(*next_spec), hl_id);
s = next_spec + 1;
msg_putchar_hl((uint8_t)(*s), hl_id);
chunk = s + 1;
}
s++;
}
// Print the rest of the message. We know there is no special
// character because strpbrk returned NULL
if (*s != NUL) {
msg_outtrans(s, hl_id, hist);
// Print the rest of the message
if (*chunk != NUL) {
msg_outtrans_len(chunk, (int)(str.size - (size_t)(chunk - str.data)), hl_id, hist);
}
}
@@ -290,7 +288,7 @@ void msg_multihl(HlMessage hl_msg, const char *kind, bool history)
msg_ext_set_kind(kind);
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i);
msg_multiline(chunk.text.data, chunk.hl_id, true, false, &need_clear);
msg_multiline(chunk.text, chunk.hl_id, true, false, &need_clear);
}
if (history && kv_size(hl_msg)) {
add_msg_hist_multihl(NULL, 0, 0, true, hl_msg);
@@ -349,7 +347,7 @@ bool msg_hl_keep(const char *s, int hl_id, bool keep, bool multiline)
bool need_clear = true;
if (multiline) {
msg_multiline(s, hl_id, false, false, &need_clear);
msg_multiline(cstr_as_string(s), hl_id, false, false, &need_clear);
} else {
msg_outtrans(s, hl_id, false);
}
@@ -2689,12 +2687,13 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
// primitive way to compute the current column
if (*s == '\r' || *s == '\n') {
msg_col = 0;
msg_didout = false;
} else {
msg_col += cw;
msg_didout = true;
}
s += len;
}
msg_didout = true; // assume that line is not empty
}
/// Show the more-prompt and handle the user response.