If you want to help but don't know where to start, here are some low-risk/isolated tasks:
- Try a complexity:low issue.
- Fix bugs found by Clang or Coverity.
- Merge a Vim patch (requires strong familiarity with Vim)
- NOTE: read the above link before sending improvements to "runtime files" (anything in
runtime/
).- Vimscript and documentation files are (mostly) maintained by Vim, not Nvim.
- Lua files are maintained by Nvim.
- NOTE: read the above link before sending improvements to "runtime files" (anything in
- Check the FAQ.
- Search existing issues (including closed!)
- Update Neovim to the latest version to see if your problem persists.
- Try to reproduce with
nvim --clean
("factory defaults"). - Bisect your config: disable plugins incrementally, to narrow down the cause of the issue.
- Bisect Neovim's source code to find the cause of a regression, if you can. This is extremely helpful.
- When reporting a crash, include a stacktrace.
- Use ASAN/UBSAN to get detailed errors for segfaults and undefined behavior.
- Check the logs.
:edit $NVIM_LOG_FILE
- Include
cmake --system-information
for build-related issues.
- Read :help dev and :help dev-doc if you are working on Nvim core.
- Read :help dev-ui if you are developing a UI.
- Read :help dev-api-client if you are developing an API client.
- Install
ninja
for faster builds of Nvim.sudo apt-get install ninja-build make distclean make # Nvim build system uses ninja automatically, if available.
- Install
ccache
for faster rebuilds of Nvim. Nvim will use it automatically if it's found. To disable caching use:CCACHE_DISABLE=true make
- To avoid duplicate work, create a draft pull request.
- Your PR must include test coverage.
- Avoid cosmetic changes to unrelated files in the same commit.
- Use a feature branch instead of the master branch.
- Use a rebase workflow for all PRs.
- After addressing review comments, it's fine to force-push.
For maintainers: when a PR is ready to merge to master,
- prefer Squash Merge for "single-commit PRs" (when the PR has only one meaningful commit).
- prefer Merge for "multi-commit PRs" (when the PR has multiple meaningful commits).
Pull requests have two stages: Draft and Ready for review.
- Create a Draft PR while you are not requesting feedback as
you are still working on the PR.
- You can skip this if your PR is ready for review.
- Change your PR to ready when the PR is ready for review.
- You can convert back to Draft at any time.
Do not add labels like [RFC]
or [WIP]
in the title to indicate the
state of your PR: this just adds noise. Non-Draft PRs are assumed to be open
for comments; if you want feedback from specific people, @
-mention them in
a comment.
Follow the conventional commits guidelines to make reviews easier and to make the VCS/git logs more valuable. The general structure of a commit message is:
<type>([optional scope]): <description>
[optional body]
[optional footer(s)]
- Prefix the commit subject with one of these types:
build
,ci
,docs
,feat
,fix
,perf
,refactor
,revert
,test
,vim-patch
- You can ignore this for "fixup" commits or any commits you expect to be squashed.
- Append optional scope to type such as
(lsp)
,(treesitter)
,(float)
, … - Description shouldn't start with a capital letter or end in a period.
- Use the imperative voice: "Fix bug" rather than "Fixed bug" or "Fixes bug."
- Try to keep the first line under 72 characters.
- A blank line must follow the subject.
- Breaking API changes must be indicated by
- "!" after the type/scope, and
- a "BREAKING CHANGE" footer describing the change.
Example:
refactor(provider)!: drop support for Python 2 BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported.
High level release notes are maintained in news.txt. A PR is not required to add a news item but is generally recommended.
Each pull request must pass the automated builds on Cirrus CI and GitHub Actions.
- CI builds are compiled with
-Werror
, so compiler warnings will fail the build. - If any tests fail, the build will fail. See test/README.md#running-tests to run tests locally.
- CI runs ASan and other analyzers.
- To run valgrind locally:
VALGRIND=1 make test
- To run ASan/UBSan locally:
CC=clang make CMAKE_FLAGS="-DENABLE_ASAN_UBSAN=ON"
. Note that MSVC requires Release or RelWithDebInfo build type to work properly.
- To run valgrind locally:
- The lint build checks that the code is formatted correctly and passes various linter checks.
- CI for FreeBSD runs on Cirrus CI.
- To see CI results faster in your PR, you can temporarily set
TEST_FILE
in test.yml.
View the Clang report to see potential bugs found by the Clang scan-build analyzer.
- Search the Neovim commit history to find examples:
git log --oneline --no-merges --grep clang
- To verify a fix locally, run
scan-build
like this:rm -rf build/ scan-build --use-analyzer=/usr/bin/clang make
Coverity runs against the master build. To view the defects, just request access; you will be approved.
- Use this format for commit messages (where
{id}
is the CID (Coverity ID); (example)):fix(coverity/{id}): {description}
- Search the Neovim commit history to find examples:
git log --oneline --no-merges --grep coverity
ASAN/UBSAN can be used to detect memory errors and other common forms of undefined behavior at runtime in debug builds.
- To build Neovim with sanitizers enabled, use
rm -rf build && CMAKE_EXTRA_FLAGS="-DCMAKE_C_COMPILER=clang -DENABLE_ASAN_UBSAN=1" make
- When running Neovim, use
ASAN_OPTIONS=log_path=/tmp/nvim_asan nvim args...
- If Neovim exits unexpectedly, check
/tmp/nvim_asan.{PID}
(or your preferredlog_path
) for log files with error messages.
You can run the linter locally by:
make lint
- You can format files by using:
This will format changed Lua and C files with all appropriate flags set.
make format # or formatc, formatlua
- Style rules are (mostly) defined by
src/uncrustify.cfg
which tries to match the style-guide. To use the Nvimgq
command withuncrustify
:if !empty(findfile('src/uncrustify.cfg', ';')) setlocal formatprg=uncrustify\ -q\ -l\ C\ -c\ src/uncrustify.cfg\ --no-backup endif
- There is also
.clang-format
which has drifted from the style-guide, but is available for reference. To use the Nvimgq
command withclang-format
:if !empty(findfile('.clang-format', ';')) setlocal formatprg=clang-format\ -style=file endif
-
Set
blame.ignoreRevsFile
to ignore noisy commits in git blame:git config blame.ignoreRevsFile .git-blame-ignore-revs
-
Recommendation is to use clangd. Can use the maintained config in nvim-lspconfig/clangd.
-
Explore the source code on the web.
For managing includes in C files, use include-what-you-use.
- Install include-what-you-use
- To see which includes needs fixing use the cmake preset
iwyu
:cmake --preset iwyu cmake --build build
- There's also a make target that automatically fixes the suggestions from
IWYU:
make iwyu
See #549 for more details.
Most of the Lua core runtime/
modules are precompiled to
bytecode, so changes to those files won't get used unless you rebuild Nvim or
by passing --luamod-dev
and $VIMRUNTIME
. For example, try adding a function
to runtime/lua/vim/_editor.lua
then:
VIMRUNTIME=./runtime ./build/bin/nvim --luamod-dev
Read :help dev-doc to understand the expected documentation style and conventions.
Many :help
docs are autogenerated from (C or Lua) docstrings. To generate the documentation run:
make doc
If you need to modify or debug the documentation flow, these are the main files:
./scripts/gen_vimdoc.py
: Main doc generator. Drives doxygen to generate xml files, and scrapes those xml files to render vimdoc files../scripts/lua2dox.lua
: Used bygen_vimdoc.py
to transform Lua files into a format compatible with doxygen../scripts/gen_eval_files.lua
: Generates documentation and Lua type files from metadata files:runtime/lua/vim/* => runtime/doc/lua.txt runtime/lua/vim/* => runtime/doc/lua.txt runtime/lua/vim/lsp/ => runtime/doc/lsp.txt src/nvim/api/* => runtime/doc/api.txt src/nvim/eval.lua => runtime/doc/builtin.txt src/nvim/options.lua => runtime/doc/options.txt
Use LuaLS annotations in Lua docstrings to annotate parameter types, return types, etc. See :help dev-doc-lua.
- The template for function documentation is:
--- {Brief} --- --- {Long explanation} --- --- @param arg1 type {description} --- @param arg2 type {description} --- ... --- --- @return type {description}
- If possible, add type information (
table
,string
,number
, ...). Multiple valid types are separated by a bar (string|table
). Indicate optional parameters viatype|nil
. - If a function in your Lua module should not be documented, add
@nodoc
. - If the function is internal or otherwise non-public add
@private
. - Private functions usually should be underscore-prefixed (named "_foo", not "foo"). - Mark deprecated functions with
@deprecated
.
Reviewing can be done on GitHub, but you may find it easier to do locally. Using GitHub CLI, you can create a new branch with the contents of a pull request, e.g. #1820:
gh pr checkout https://github.com/neovim/neovim/pull/1820
Use git log -p master..FETCH_HEAD
to list all
commits in the feature branch which aren't in the master
branch; -p
shows each commit's diff. To show the whole surrounding function of a change
as context, use the -W
argument as well.