CGNvim is a simple and modern Neovim >= 0.11 configuration for game and computer graphics development environment (e.g., Unity game engine or C++ game development/graphics, development using low-level graphics API).
Since this configuration is highly modular, you can simply see how certain functionalities are done (e.g., Roslyn LS C# LSP) and simply copy and integrate their config into you own Neovim config.
This configuration tries to provide a minimal set of plugins to approximate the usual game/graphics IDEs (e.g., Visual Studio).
- LSP completion/hints and linting support for: C# (Roslyn LS), C/C++ (clangd), Lua (lua-language-server), GLSL (glsl-analyzer). LSP is implemented using Neovim's >= 0.11 core LSP module.
- Detailed guide for integration with the Unity game engine
- Fast and lightweight default configuration
- Syntax highlighting using nvim-treesitter for: C#, C/C++, GLSL, HLSL, XML, YAML, etc.
- Formatting (and autoformatting on save) using conform.nvim for: C# (csharpier), Lua (stylua), C++, etc.
- Integrated terminal using toggleterm.nvim (togglable using:
<Space>tt) - Git integration using gitsigns.nvim
- Mnemonic keymaps that make sense (e.g.,
<Space>ttfor (t)oggle (t)erminal) - Lazy Neovim plugin management (i.e., plugins are only loaded when needed)
- 3rd party LSPs/formatters/DAPs are automatically handled by mason.nvim using lazy.nvim
- Clear project structure that is highly customizable and easily extensible:
- To add/edit a plugin, see Adding or Editing Plugins
- To add/edit a LSP, see Adding or Editing LSPs
- To add/edit a formatter, see Adding or Editing Formatters
- To add/edit a DAP, see Adding or Editing DAPs
- Debugging support using nvim-dap with sensible default configurations for: C/C++ (codelldb), Python (debugpy), C# (Unity)
- Attaching to the Unity debugger to debug editor/player instances (see neovim-unity for details)
For integration with the Unity game engine see this detailed guide: neovim-unity
.
├── init.lua --> loads the config: require("cgnvim")
├── LICENSE.txt
├── lua
│ └── cgnvim
│ ├── configs --> configs for plugins (maps 1-to-1 with ./plugins/)
│ │ ├── bufferline.lua
│ │ ├── ...
│ │ └── trouble.lua
│ ├── daps --> DAPs are added/configured here
│ │ ├── python.lua
│ │ ├── ...
│ │ └── unity.lua
│ ├── gautocmds.lua --> set of non-plugin-specific autocmd calls
│ ├── gmappings.lua --> set of non-plugin-specific mappings
│ ├── gsettings.lua --> set of non-buffer-specific settings and options
│ ├── gusercmds.lua --> set of non-plugin-specific user commands
│ ├── init.lua --> lsps setup, daps setups, lazynvim bootstrapping
│ ├── lsps --> LSPs are added/configured here
│ │ ├── clangd.lua
│ │ ├── ...
│ │ └── roslyn_ls.lua
│ └── plugins --> plugins to be managed by LazyNvim are added here
│ ├── bufferline.lua
│ ├── ...
│ └── trouble.lua
├── README.md
└── stylua.toml --> for lua formatting using StyLua
lua/cgnvim/plugins/ and lua/cgnvim/configs/ have a one-to-one
association where each file in lua/cgnvim/plugins/ denotes a plugin name
(usually <plugin-name>.lua) and describes how it should be fetched and loaded
by the LazeNvim plugin manager. The options passed to its LSP setup are defined
in a file of similar name in lua/cgnvim/configs/.
Each entry in lua/cgnvim/lsps/ denotes a specific LSP configuration that is usually copied from nvim-lspconfig/lsp and is loaded and enabled in lua/cgnvim/lspconfig.lua.
Most commently used keymaps are listed in a cheatsheet that is automatically updated in the releases page. Maybe print it out (using a laser printer ;-)) and keep it nearby (that's what I do - because I constantly forget keymaps).
Getting a LSP to work properly (especially in the case of C# with Unity) can be a daunting task. I have spent a significant amount of time tinkering with different LSPs for C# on Linux. Omnisharp is simply not usable, any mid-sized Unity projects can cause memory consumption of up-to 20GBs or more (very probably due to a severe memory leakage problem).
The relatively new Roslyn Language Server seems to perform better, but there are a couple of caveats that one has to be aware of.
In case you get System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached. in the LSP log (accessible
in the filesystem at :lua =require('vim.lsp.log').get_filename()) then
you have to increase the maximum number of file descriptors that can be opened
by a process:
echo fs.inotify.max_user_instances=4096 | sudo tee -a /etc/sysctl.conf && sudo sysctl -pIn case you get Undefined reference warnings/errors in the LSP log, you have
to run dotnet restore in your solution/project root directory:
dotnet restore "<unity-project-name>.sln"It is important to note that LSPs can be quite verbose and a lot of errors and
warnings can be safely ignored. This is the case with Roslyn LS, a lot of
Unresolved references can be simply ignored (hence why its logger level is set
to ERROR).
Plugins are managed by lazy.nvim and are automatically loaded from lua/cgnvim/plugins/ where each file corresponds to a plugin.
To add a new plugin:
-
create a new lua file at
lua/cgnvim/plugins/<plugin-name>.luaand add the LazyNvim configuration for it. For example:return { "<plugin-github-repo>/<plugin-name>.nvim", lazy = false, version = "*", -- plugin's setup options are loaded from a file of similar name in lua/cgnvim/configs/ -- this makes plugin configurations that are frequently changed in a single -- convenient location opts = function() return require("cgnvim.configs.<plugin-name>") end, ..., -- other LazyNvim configurations }
-
for a consistent configuration, create a new lua file (with same name as in lua/cgnvim/plugins/) at
lua/cgnvim/configs/<plugin-name>.luaand define your plugin setup options there:return { -- here goes plugin setup options }
-
restart Neovim and check the command
:Lazyto see if your plugin has successfully been added
LSPs are enabled in lua/cgnvim/init.lua and their configurations live in lua/cgnvim/lsps/
To add a new LSP, say a LSP for Python files (e.g., ruff):
-
create a new lua file under the path lua/cgnvim/lsps/ruff.lua and define the LSP client configuration in it as follows (it is usually copied from: nvim-lspconfig/lsps):
return { -- LSP client configuration following: https://neovim.io/doc/user/lsp.html#vim.lsp.ClientConfig -- you usually copy this configuration from https://github.com/neovim/nvim-lspconfig/tree/master/lsp -- and adjust it accordingly (e.g., by changing the LSP cmd) cmd = { "ruff" }, filetypes = { "py" }, root_markers = { ".git" } -- etc ... }
-
(optionally) for automatic installation and management of your LSP by Mason, if it is available in Mason (check command
:Mason), then navigate to lua/cgnvim/configs/mason-tool-installer.lua:-- a list of all tools you want to ensure are installed upon start by Mason ensure_installed = { ..., -- other lsps/formatters/linters { "ruff", auto_update = true }, }
-
restart Neovim and open a file that can trigger the LSP (in this example, a Python file). Check
:LspInfoto see if your LSP configuration is there and a LSP client is successfully attached. Check:LspLogfor LSP logs.
To remove a LSP, navigate to lua/cgnvim/lsps/ and remove the
corresponding LSP entry. Navigate to lua/cgnvim/configs/mason-tool-installer.lua
and remove the plugin from ensure_installed table in case it is there.
To disable a LSP without removing its configuration, navigate to lua/cgnvim/init.lua
then add the lsp name (same as in lua/cgnvim/lsps/ but without the lua extension) to
the lsp_ignore table.
Formatting is managed by the conform.nvim plugin in addition to mason-tool-installer.nvim for automatic installation by mason.nvim.
To add a new formatter, say a formatter (e.g., prettierd) for Javascript files:
-
navigate to lua/cgnvim/configs/conform.lua and add the formatter to
formatters_by_ft:-- add new formatters here (also add them in ./mason-tool-installer.lua for automatic installation by Mason) formatters_by_ft = { ..., -- other formatters javascript = { "prettierd", stop_after_first = true }, },
Here we are assuming the command
prettierdis globally accessible (see next point) -
(optionally) for automatic installation and management of your formatter by Mason, if it is listed in Mason (check command
:Mason), then navigate to lua/cgnvim/configs/mason-tool-installer.lua and add it as an entry inensure_installed:-- a list of all tools you want to ensure are installed upon start by Mason ensure_installed = { ..., -- other lsps/formatters/linters { "prettierd", auto_update = true }, }
-
restart Neovim. Check
:ConformInfoand see if your formatter is ready. Otherwise check:Masonto see if your formatter is installed. Try to open a file with the right extension and format it (either by format on write using:w, or using:lua require("conform").format({ async = true }))
Debug adapters (DA)s are enabled in lua/cgnvim/init.lua and their configurations live in lua/cgnvim/daps/.
To add a new DA, say a DA for javascript/Firefox:
-
install the DA and the debugger (both may reside in the same executable). In this case, the debugger is already integrated within Firefox. You just have to install the DA (e.g., vscode-firefox-debug).
-
create a new lua file under the path
lua/cgnvim/lsps/firefox.luaand define the DA configuration in it as follows (it is usually copied and adjusted from: nvim-dap configs):local dap = require('dap') dap.adapters.firefox = { type = 'executable', command = 'node', -- command to launch the DA -- path to the DA node package (and other optional args) args = {os.getenv('HOME') .. '/path/to/vscode-firefox-debug/dist/adapter.bundle.js'}, } -- make sure not to override other typescript DAP configs if dap.configurations.python == nil then dap.configurations.python = {} end -- do NOT overwrite the Language configuration as multiple DAs may add multiple configurations for the same -- ft (e.g., Chrome debug adapter may already have an entry in the table dap.configurations.typescript) table.insert(dap.configurations.typescript, { -- mandatory options expected by nvim-dap name = 'Debug with Firefox', type = 'firefox', request = 'launch', -- options below are debug-adapter specific reAttach = true, url = 'http://localhost:3000', webRoot = '${workspaceFolder}', -- adjust Firefox path accordingly if necessary firefoxExecutable = '/usr/bin/firefox' })
-
(optionally) for automatic installation and management of your DA by Mason, if it is available in Mason (check command
:Mason), then navigate to lua/cgnvim/configs/mason-tool-installer.lua-- a list of all tools you want to ensure are installed upon start by Mason ensure_installed = { ..., -- other lsps/formatters/linters { "<your-da-name>", auto_update = true }, }
in the case of vscode-firefox-debug, it is not available in Mason (at least officially) and has to be installed manually.
-
restart Neovim and start debugging a Javascript file. Check the
:DapShowLogcommand output for any potential issues.
- Support large files (usually JSON files that are too large completely
crash Neovim because of treesitter and/or LSP)
- Disable Treesitter for large files (e.g., >= 128KBs)
- Disable LSP for large files (e.g., 32KBs)
- Add Yaml highlighting and formatting support (IMPORTANT)
- Add snippets completion (OPTIONAL)
- Add a minimal spell checker (OPTIONAL)
- Add OpenGL completion (from https://github.com/vurentjie/cmp-gl)
MIT License. Read license.txt file.
