Skip to content
/ CGNvim Public

(C)omputer (G)raphics (N)eo(vim): Lightweight Neovim Configuration for Computer Graphics Development Environments

License

Notifications You must be signed in to change notification settings

walcht/CGNvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

Note

WORK IN PROGRESS PROJECT!

CGNvim is a simple and modern Neovim >= 0.11 configuration for game and computer graphics development environment (e.g., Unity game engine, C++ game development, development using low-level graphics API etc.).

Features

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>tt for (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:
  • Debugging support using [nvim-dap][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)

Unity Game Engine

For integration with the Unity game engine see this detailed guide: neovim-unity

Project Structure

.
├── 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.

Default Keymaps Overview

To list all the defined and default keymaps, enter the command :map (or for a better output :Telescope keymaps ). CGNvim tries to simplify the memorization of keymaps by relying on mnemonics.

The main keymaps that contribute the most at simplifying the usual workflow are listed below (<leader> is <Space> unless the default configuration is changed).

General Keymaps

Keymap Mode Short Description Detailed Description
<leader>tt n (t)oggle (t)erminal toggle the integrated terminal
<leader>ex n toggle file (ex)plorer toggle the NvimTree file explorer
<leader>rw n (r)ename (w)ord rename all occurences of the word under cursor in current buffer
<leader>ts n,v,x (t)oggle (s)pell toggle spell checking for current buffer
<leader>ss n (s)pell (s)uggest show Telescope's spell suggestion for the word under the cursor
<leader>tr n,v,x (t)oggle (r)elative line numbering toggle relative line numbering (default: off)
<leader>d n,v,x (d)elete to void register (d)elete to void register (without copying). Vim's default delete overwrites the content of the register
<leader>y n,v,x (y)ank to system clipboard copy (yank) to system clipboard. Might require an external package for support on Wayland
J x move selected line(s) down(J)
K x move selected line(s) up(K)
J n append line below to current line

Window Navigation and Resizing Keymaps

Keymap Mode Short Description
<C-h> n move to left(h) window
<C-j> n move to down(j) window
<C-k> n move to up(k) window
<C-l> n move to right(l) window
<C-Up> n resize window size (Up)wards
<C-Down> n resize window size (Down)wards
<C-Left> n resize window size (Left)wards
<C-Right> n resize window size (Right)wards
<S-l> n navigate to right(l) buffer
<S-h> n navigate to left(h) buffer

File Explorer Keymaps

Only keymaps that are considered important are listed

Keymap Mode Short Description
g? n (g)o to help(?) window to show keymaps
v<CR> n open() (v)ertically
a n (a)ppend/create file/folder
y n (y)ank basename to system clipboard
Y n (Y)ank file/directory absolute path
c n copy file (c)ontent
d n (d)elete file/directory
r n (r)ename file/directory
Tab n preview file/expand directory
K n show file metadata info
. n run command on current(.) entry
<leader>tg n (t)oggle (g)itignore filter
<leader>td n ((t)oggle (d)otfiles filter

Formatting Keymaps

Keymap Mode Short Description Detailed Description
fb n (f)ormat (b)uffer format current buffer according to conform.nvim config
<C-I> n same as fb VSCode formatting shortcut

Git Keymaps

Keymap Short Description Detailed Description
<leader>gsb (g)it (s)tage (b)uffer stage the whole current buffer
<leader>grb (g)it (r)eset (b)uffer reset the whole current buffer
<leader>gph (g)it (p)review (h)unk highlight hunk under cursor if a hunk is present
<leader>gsh (g)it (s)tage (h)unk stage hunk under cursor if a hunk is present
<leader>grh (g)it (r)eset (h)unk reset hunk under cursor if a hunk is present
]h next (h)unk ([ on the right) navigate to next hunk
[h prev (h)unk ([ on the left) navigate to previous hunk
<leader>gdv (g)it (d)iff (v)iew show git diff view for current buffer
<leader>gtb (g)it (t)oggle (b)lame toggle git blame for current line under cursor

Diagnostics Keymaps

Keymap Short Description Detailed Description
]d next(]) (d)iagnostics navigate to next diagnostics
[d prev([) (d)iagnostics navigate to previous diagnostics
<leader>vt toggle (v)irtual (t)ext diagnostics toggle virtual text diagnostics. Shows diagnostics at the right of the corresponding line using virtual text
<leader>vl toggle (v)irtual (l)ines diagnostics toggle virtual lines diagnostics. Uses multiple virtual lines under the corresponding line to show diagnostics. Better than virtual text diagnostics but consumes more visual space (i.e., adds a lot of lines on hover).
<leader>ed (e)xplain (d)iagnostics explain diagnostics under cursor
<leader>ql (q)uickfix (l)ist toggles the quickfix list window
<leader>bd (b)uffer (d)iagnostics toggle Trouble's buffer (local) diagnostics window
<leader>gd (g)lobal (d)iagnostics toggle Trouble's global diagnostics window

LSP Keymaps

Keymap Short Description Detailed Description
K show LSP (K)ownledge LSP hover information about symbol under cursor
KK (K)indly jump to LSP (K)ownledge jumps to LSP hover information window about symbol under cursor
gd (g)o (d)efinition go to the definition of the symbol under cursor
gi (g)o (i)mplementation go to the implmentation of the symbol under cursor
gD (g)o (D)eclaration go to the declaration of the symbol under cursor
gr (g)o (r)eferences go to the references of symbol under cursor
<leader>ih (i)nlay (h)ints toggle LSP inlay hints. E.g., uses virtual text to show parameter names)
<leader>ca (c)ode (a)ction list code actions available for symbol under cursor
<leader>rs (r)ename (s)ymbol rename symbol under the cursor and all of its references using LSP

Debugging Keymaps

Keymap Short Description
<leader>dc (d)ebugger (c)ontinue/start
<leader>db (d)ebugger toggle (b)reakpoint
<leader>do (d)ebugger step (o)ver
<leader>di (d)ebugger step (i)nto
<leader>dO (d)ebugger step (O)ut
F5 same as <leader>dc
F10 same as <leader>do
F11 same as <leader>di
F12 same as <leader>dO

Potential LSP Issues

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.

C# LSP (Roslyn Language Server)

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 -p

In 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).

Adding or Editing Plugins

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:

  1. create a new lua file at lua/cgnvim/plugins/<plugin-name>.lua and 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
    }
  2. for a consistent configuration, create a new lua file (with same name as in lua/cgnvim/plugins/) at lua/cgnvim/configs/<plugin-name>.lua and define your plugin setup options there:

    return {
      -- here goes plugin setup options
    }
  3. restart Neovim and check the command :Lazy to see if your plugin has successfully been added

Adding or Editing LSPs

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):

  1. 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 ...
    }
  2. (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 },
    }
  3. restart Neovim and open a file that can trigger the LSP (in this example, a Python file). Check :LspInfo to see if your LSP configuration is there and a LSP client is successfully attached. Check :LspLog for LSP logs.

Removing or Disabling LSPs

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.

Adding or Editing Formatters

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:

  1. 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 prettierd is globally accessible (see next point)

  2. (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 in ensure_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 },
    }
  3. restart Neovim. Check :ConformInfo and see if your formatter is ready. Otherwise check :Mason to 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 }))

Adding or Editing DAs

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:

  1. 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).

  2. create a new lua file under the path lua/cgnvim/lsps/firefox.lua and 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'
    })
  3. (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.

  4. restart Neovim and start debugging a Javascript file. Check the :DapShowLog command output for any potential issues.

TODOs

  • Add Godot game engine integration (IMPORTANT)
  • Add Unreal Engine integration (IMPORTANT)
  • 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 script for the generation of single-page PDF overview of keymaps (IMPORTANT)
  • 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)

License

MIT License. Read license.txt file.

About

(C)omputer (G)raphics (N)eo(vim): Lightweight Neovim Configuration for Computer Graphics Development Environments

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages