diff options
author | luukvbaal <luukvbaal@gmail.com> | 2024-11-17 19:21:50 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-17 10:21:50 -0800 |
commit | e025f5a5b30a1ef92e88fed0f0c548d2240d30c0 (patch) | |
tree | 9ae569b85a6f1506a402556e44b6b6a81485efbc | |
parent | 6ea45031d5841d3227c545f213d0903b951e40be (diff) | |
download | rneovim-e025f5a5b30a1ef92e88fed0f0c548d2240d30c0.tar.gz rneovim-e025f5a5b30a1ef92e88fed0f0c548d2240d30c0.tar.bz2 rneovim-e025f5a5b30a1ef92e88fed0f0c548d2240d30c0.zip |
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().
-rw-r--r-- | runtime/doc/ui.txt | 1 | ||||
-rw-r--r-- | runtime/lua/vim/_editor.lua | 13 | ||||
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 4 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 39 | ||||
-rw-r--r-- | src/nvim/message.c | 39 | ||||
-rw-r--r-- | test/functional/core/startup_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/ui_event_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/ui/messages_spec.lua | 39 |
9 files changed, 64 insertions, 77 deletions
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 4ee8121034..4e8253c47a 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -796,6 +796,7 @@ must handle. "echomsg" |:echomsg| message "echoerr" |:echoerr| message "lua_error" Error in |:lua| code + "lua_print" |print()| from |:lua| code "rpc_error" Error response from |rpcrequest()| "return_prompt" |press-enter| prompt after a multiple messages "quickfix" Quickfix navigation message diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index b4a1e0fc15..44f17b3f85 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -1151,21 +1151,16 @@ end --- @param ... any --- @return any # given arguments. function vim.print(...) - if vim.in_fast_event() then - print(...) - return ... - end - + local msg = {} for i = 1, select('#', ...) do local o = select(i, ...) if type(o) == 'string' then - vim.api.nvim_out_write(o) + table.insert(msg, o) else - vim.api.nvim_out_write(vim.inspect(o, { newline = '\n', indent = ' ' })) + table.insert(msg, vim.inspect(o, { newline = '\n', indent = ' ' })) end - vim.api.nvim_out_write('\n') end - + print(table.concat(msg, '\n')) return ... end diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ab6115f145..ef6e0940cf 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -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); } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index e937961b44..8cccf08e11 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -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? } diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 15f70fb725..c4fa8b0fff 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -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 diff --git a/src/nvim/message.c b/src/nvim/message.c index e8f20916b8..47f33c8967 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -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 (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 (*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 != 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. diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index e885164c20..7062211187 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -277,10 +277,8 @@ describe('startup', function() -- nvim <vim args> -l foo.lua <vim args> assert_l_out( - -- luacheck: ignore 611 (Line contains only whitespaces) [[ wrap - bufs: nvim args: 7 lua args: { "-c", "set wrap?", diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 6d4be4d1f2..c8616e3e11 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -142,7 +142,7 @@ describe('vim.ui_attach', function() 'msg_history_show', { { 'echomsg', { { 0, 'message1', 0 } } }, - { '', { { 0, 'message2', 0 } } }, + { 'lua_print', { { 0, 'message2', 0 } } }, { 'echomsg', { { 0, 'message3', 0 } } }, }, }, diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 25f3465d46..734877d262 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1113,6 +1113,33 @@ stack traceback: }) eq(showmode, 1) end) + + it('emits single message for multiline print())', function() + exec_lua([[print("foo\nbar\nbaz")]]) + screen:expect({ + messages = { + { + content = { { 'foo\nbar\nbaz' } }, + kind = 'lua_print', + }, + }, + }) + exec_lua([[print(vim.inspect({ foo = "bar" }))]]) + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + messages = { + { + content = { { '{\n foo = "bar"\n}' } }, + kind = 'lua_print', + }, + }, + }) + exec_lua([[vim.print({ foo = "bar" })]]) + screen:expect_unchanged() + end) end) describe('ui/builtin messages', function() @@ -2062,8 +2089,6 @@ aliquip ex ea commodo consequat.]] end) it('can be quit with Lua #11224 #16537', function() - -- NOTE: adds "4" to message history, although not displayed initially - -- (triggered the more prompt). screen:try_resize(40, 5) feed(':lua for i=0,10 do print(i) end<cr>') screen:expect { @@ -2093,13 +2118,13 @@ aliquip ex ea commodo consequat.]] {4:-- More --}^ | ]], } - feed('j') + feed('G') screen:expect { grid = [[ - 1 | - 2 | - 3 | - 4 | + 7 | + 8 | + 9 | + 10 | {4:Press ENTER or type command to continue}^ | ]], } |