Go to file
Justin M. Keyes 3b8c19ea46 fix(bufwrite): cursor flicker on :write
PROBLEM:
Cursor briefly flickers in cmdline when the "written" message is printed
(very noticeable in Neovide with cursor animation).

SOLUTION:
- Mark UI "busy" (cursor hidden) while emitting the message, as done for
  the search message (cb2ca54331).
- Note: ff68fd6b8a moved the message from `filemess()` into
  `buf_write..msg_progress`.
- Fix a bug in `tui.c:flush_buf` which manifested after this change. See
  ANALYSIS below. https://github.com/libuv/libuv/issues/5182

ANALYSIS:
After this change...

    ui_busy_start();
    set_keep_msg(msg_progress(IObuff, msg_id, "success", 0, true, true), 0);
    ui_busy_stop();

...ASAN analyzer fails on tui_spec.lua test "with non-tty (pipe) stdout/stderr":

    2026-07-04T14:09:28.9521023Z = ==32405==ERROR: AddressSanitizer: ABRT on unknown address 0x03e900007e95
    ...
    4 0x7f5506a288fe in abort stdlib/abort.c:79:7
    5 0x559afd7113a2 in uv__epoll_ctl_flush
    build/src/libuv/src/unix/linux.c:1335:7
    6 0x559afd710a81 in uv__io_poll
    build/src/libuv/src/unix/linux.c:1448:9
    7 0x559afd6f67a7 in uv_run
    build/src/libuv/src/unix/core.c:460:5
    8 0x559afd2a72cc in flush_buf
    nvim/tui/tui.c:2642:5
    9 0x559afd2bce9f in tui_flush
    nvim/tui/tui.c:1747:3
    10 0x559afd2f39a0 in ui_client_event_flush
    nvim/auto/ui_events_client.generated.h:64:3
    11 0x559afcb8e014 in parse_msgpack
    nvim/msgpack_rpc/channel.c:255:11
    12 0x559afcb840e7 in receive_msgpack
    nvim/msgpack_rpc/channel.c:217:5
    13 0x559afc53b2af in read_event
    nvim/event/rstream.c:180:23
    14 0x559afc53ad52 in invoke_read_cb
    nvim/event/rstream.c:233:3
    15 0x559afc5382d6 in read_cb
    nvim/event/rstream.c:135:3
    16 0x559afd707b25 in uv__read
    build/src/libuv/src/unix/stream.c:1145:7
    17 0x559afd70744a in uv__stream_io
    build/src/libuv/src/unix/stream.c:1208:5
    18 0x559afd6f727e in uv__io_cb
    build/src/libuv/src/unix/core.c:930:5
    19 0x559afd710d7a in uv__io_poll
    build/src/libuv/src/unix/linux.c:1546:11
    20 0x559afd6f67a7 in uv_run
    build/src/libuv/src/unix/core.c:460:5
    21 0x559afc526e2d in loop_uv_run
    nvim/event/loop.c:59:3
    22 0x559afc526aa4 in loop_poll_events
    nvim/event/loop.c:80:26
    23 0x559afd2fdbb7 in ui_client_run
    nvim/ui_client.c:172:5
    24 0x559afc920d7b in main /home/runner/work/neovim/neovim/src/nvim/main.c:355:5
    25 0x7f5506a2a1c9 in __libc_start_call_main
    main.h:58:16
    26 0x7f5506a2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    27 0x559afbd6d254 in _start

The abort requires two rare conditions:
1. a `uv_write` whose buffer array *ends* in a zero-length buffer, which only
   happens by "flush while cursor-hidden".
2. an output fd that *epoll cannot watch*. The only CI test with such an fd is
   tui_spec.lua "with non-tty (pipe) stdout/stderr", which runs a TUI with
   `stdout > /dev/null`, then runs `:w testF`, which triggers the "written"
   message.

Our change guarantees trailing-empty flushes (`:w` fires busy + `ui_flush()`
while busy) in the only test that runs a TUI on `/dev/null`.

