From b53c00b42599f31c0bd30be75b4dd4be32fd883d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 7 Aug 2026 18:49:44 -0400 Subject: [PATCH] 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`. --- src/nvim/bufwrite.c | 29 +++++++++++----------- src/nvim/fileio.c | 37 ++++++++++++++-------------- src/nvim/insexpand.c | 9 ++++--- src/nvim/message.c | 12 --------- src/nvim/message.h | 4 --- test/functional/ui/messages_spec.lua | 4 +-- 6 files changed, 39 insertions(+), 56 deletions(-) diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 8a3d17e3c3..ddeda3c074 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -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; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index f30b6436e6..238b89a7c5 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -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 } diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index ea86f307b1..38b3d2156d 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -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); diff --git a/src/nvim/message.c b/src/nvim/message.c index b39b07a60c..3b508dce4f 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -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]; diff --git a/src/nvim/message.h b/src/nvim/message.h index 94ad0970ed..bcf07cfb5f 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -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 { diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index ea87243daa..b8cc3115d5 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -3960,8 +3960,8 @@ describe('progress-message', function() }) end) command('set shortmess-=C complete=kXdict') - feed('ifoo') - -- Leaving completion ends the scan message, which otherwise stays "running" forever. + -- Ends when scanning ends, regardless of whether popupmenu is open. + feed('ifoo') eq({ 'nvim.completion running', 'nvim.completion success' }, exec_lua('return _G.events')) end)