Previously, `make lint` would invoke `lintcommit` which would fail if there were fixup or other disallowed commits. This would disrupt local development as developers would often want non-commit linting to work early on without needing to adhere to the strict commit rules.
15 KiB
Contributing to Neovim
Getting started
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
Reporting problems
- 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.
Developer guidelines
- 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
orsccache
for faster rebuilds of Nvim. Nvim will use one of these automatically if it's found. To disable caching use:cmake -B build -D CACHE_PRG=OFF
Pull requests (PRs)
- 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.
Merging to master
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).
Stages: Draft and Ready for review
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.
Commit messages
Follow the conventional commits guidelines to make reviews easier and to make
the VCS/git logs more valuable (try make lintcommit
). 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.
Automated builds (CI)
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
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
Sanitizers (ASAN and UBSAN)
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.
Coding
Lint
You can run the linter locally by:
make lint
Style
- 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
Navigate
-
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.
Includes
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.
Lua runtime files
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
Documentation
Read :help dev-doc to understand the expected documentation style and conventions.
Generating :help
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.
Lua docstrings
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
.
Third-party dependencies
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
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.