0. In a normal (non-busy) no-sync flush, post always contains `cursor_normal`.
1. Our change emits:
   ```
   busy_start → msg_progress("…written") → ui_flush → busy_stop
   ```
2. TUI flushes *while busy*, so `should_invisible() = true` and `flush_buf`
   skips the cursor-restore string (`bufs[2]` is zero-length).
3. libuv *cannot complete* a write whose tail is a zero-length buffer: EVERY
   trailing-empty write goes through epoll, even when every byte was already
   written. https://github.com/libuv/libuv/issues/5182
4. In `tui_spec.lua:3298`, the output fd is `/dev/null`, whose kernel
   `file_operations` has no `.poll` method (`drivers/char/mem.c`), so
   `EPOLL_CTL_ADD` fails with `EPERM`.

Trailing empty buffers are semantically pointless, and libuv punishes
them: forced async, one epoll round-trip *per trailing empty*, plus
a 0-byte `write()` syscall.

Helped-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Helped-by: Fred Sundvik <fsundvik@gmail.com>
2026-07-04 23:17:27 +02:00
2026-06-30 15:32:18 +02:00
2026-05-13 13:14:07 +01:00
2026-06-30 14:50:32 +03:00
2026-03-20 23:30:09 +01:00
2025-12-30 01:44:52 -05:00
2026-03-13 12:29:44 +00:00
2026-06-30 14:50:32 +03:00
2025-01-11 10:34:12 +01:00
2026-04-18 15:38:59 -04:00
2026-03-11 18:00:18 +01:00
2026-03-11 18:00:18 +01:00
2026-04-16 10:48:11 -04:00

Neovim

Documentation | Chat

Coverity Scan analysis Packages Debian CI Downloads

Neovim is a project that seeks to aggressively refactor Vim in order to:

See the Introduction wiki page and Roadmap for more information.

Features

See :help nvim-features for the full list, and :help news for noteworthy changes in the latest version!

Install from package

Pre-built packages for Windows, macOS, and Linux are found on the Releases page.

Managed packages are in Homebrew, Debian, Ubuntu, Fedora, Arch Linux, Void Linux, Gentoo, and more!

Install from source

See BUILD.md and supported platforms for details.

The build is CMake-based, but a Makefile is provided as a convenience. After installing the dependencies, run the following command.

make CMAKE_BUILD_TYPE=RelWithDebInfo
sudo make install

To install to a non-default location:

make CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_INSTALL_PREFIX=/full/path/
make install

CMake hints for inspecting the build:

  • cmake --build build --target help lists all build targets.
  • build/CMakeCache.txt (or cmake -LAH build/) contains the resolved values of all CMake variables.
  • build/compile_commands.json shows the full compiler invocations for each translation unit.

Transitioning from Vim

See :help nvim-from-vim for instructions.

Project layout

├─ cmake/           CMake utils
├─ cmake.config/    CMake defines
├─ cmake.deps/      subproject to fetch and build dependencies (optional)
├─ runtime/         plugins and docs
├─ src/nvim/        application source code (see src/nvim/README.md)
│  ├─ api/          API subsystem
│  ├─ eval/         Vimscript subsystem
│  ├─ event/        event-loop subsystem
│  ├─ generators/   code generation (pre-compilation)
│  ├─ lib/          generic data structures
│  ├─ lua/          Lua subsystem
│  ├─ msgpack_rpc/  RPC subsystem
│  ├─ os/           low-level platform code
│  └─ tui/          built-in UI
└─ test/            tests (see test/README.md)

License

Neovim contributions since b17d96 are licensed under the Apache 2.0 license, except for contributions copied from Vim (identified by the vim-patch token). See LICENSE.txt for details.

Description
Vim-fork focused on extensibility and usability
Readme 576 MiB
Languages
Vim Script 40.1%
Lua 32.1%
C 26.9%
CMake 0.4%
Zig 0.2%
Other 0.1%