commit e63346dfe91baae48ecdc5453b4033d4d01a7286
parent 8f1c161d9d11a79442b3496fb042c10d6b1ad9f6
Author: luukvbaal <luukvbaal@gmail.com>
Date: Thu, 26 Feb 2026 13:45:33 +0100
fix(messages): reset redirection message column at message start #38068
Problem: Leading message newlines (not emitted with ext_messages since
4260f73) were responsible for resetting the redirection message
column (while the newline itself is later pruned...).
Solution: Ensure the redirection column is reset at the start of a message.
(Instead of re-adjusting all the newline callsites which can
themselves hopefully be pruned if ext_messages is enabled by
default.)
Diffstat:
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/nvim/message.c b/src/nvim/message.c
@@ -1632,6 +1632,7 @@ void msgmore(int n)
}
}
+static int redir_col = 0; // Message column used in redir_write().
void msg_ext_set_kind(const char *msg_kind)
{
// Don't change the label of an existing batch:
@@ -1641,6 +1642,12 @@ void msg_ext_set_kind(const char *msg_kind)
// need refactoring the msg_ interface to not be "please pretend nvim is
// a terminal for a moment"
msg_ext_kind = msg_kind;
+
+ // Need to reset the redirection column at the start of a message, for which
+ // leading newlines are responsible without kUIMessages. Unrelated to setting
+ // the kind but this is called more consistently at the start of a message
+ // than msg_start() at this point.
+ redir_col = msg_ext_append ? redir_col : 0;
}
/// Prepare for outputting characters in the command line.
@@ -3371,7 +3378,6 @@ void msg_check(void)
static void redir_write(const char *const str, const ptrdiff_t maxlen)
{
const char *s = str;
- static int cur_col = 0;
if (maxlen == 0) {
return;
@@ -3390,7 +3396,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
if (redirecting()) {
// If the string doesn't start with CR or NL, go to msg_col
if (*s != '\n' && *s != '\r') {
- while (cur_col < msg_col) {
+ while (redir_col < msg_col) {
if (capture_ga) {
ga_concat_len(capture_ga, " ", 1);
}
@@ -3404,7 +3410,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
if (verbose_fd != NULL) {
fputs(" ", verbose_fd);
}
- cur_col++;
+ redir_col++;
}
}
@@ -3431,17 +3437,17 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
putc(*s, verbose_fd);
}
if (*s == '\r' || *s == '\n') {
- cur_col = 0;
+ redir_col = 0;
} else if (*s == '\t') {
- cur_col += (8 - cur_col % 8);
+ redir_col += (8 - redir_col % 8);
} else {
- cur_col++;
+ redir_col++;
}
s++;
}
if (msg_silent != 0) { // should update msg_col
- msg_col = cur_col;
+ msg_col = redir_col;
}
}
}
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
@@ -439,6 +439,12 @@ describe('API', function()
assert_alive()
eq(false, exec_lua('return _G.success'))
end)
+
+ it('redir_write() message column is reset with ext_messages', function()
+ exec_lua('vim.ui_attach(1, { ext_messages = true }, function() end)')
+ api.nvim_exec2('hi VisualNC', { output = true })
+ eq('VisualNC xxx cleared', api.nvim_exec2('hi VisualNC', { output = true }).output)
+ end)
end)
describe('nvim_command', function()