fix(progress): ins-compl progress-msg during pum #41226

Problem:
The insert-mode completion progress-message is in "running" state while
the user is selecting an item. That is noisy and unwanted UX; it was
only intended for the "Scanning..." task.

Solution:
End the progress-msg just after `ins_compl_show_statusmsg`.
This commit is contained in:
Justin M. Keyes
2026-08-07 18:49:44 -04:00
committed by GitHub
parent 33a688f9fe
commit b53c00b425
6 changed files with 39 additions and 56 deletions

View File

@@ -1082,13 +1082,20 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
} else {
msg_scroll = true; // don't overwrite previous file message
}
// Progress-msg id, e.g. `nvim.bufwrite "foo.txt"`.
char msg_id[MAXPATHL + 32];
#ifndef UNIX
char *msgname = sfname;
#else
char *msgname = fname;
#endif
size_t id_len = xstrlcpy(msg_id, "nvim.bufwrite ", sizeof(msg_id));
add_quoted_fname(msg_id + id_len, sizeof(msg_id) - id_len, buf, msgname);
msg_id[strlen(msg_id) - 1] = NUL; // add_quoted_fname() appends a space, for display only.
if (!filtering) {
// show that we are busy
#ifndef UNIX
filemess_progress(buf, sfname);
#else
filemess_progress(buf, fname);
#endif
filemess_progress(buf, msgname, msg_id);
}
msg_scroll = false; // always overwrite the file message now
@@ -1671,8 +1678,6 @@ restore_backup:
#endif
if (!filtering) {
add_quoted_fname(IObuff, IOSIZE, buf, fname);
char msg_id[bufwrite_msg_id_size];
msg_id_for_bufwrite(msg_id, buf, fname);
bool insert_space = false;
if (write_info.bw_conv_error) {
xstrlcat(IObuff, _(" CONVERSION ERROR"), IOSIZE);
@@ -1813,15 +1818,9 @@ nofail:
os_free_acl(acl);
if (err.msg != NULL) {
#ifndef UNIX
char *errname = sfname;
#else
char *errname = fname;
#endif
// - 100 to save some space for further error message.
add_quoted_fname(IObuff, IOSIZE - 100, buf, errname);
char msg_id[bufwrite_msg_id_size]; // End the progress-msg started by filemess_progress().
msg_id_for_bufwrite(msg_id, buf, errname);
add_quoted_fname(IObuff, IOSIZE - 100, buf, msgname);
// The error ends the progress-msg started by filemess_progress().
emit_err(&err, filtering ? NULL : msg_id);
retval = FAIL;

View File

@@ -110,8 +110,9 @@ static const char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buf
/// Shows a message about file `name`, e.g. `"foo.txt" [New]`.
///
/// @param s Info appended to the filename, e.g. "[New]".
/// @param progress Emit as a progress-message. Caller must emit a non-"running" status, later.
static void filemess(buf_T *buf, char *name, char *s, bool progress)
/// @param msg_id Emit as a progress-message with this id, or NULL for a plain message.
/// Caller must emit a non-"running" status for `msg_id`, later.
static void filemess(buf_T *buf, char *name, char *s, const char *msg_id)
{
int prev_msg_col = msg_col;
@@ -141,10 +142,8 @@ static void filemess(buf_T *buf, char *name, char *s, bool progress)
msg_scroll = msg_scroll_save;
msg_scrolled_ign = true;
// may truncate the message to avoid a hit-return prompt
if (progress) {
char msg_id[bufwrite_msg_id_size];
msg_id_for_bufwrite(msg_id, buf, name);
msg_progress(IObuff, msg_id, "running", 0, false, true, false);
if (msg_id != NULL) {
msg_progress(IObuff, (char *)msg_id, "running", 0, false, true, false);
} else {
msg_outtrans(msg_may_trunc(false, IObuff), 0, false);
}
@@ -153,10 +152,10 @@ static void filemess(buf_T *buf, char *name, char *s, bool progress)
}
/// Shows the "busy" message for writing file `name`, as a progress-message. #39280
/// Caller must end the progress by emitting a non-"running" status.
void filemess_progress(buf_T *buf, char *name)
/// Caller must end the progress by emitting a non-"running" status to the same `msg_id`.
void filemess_progress(buf_T *buf, char *name, const char *msg_id)
{
filemess(buf, name, "", true);
filemess(buf, name, "", msg_id);
}
/// Read lines from file "fname" into the buffer after line "from".
@@ -361,7 +360,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// If the name is too long we might crash further on, quit here.
if (fnamelen >= MAXPATHL) {
filemess(curbuf, fname, _("Illegal file name"), false);
filemess(curbuf, fname, _("Illegal file name"), NULL);
msg_end();
msg_scroll = msg_save;
goto theend;
@@ -372,7 +371,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// swap file may destroy it! Reported on MS-DOS and Win 95.
if (after_pathsep(fname, fname + fnamelen)) {
if (!silent) {
filemess(curbuf, fname, _(msg_is_a_directory), false);
filemess(curbuf, fname, _(msg_is_a_directory), NULL);
}
msg_end();
msg_scroll = msg_save;
@@ -402,11 +401,11 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
// check for it before os_open().
if (S_ISDIR(perm)) {
if (!silent) {
filemess(curbuf, fname, _(msg_is_a_directory), false);
filemess(curbuf, fname, _(msg_is_a_directory), NULL);
}
retval = NOTDONE;
} else {
filemess(curbuf, fname, _("is not a file"), false);
filemess(curbuf, fname, _("is not a file"), NULL);
}
msg_end();
msg_scroll = msg_save;
@@ -495,9 +494,9 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
}
if (!silent) {
if (dir_of_file_exists(fname)) {
filemess(curbuf, sfname, _("[New]"), false);
filemess(curbuf, sfname, _("[New]"), NULL);
} else {
filemess(curbuf, sfname, _("[New DIRECTORY]"), false);
filemess(curbuf, sfname, _("[New DIRECTORY]"), NULL);
}
}
// Even though this is a new file, it might have been
@@ -523,10 +522,10 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
? _("[File too big]")
// libuv only returns -errno in Unix; Windows open() does not set EOVERFLOW.
: (fd == -EOVERFLOW) ? _("[File too big]") : _("[Permission Denied]")),
false);
NULL);
#else
filemess(curbuf, sfname, ((fd == UV_EFBIG) ? _("[File too big]") : _("[Permission Denied]")),
false);
NULL);
#endif
curbuf->b_p_ro = true; // must use "w!" now
@@ -684,7 +683,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip,
if (!recoverymode && !filtering && !(flags & READ_DUMMY) && !silent) {
if (!read_stdin && !read_buffer) {
filemess(curbuf, sfname, "", false);
filemess(curbuf, sfname, "", NULL);
}
}
@@ -1753,7 +1752,7 @@ failed:
if (got_int) {
if (!(flags & READ_DUMMY)) {
filemess(curbuf, sfname, _(e_interr), false);
filemess(curbuf, sfname, _(e_interr), NULL);
if (newfile) {
curbuf->b_p_ro = true; // must use "w!" now
}

View File

@@ -2856,10 +2856,6 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
ins_compl_free();
compl_started = false;
compl_matches = 0;
if (!shortmess(kShmCompletionscan) && !compl_autocomplete) {
// End the "Scanning..." progress-msg. ins_compl_show_statusmsg() already reported the result.
msg_progress(NULL, "nvim.completion", "success", 0, false, false, false);
}
if (!shortmess(kShmCompletionmenu)) {
msg_clr_cmdline(); // necessary for "noshowmode"
}
@@ -6355,6 +6351,11 @@ int ins_complete(int c, bool enable_pum)
ins_compl_show_statusmsg();
}
if (!shortmess(kShmCompletionscan) && !compl_autocomplete) {
// End the "Scanning..." progress-msg. ins_compl_show_statusmsg() already reported the result.
msg_progress(NULL, "nvim.completion", "success", 0, false, false, false);
}
// Show the popup menu, unless we got interrupted.
if (enable_pum && !compl_interrupted) {
show_pum(save_w_wrow, save_w_leftcol);

View File

@@ -169,18 +169,6 @@ bool msg_id_exists(int64_t id)
return id > 0 && id < msg_id_next;
}
/// Formats a progress-msg id for use by bufwrite.c/fileio.c.
///
/// @param msg_id Buffer of `bufwrite_msg_id_size` bytes.
void msg_id_for_bufwrite(char *msg_id, buf_T *buf, char *name)
{
xstrlcpy(msg_id, "nvim.bufwrite ", bufwrite_msg_id_size);
size_t len = strlen(msg_id);
add_quoted_fname(msg_id + len, bufwrite_msg_id_size - len, buf, name);
// add_quoted_fname() appends a space for display; the id ends at the closing quote.
msg_id[strlen(msg_id) - 1] = NUL;
}
static void ui_ext_msg_set_pos(int row, bool scrolled)
{
char buf[MAX_SCHAR_SIZE];

View File

@@ -9,10 +9,6 @@
#include "nvim/keycodes_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
#include "nvim/message_defs.h" // IWYU pragma: keep
#include "nvim/os/os_defs.h"
/// Buffer size for msg_id_for_bufwrite().
enum { bufwrite_msg_id_size = MAXPATHL + 32, };
/// Types of dialogs passed to do_dialog().
enum {

View File

@@ -3960,8 +3960,8 @@ describe('progress-message', function()
})
end)
command('set shortmess-=C complete=kXdict')
feed('ifoo<C-n><Esc>')
-- Leaving completion ends the scan message, which otherwise stays "running" forever.
-- Ends when scanning ends, regardless of whether popupmenu is open.
feed('ifoo<C-n>')
eq({ 'nvim.completion running', 'nvim.completion success' }, exec_lua('return _G.events'))
end)