This document lists some general useful advice when working with C++ inside neovim. Some of the things described here are automated by the plugin. Appropriate admonitions are present in such cases.
This one can be a tough one for some. We are programmers, we love experimenting, inventing, fiddling and making things work.
Problem arises in certain situations, where the effort put in isn't worth the compensation. I get it, you love neovim, I love it too! But the first thing you need to understand is that not every tool is always bound for the job. Neovim with C++ is a good example of that, because while it may and will work for a lot of codebases, for some the language server, debugging capabilities or refactoring capabilities may simply be.. not enough.
This also applies to specific framework/tooling integrations. In more specialized areas like gamedev (UE), embedded, automotive or computer vision neovim may not offer the capabilities to integrate with existing tools and architecture.
Sure, you can still use it, but you have to really reflect on your choice and ask yourself if you're not wasting your time by being stubborn.
This is especially important in business. Your job as a programmer working for company is not writing pretty code or crafting beautiful data structures. It's also not jumping quickly between pieces of text and flexing your motions in front of colleagues. Your job as a programmer is to bring value and reduce costs.
If you use neovim for work and it hinders your ability to do that, because you waste time restarting your clangd, because it's always crashing in your massive codebase, because the dap/gdb integration is not nearly enough to debug your multi-threaded environment or you simply don't have a way to integrate with other tools and have to hop between them - you're costing business money.
This is not an attack, I'm not trying to make you feel shameful or stop you from trying to tailor your favourite editor for your job - but be aware that time is finite and there may be more sophisticated tools for the job.
The ability to not be a shill and a fanboy of certain technologies is a very important one for a programmer, especially one whose job is to bring business value.
Apart from having specialized editor integrations we should understand and maximize the usage of our existing tools.
Clangd integrates natively with clang-tidy, which is a static analysis tool for C++.
To enable the integration you have to pass in the --clang-tidy flag to clangd.
Note
cpp-tools.nvim does that automatically in its default configuration.
To configure clang-tidy, add a .clang-tidy file in your project root directory.
Available options can be explored by running clang-tidy --help (grep for Configuration files),
or by visiting The llvm clang-tidy releases docs (search for Configuration files as well).
Certain language servers offer a builtin formatting capability.
clangd does so, but it needs clang-format to be present in the environment.
Configuring clang-format involves creating a .clang-format file with specific formatting options: Clang-Format style options.
Listing and explaining them would be pointless, as the builtin --help command already does so very well.
I recommend to run clangd --help yourself to see what options are available, some of them are really useful.
Clangd, as most clang tools allows to create a global or project local configuration file which will further refine its actions.
To configure clangd, place a .clangd file in your project root directory and add your options there.
Available options are listed here
That typically means you haven't generated a compilation database.
It's a JSON file that maps each file to the command it was compiled with.
For CMake, you have to set the -DCMAKE_EXPORT_COMPILE_COMMANDS macro. Meson and certain other build systems generate it automatically.
If your build system doesn't support generating the compilation database, use bear.
If you're not on Nix, then try everything listed in the official Fixing missing system headers section.
If you're on Nix and any of the above don't work, you may be running into this issue.
The fix for that is setting an environment variable with the path to your clangd, and capturing it in your editor, then using it,
instead of clangd, in the command.
Note
cpp-tools.nvim automatically uses (os.getenv('CLANGD_PATH') or 'clangd')
This is how this would look like in Nix:
mkShell {
...
env.CLANGD_PATH = lib.getExe' pkgs.clang-tools_18 "clangd";
}This is due to the fact that these are guarded by special "feature test macros" of form __cpp_lib_x, __cpp_has_x, etc.
If you already have clangd configured you can go to definition on the header. It should be guarded by something akin to this:
#if __cplusplus > 202002L && __cpp_concepts >= 202002LIf you vim.lsp.buf.hover() on the respective macro names (usually the K keymap), you will see their values.
For example, currently, for me, on clangd 18.0.7 __cplusplus is defined as 201703, and __cpp_concepts doesn't exist at all.
If your compiler compiles your code fine, but clangd doesn't see these, there are two possible fixes:
- Point clangd to your compiler by appending the
--query=driver=<path globs>option to the commandline - If the above doesn't work, add or modify
.clangdfile in your project root directory with the following content:
CompileFlags:
Add: ['-D__cpp_concepts=202002'] # The exact flags and their values depend on the specific headers and typesUse the --completion-style with detailed value.
Note
cpp-tools.nvim does that automatically.
Use the --all-scopes-completion flag.
Note
cpp-tools.nvim does that automatically.
Use the --function-arg-placeholders flag.
Note
cpp-tools.nvim does that automatically.
Use the --header-insertion flag with the iwyu value.
Also use --head-insertion-decorators for clangd to prepend a dot for completions which will insert an include.
Note
cpp-tools.nvim does that automatically. It also offers a module which automatically and nicely sorts includes.
TBD.
TBD.