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 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.
- Nvim's filetype detection behavior matches Vim, so changes to filetype detection should be submitted to Vim first.
- 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"). - If a specific configuration or plugin is necessary to recreate the problem, use the minimal template in
contrib/minimal.lua
withnvim --clean -u contrib/minimal.lua
after making the necessary changes. - 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 structure of a commit message is:
type(scope): subject
Problem:
...
Solution:
...
- Commit message subject (you can ignore this for "fixup" commits or any commits you expect to be squashed):
- Prefix with a type:
build ci docs feat fix perf refactor revert test vim-patch
- Append an optional
(scope)
such as(lsp)
,(treesitter)
,(float)
, … - Use the imperative voice: "Fix bug" rather than "Fixed bug" or "Fixes bug."
- Keep it short (under 72 characters).
- Prefix with a type:
- Commit message body (detail):
- Concisely describe the Problem/Solution in the commit body. Describing the problem
independently of the solution often leads to a better understanding for you, reviewers, and future readers.
Problem: Solution:
- Concisely describe the Problem/Solution in the commit body. Describing the problem
independently of the solution often leads to a better understanding for you, reviewers, and future readers.
- Indicate breaking API changes with "!" after the type, and a "BREAKING CHANGE" footer. Example:
refactor(provider)!: drop support for Python 2 BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported.
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.
Coverity runs against the master build. To view the defects you must request access (Coverity does not have a "public" view), then you will be approved as soon as a maintainer sees the email.
- 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
To validate the documentation files, run:
make lintdoc
If you need to modify or debug the documentation flow, these are the main files:
-
./scripts/gen_vimdoc.lua
: Main doc generator. Parses C and Lua files to render vimdoc files. -
./scripts/luacats_parser.lua
: Documentation parser for Lua files. -
./scripts/cdoc_parser.lua
: Documentation parser for C files. -
./scripts/luacats_grammar.lua
: Lpeg grammar for LuaCATS -
./scripts/cdoc_grammar.lua
: Lpeg grammar for C doc comments -
./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
-
./scripts/lintdoc.lua
: Validation and linting of documentation files.
Use LuaLS annotations in Lua docstrings to annotate parameter types, return types, etc. See :help dev-lua-doc.
- 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
.
To build Nvim using a different commit of a dependency change the appropriate
URL in cmake.deps/deps.txt
. For example, to use a different version of luajit
replace the value in LUAJIT_URL
with the wanted commit hash:
LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/<sha>.tar.gz
Set DEPS_IGNORE_SHA
to TRUE
in cmake.deps/CMakeLists.txt
to skip hash
check from cmake.
Alternatively, you may point the URL as a local path where the repository is.
This is convenient when bisecting a problem in a dependency with git bisect
.
This may require running make distclean
between each build. Hash checking is
always skipped in this case regardless of DEPS_IGNORE_SHA
.
LUAJIT_URL /home/user/luajit
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.