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:ff68fd6b8amoved 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>
Neovim is a project that seeks to aggressively refactor Vim in order to:
- Simplify maintenance and encourage contributions
- Split the work between multiple developers
- Enable advanced UIs without modifications to the core
- Maximize extensibility
See the Introduction wiki page and Roadmap for more information.
Features
- Modern GUIs
- API access from any language including C/C++, C#, Clojure, D, Elixir, Go, Haskell, Java/Kotlin, JavaScript/Node.js, Julia, Lisp, Lua, Perl, Python, Racket, Ruby, Rust
- Embedded, scriptable terminal emulator
- Asynchronous job control
- Shared data (shada) among multiple editor instances
- XDG base directories support
- Compatible with most Vim plugins, including Ruby and Python plugins
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 helplists all build targets.build/CMakeCache.txt(orcmake -LAH build/) contains the resolved values of all CMake variables.build/compile_commands.jsonshows 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.
