fix(messages): "progress" kind for busy messages #39280

Problem:  The "Scanning:" completion, bufwrite, and indent (there may be
          more) messages which indicate progress can use the "progress" kind
          for their msg_show event. Indent message does not have a kind.

Solution: Emit these messages with the "progress" kind. Set the message id
          to the replaced kind so that a UI knows to replace it (and to provide
          a migration path in case a UI was distinguishing these messages for
          whatever reason).
This commit is contained in:
luukvbaal
2026-04-21 22:11:41 +02:00
committed by GitHub
parent fe60268258
commit ff68fd6b8a
10 changed files with 75 additions and 35 deletions
-1
View File
@@ -846,7 +846,6 @@ must handle.
"empty" Empty message (`:echo ""`), with empty `content`.
Should clear messages sharing the 'cmdheight'
area if it is the only message in a batch.
"bufwrite" |:write| message
"confirm" Message preceding a prompt (|:confirm|,
|confirm()|, |inputlist()|, |z=|, …)
"emsg" Error (|errors|, internal error, |:throw|, …)
+2
View File
@@ -65,6 +65,8 @@ API
• |nvim_create_autocmd()|, |nvim_exec_autocmds()| and |nvim_clear_autocmds()|
no longer treat an empty non-nil pattern as nil.
• |nvim_clear_autocmds()| no longer treats an empty array event as nil.
• |ui-messages| `msg_show.bufwrite` and `msg_show.completion` messages are now
`msg_show.progress` events.
DIAGNOSTICS
+1 -5
View File
@@ -1081,7 +1081,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
msg_scroll = true; // don't overwrite previous file message
}
if (!filtering) {
msg_ext_set_kind("bufwrite");
// show that we are busy
#ifndef UNIX
filemess(buf, sfname, "");
@@ -1708,10 +1707,7 @@ restore_backup:
xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"), IOSIZE);
}
}
msg_ext_set_kind("bufwrite");
msg_ext_overwrite = true;
set_keep_msg(msg_trunc(IObuff, false, 0), 0);
set_keep_msg(msg_progress(IObuff, "bufwrite", "success", 0, true, true), 0);
}
// When written everything correctly: reset 'modified'. Unless not
+5 -2
View File
@@ -131,9 +131,12 @@ void filemess(buf_T *buf, char *name, char *s)
msg_scroll = msg_scroll_save;
msg_scrolled_ign = true;
// may truncate the message to avoid a hit-return prompt
msg_outtrans(msg_may_trunc(false, IObuff), 0, false);
if (*s == NUL) {
msg_progress(IObuff, "bufwrite", "running", 0, false, true);
} else {
msg_outtrans(msg_may_trunc(false, IObuff), 0, false);
}
msg_clr_eos();
ui_flush();
msg_scrolled_ign = false;
}
+12 -9
View File
@@ -1004,19 +1004,20 @@ void op_reindent(oparg_T *oap, Indenter how)
if (i > 1
&& (i % 50 == 0 || i == oap->line_count - 1)
&& oap->line_count > p_report) {
smsg(0, _("%" PRId64 " lines to indent... "), (int64_t)i);
snprintf(IObuff, IOSIZE, _("%" PRId64 " lines to indent... "), (int64_t)i);
// Restore cursor to avoid redrawing curwin in msg_show callback.
linenr_T save_lnum = curwin->w_cursor.lnum;
curwin->w_cursor.lnum = start_lnum;
msg_progress(IObuff, "indent", "running", 0, true, false);
curwin->w_cursor.lnum = save_lnum;
}
// Be vi-compatible: For lisp indenting the first line is not
// indented, unless there is only one line.
if (i != oap->line_count - 1 || oap->line_count == 1
|| how != get_lisp_indent) {
if (i != oap->line_count - 1 || oap->line_count == 1 || how != get_lisp_indent) {
char *l = skipwhite(get_cursor_line_ptr());
if (*l == NUL) { // empty or blank line
amount = 0;
} else {
amount = how(); // get the indent for this line
}
// Get indent for this line unless it is blank.
amount = *l == NUL ? 0 : how();
if (amount >= 0 && set_indent(amount, 0)) {
// did change the indent, call changed_lines() later
if (first_changed == 0) {
@@ -1047,7 +1048,9 @@ void op_reindent(oparg_T *oap, Indenter how)
if (oap->line_count > p_report) {
i = oap->line_count - (i + 1);
smsg(0, NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
snprintf(IObuff, IOSIZE,
NGETTEXT("%" PRId64 " line indented ", "%" PRId64 " lines indented ", i), (int64_t)i);
msg_progress(IObuff, "indent", "success", 0, true, false);
}
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
// set '[ and '] marks
+4 -13
View File
@@ -1944,11 +1944,8 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags,
for (int i = 0; i < count && !got_int && !ins_compl_interrupted(); i++) {
FILE *fp = os_fopen(files[i], "r"); // open dictionary file
if (flags != DICT_EXACT && !shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) {
msg_hist_off = true; // reset in msg_trunc()
msg_ext_set_kind("completion");
vim_snprintf(IObuff, IOSIZE,
_("Scanning dictionary: %s"), files[i]);
msg_trunc(IObuff, true, HLF_R);
vim_snprintf(IObuff, IOSIZE, _("Scanning dictionary: %s"), files[i]);
msg_progress(IObuff, "completion", "running", HLF_R, false, true);
}
if (fp == NULL) {
@@ -3823,16 +3820,13 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
st->dict_f = DICT_EXACT;
}
if (!shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) {
msg_hist_off = true; // reset in msg_trunc()
msg_ext_overwrite = true;
msg_ext_set_kind("completion");
vim_snprintf(IObuff, IOSIZE, _("Scanning: %s"),
st->ins_buf->b_fname == NULL
? buf_spname(st->ins_buf)
: st->ins_buf->b_sfname == NULL
? st->ins_buf->b_fname
: st->ins_buf->b_sfname);
msg_trunc(IObuff, true, HLF_R);
msg_progress(IObuff, "completion", "running", HLF_R, false, true);
}
} else if (*st->e_cpt == NUL) {
status = INS_COMPL_CPT_END;
@@ -3865,11 +3859,8 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
} else if (*st->e_cpt == ']' || *st->e_cpt == 't') {
compl_type = CTRL_X_TAGS;
if (!shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) {
msg_ext_set_kind("completion");
msg_hist_off = true; // reset in msg_trunc()
msg_ext_overwrite = true;
vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags."));
msg_trunc(IObuff, true, HLF_R);
msg_progress(IObuff, "completion", "running", HLF_R, false, true);
}
}
}
+26 -1
View File
@@ -14,6 +14,7 @@
#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer_defs.h"
@@ -387,7 +388,6 @@ MsgID msg_multihl(MsgID id, HlMessage hl_msg, const char *kind, bool history, bo
msg_clr_eos();
bool need_clear = false;
bool hl_msg_updated = false;
msg_ext_history = history;
if (kind != NULL) {
msg_ext_set_kind(kind);
}
@@ -1099,6 +1099,31 @@ char *msg_may_trunc(bool force, char *s)
return s;
}
char *msg_progress(char *s, char *id, char *status, int hl_id, bool hist, bool trunc)
{
Error err = ERROR_INIT;
Dict(echo_opts) opts = {
.kind = cstr_as_string("progress"),
.source = cstr_as_string("nvim"),
.status = cstr_as_string(status),
.id = CSTR_AS_OBJ(id),
};
if (hist && (!trunc || ui_has(kUIMessages))) {
msg_hist_add(s, -1, 0);
}
if (trunc) {
s = msg_may_trunc(false, s);
}
MAXSIZE_TEMP_ARRAY(chunk, 2);
MAXSIZE_TEMP_ARRAY(chunks, 1);
ADD_C(chunk, CSTR_AS_OBJ(s));
ADD_C(chunk, INTEGER_OBJ(hl_id));
ADD_C(chunks, ARRAY_OBJ(chunk));
nvim_echo(chunks, false, &opts, &err);
ui_flush();
return s;
}
void hl_msg_free(HlMessage hl_msg)
{
for (size_t i = 0; i < kv_size(hl_msg); i++) {
+19 -3
View File
@@ -95,7 +95,7 @@ describe('ui/ext_messages', function()
{1:~ }|*3
]],
messages = {
{ content = { { writemsg } }, history = true, kind = 'bufwrite' },
{ content = { { writemsg } }, history = true, id = 'bufwrite', kind = 'progress' },
{
content = { { 'W10: Warning: Changing a readonly file', 19, 'WarningMsg' } },
history = true,
@@ -576,6 +576,20 @@ describe('ui/ext_messages', function()
]],
messages = { { content = { { ' foldclose=' } }, history = true, kind = 'list_cmd' } },
})
-- Indent message
feed('A2\nline 3<Esc>gg=G')
screen:expect({
grid = [[
^line 1 |
line 2 |
line 3 |
{1:~ }|*2
]],
messages = {
{ content = { { '3 lines indented ' } }, history = true, id = 'indent', kind = 'progress' },
},
})
end)
it(':echoerr', function()
@@ -1383,7 +1397,8 @@ stack traceback:
messages = {
{
content = { { string.format('"%s" [New] 0L, 0B written', fname) } },
kind = 'bufwrite',
kind = 'progress',
id = 'bufwrite',
history = true,
},
},
@@ -1629,7 +1644,8 @@ stack traceback:
messages = {
{
content = { { 'Scanning tags.', 6, 'Question' } },
kind = 'completion',
kind = 'progress',
id = 'completion',
},
},
showmode = {
+6
View File
@@ -1453,6 +1453,12 @@ function Screen:_handle_msg_show(kind, chunks, replace_last, history, append, id
if not replace_last or pos == 0 then
pos = pos + 1
end
for i, msg in pairs(self.messages) do
if id ~= -1 and msg.id == id then
pos = i
break
end
end
self.messages[pos] = {
kind = kind,
content = chunks,
-1
View File
@@ -18,7 +18,6 @@ if exists('s:did_load')
set laststatus=1
set listchars=eol:$
set maxsearchcount=99
set messagesopt=hit-enter,history:500
set mousemodel=extend
set nohidden nosmarttab noautoindent noautoread
set nohlsearch noincsearch