diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 27bb77f82c..c8930dc909 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -1710,7 +1710,10 @@ restore_backup: xstrlcat(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"), IOSIZE); } } + // Hide cursor while emitting "written" message, so cursor doesn't flicker in cmdline. #25974 + ui_busy_start(); set_keep_msg(msg_progress(IObuff, msg_id, "success", 0, true, true), 0); + ui_busy_stop(); } // When written everything correctly: reset 'modified'. Unless not diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 3a0fd6bbfc..a1b57a932a 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -2634,12 +2634,17 @@ static void flush_buf(TUIData *tui, FlushBufFinish finish) fwrite(bufs[i].base, bufs[i].len, 1, tui->screenshot); } } else { - int ret - = uv_write(&req, (uv_stream_t *)&tui->output_handle, bufs, ARRAY_SIZE(bufs), NULL); - if (ret) { - ELOG("uv_write failed: %s", uv_strerror(ret)); + unsigned nbufs = ARRAY_SIZE(bufs); + while (nbufs > 0 && bufs[nbufs - 1].len == 0) { + nbufs--; // Trim trailing zero-length buffers. https://github.com/libuv/libuv/issues/5182 + } + if (nbufs > 0) { + int ret = uv_write(&req, (uv_stream_t *)&tui->output_handle, bufs, nbufs, NULL); + if (ret) { + ELOG("uv_write failed: %s", uv_strerror(ret)); + } + uv_run(&tui->write_loop, UV_RUN_DEFAULT); } - uv_run(&tui->write_loop, UV_RUN_DEFAULT); } tui->buf_to_flush = NULL; tui->bufpos = 0; diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index fa45293ebe..e79decbc3f 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1727,6 +1727,30 @@ describe('ui/builtin messages', function() } end) + it('no cursor flicker during :write message (marks UI busy) #25974', function() + local fname = 'Xtest_write_busy' + finally(function() + os.remove(fname) + end) + local busy_start, busy_stop = 0, 0 + screen._handle_busy_start = (function(orig) + return function() + orig(screen) + busy_start = busy_start + 1 + end + end)(screen._handle_busy_start) + screen._handle_busy_stop = (function(orig) + return function() + orig(screen) + busy_stop = busy_stop + 1 + end + end)(screen._handle_busy_stop) + command('write ' .. fname) + screen:expect({ any = 'written' }) + eq(true, busy_start >= 1) -- cursor was hidden while the message was emitted + eq(busy_start, busy_stop) -- balanced: cursor restored afterwards + end) + it(':hi Group output', function() screen:try_resize(70, 7) feed(':hi ErrorMsg')