+++ Updated for UE 5.1 (see bottom)
For autocompletion there are two options:
In my experience, coc is easier to set up. If you want to get started as quickly as possible, this is your best bet.
- Install coc.vim, e.g. with vim-plug inside
.vimrc
:Plug 'neoclide/coc.nvim'
- Run
:CocInstall coc-clangd
You will likely have to familiarize yourself with coc's shortcuts first or customize it as you see fit.
Setting up LSP takes a bit of time but for those that already have it up and running, there is probably not much to do. To keep this short, I will not explain the setup process. However, feel free to copy my Neovim config from my dotfiles. I have also set up some extra features for clangd in my config, if you are interested. If you wish to start from sratch, check out the server configuration for clangd and the completion plugin nvim-cmp as a starting point.
No matter which option you pick, you must do the following steps first:
- In UE
- go to
Edit - Editor Preferences - General - Source Code - Source Code Editor
and selectVisual Studio Code
- go to
File - Refresh Visual Studio Code Project
for UE4 orTools - Refresh Visual Studio Code Project
for UE5
- go to
- Create a symlink from your project's root directory to
myProject/.vscode/compileCommands_myProject.json
ln -s .vscode/compileCommands_myProject.json compile_commands.json
If you open your project in (Neo)vim and you are greeted by tons of error messages after you have successfully set up either coc or lsp, you might have to modify your compile_commands.json
. For this purpose, I have created a file called clang-flags.txt
that contains a bunch of compile flags which improve the experience drastically. The files look like this:
-std=c++20
-ferror-limit=0
-Wall
-Wextra
-Wpedantic
-Wshadow-all
-Wno-unused-parameter
Yes, C++20 is not even supported by UE, yet this got rid of many false error messages.
Now you need to modify your compile_commands.json
to use clang-flags.txt
. Using (Neo)vim to modify the file is easy but making a little script to automate this process is probably worth it in the long run. Add @/path/to/my/clang-flags.txt
after clang++
.
{
"file": "/home/User/MyGame/Plugins/UEGitPlugin/Source/GitSourceControl/Private/GitSourceControlMenu.cpp",
"command": "clang++ @/path/to/my/clang-flags.txt /home/User/MyGame/Plugins/UEGitPlugin/Source/GitSourceControl/Private/GitSourceControlMenu.cpp @/home/User/MyGame/.vscode/compileCommands_MyGame/GitSourceControl.4.rsp",
"directory": "/home/User/unrealengine/Engine/Source"
},
Make sure that all command
entries also contain the respective file that is supposed to be compiled. Above we are trying to compile GitSourceControlMenu.cpp
, so its path should be added after clang-flags.txt
and before the rsp
file. This procedure has to be done for all .h
and .cpp
files. I highly recommend any type of automation for this process via some simple scripts. At least under UE5, I don't need to do this manually anymore. I regenerate this file regularly using ue4-cli's ue4 gen
command.
Another option to eliminate false error messages is using your own clang instead of the one that UE ships with by default. Clang 14 is working well for me. All you need to do is to remove the path before clang++
as shown in the code snippet above. To check if everything is working, simply run the command
entry of some arbitrary file in your terminal. You might still get some errors but for the most part you should see a relatively lengthy compilation process. This is also equivalent to the time it will take until you get any completion results inside of (Neo)vim.
Feel free to use this little code snippet to fix-up your compile database (it requires ue4-cli
, more about it down below):
#!/usr/bin/env bash
ue_path=$(ue4 root | tail -1)
target="clang++ @'$(pwd)/clang-flags.txt'"
sed -i -e "s,$ue_path\(.*\)clang++,$target,g" compile_commands.json
However, this code won't add headers and source files to your compile database in case they are missing.
- Install vimspector, e.g.
Plug 'puremourning/vimspector'
- Configure debugging vimspector keybinds or simply add
let g:vimspector_enable_mappings = 'HUMAN'
to your.vimrc
. - Create a
.vimspector.json
inside of your project's root directory (simply refer to the myProjectEditor (DebugGame) entry inmyProject/.vscode/launch.json
), e.g.
{
"configurations": {
"Launch": {
"adapter": "vscode-cpptools",
"configuration": {
"request": "launch",
"program": "/path/to/UnrealEngine/Engine/Binaries/Linux/UE4Editor-Linux-DebugGame",
"args": [ "/path/to/myProject/myProject.uproject" ],
"cwd": "/path/to/UnrealEngine",
"externalConsole": true,
"MIDebuggerPath": "/usr/bin/gdb",
"MIMode": "gdb"
}
}
}
}
- Compile a debug build
path/to/UnrealEngine/Engine/Build/BatchFiles/Linux/Build.sh myProject Linux DebugGame '/path/to/myProject/myProject.uproject' -waitmutex
- Set a breakpoint (F9) and start debugging (F5) in Vim and your project will open in a new instance for debugging.
If you just wish to compile your project refer to the following entries in myProject/.vscode/tasks.json
:
path/to/UnrealEngine/Engine/Build/BatchFiles/Linux/Build.sh myProject Linux Development '/path/to/myProject/myProject.uproject' -waitmutex
For anything else building and debugging-related simply refer to tasks.json
and launch.json
in myProject/.vscode
.
I am currently trying to set up nvim-dap for Neovim. As soon as it's working, I will add the instructions here.
I highly recommend using ue4-cli. This application is primarily used for compiling your project from the terminal but it can do a bunch of other neat things like running automation tests, generating IDE project files, cleaning your build files, and even packaging your build. It also works for UE5 if you set the engine path manually (at the time of writing, this is still a bug). I have also defined a function in my .zshrc
to act as a wrapper for ue4-cli. Feel free to use this for some more inspiration.
# Expand ue4cli
ue() {
ue4cli=$HOME/.local/bin/ue4
engine_path=$($ue4cli root)
# cd to ue location
if [[ "$1" == "engine" ]]; then
cd $engine_path
# combine clean and build in one command
elif [[ "$1" == "rebuild" ]]; then
$ue4cli clean
$ue4cli build
if [[ "$2" == "run" ]]; then
$ue4cli run
fi
# build and optionally run while respecting build flags
elif [[ "$1" == "build" ]]; then
if [[ "${@: -1}" == "run" ]]; then
length="$(($# - 2))" # Get length without last param because of 'run'
$ue4cli build ${@:2:$length}
$ue4cli run
else
shift 1
$ue4cli build "$@"
fi
# Run project files generation, create a symlink for the compile database and fix-up the compile database
elif [[ "$1" == "gen" ]]; then
$ue4cli gen
project=${PWD##*/}
ln -s ".vscode/compileCommands_${project}.json" compile_commands.json
replace_string="clang++ @'$(pwd)/clang-flags.txt'"
sed -i -e "s,$engine_path\(.*\)clang++,$replace_string,g" compile_commands.json
# Generate ctags for project and optionally the engine itself with `ue ctags` and `ue ctags engine` respectively.
elif [[ "$1" == "ctags" ]]; then
if [[ "$2" == "engine" ]]; then
echo "Generating ctags database for unreal engine"
ctags -R --c++-kinds=+p --fields=+iaS --extras=+q --languages=C++ "$engine_path/Engine/Source"
echo "Generation completed."
fi
echo "Generating ctags database in current directory ..."
ctags -R Source
echo "Generation completed."
# Pass through all other commands to ue4
else
$ue4cli "$@"
fi
}
alias ue4='echo Please use ue instead.'
alias ue5='echo Please use ue instead.'
Navigating engine source code is not possible with coc or lsp because it would require a compile database of the engine. While I was able to generate one with the command below, I couldn't get it to work after all. Any help with this would be highly appreciated.
./Engine/Build/BatchFiles/Linux/Build.sh MyProjectName Linux Development '/path/to/myProject/myProject.uproject' -mode=GenerateClangDatabase
However, there is another solution: ctags. Simply install universal-ctags
(e.g. with your package manager) and run the following command:
ctags -R --c++-kinds=+p --fields=+iaS --extras=+q --languages=C++ /path/to/your/unrealengine/Engine/Source
When the cursor is over a symbol that was found by ctags, Ctrl+] will let you jump to the tag using the newly generated tags
file. I usually run the command above in my project's root directory, so that no additional configuration is required for (N)vim to find the file.
Yes, you can even get static analysis in your code. All you need is a file named .clang-tidy
in your project's root directory. Creating this file was quite the hassle since a lot of the tests that clang-tidy runs just don't make any sense when working with Unreal Engine and trying to follow the guidelines. As a starting point, you can use my version:
---
Checks: 'clang-diagnostic-*,misc-*,readability-*,bugprone-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-readability-avoid-const-params-in-decls,-misc-unused-parameters,-readability-named-parameter,-readability-magic-numbers,-misc-non-private-member-variables-in-classes,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-avoid-magic-numbers,-modernize-use-auto,-cppcoreguidelines-pro-type-union-access,-bugprone-easily-swappable-parameters'
WarningsAsErrors: false
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: google
CheckOptions:
- key: cert-dcl16-c.NewSuffixes
value: 'L;LL;LU;LLU'
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
value: '0'
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
value: '1'
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
...
Consider using a .clang-format
to automatically format your code in all of your projects. This one is probably the best you can find online. Simply place it in your project's root directory.
One thing I disliked about having .clang-format
in the root directory is that it would format everything, including the Plugins
folder. As a quick workaround, I put the following .clang-format
in the Plugins
folder:
DisableFormat: true
SortIncludes: false
The steps above still work after recompiling the engine. However, you have to clean build and delete both .vscode
and compile_commands.json
before running my custom ue gen
override. Also make sure to adjust the respective line with the sed
command to replace_string="clang++\"\,\n\t\t\t\"@$(pwd)/clang-flags.txt\"\,"
.
If you are on Arch and experience long loading times when starting the editor (UE4 only) follow the instructions on the Arch Wiki. It really makes a difference.
Let me know if you have any suggestions or ideas to make UE development in (Neo)vim even better.
OS - Arch Linux VIM - Vi IMproved 8.2 NVIM - 0.7.2 coc.nvim - 0.0.80 clangd - 12.0.1 Unreal - 4.28 Vimspector - Build 1284234985
This problem seems fixed in this pull request. https://github.com/EpicGames/UnrealEngine/pull/10731.