en
8/17/2023
Configuring Neovim for Unity Development

I have been using Neovim as my main code editor for a while now. So I try to configure it to work with any coding project that I have to do. Configuring Neovim to work with something can take a while on it’s own, but I think it’s worth it in the long run since you get to learn more about to tools you use.

Anyways, this time I will write about how I managed to get C# language server, Omnisharp, to work with Neovim in Unity development. I have this configuration working on Linux, macOS, and Windows (Git Bash). At the time of writing, the versions of each components are as follows:

Neovim: v0.9.1
Unity Hub: v3.5.0 
Unity Editor: 2022.3.5f1
Omnisharp: v1.39.8

Operating Systems:
 - Arch Linux
 - macOS Ventura
 - Windows 10 22H2

Omnisharp

Omnisharp is a language server, when configured properly, it will send diagnostics and auto completion (IntelliSense) data to the editor. Omnisharp can be enabled in Visual Studio Code by installing the official C# extension, and needs a little bit of configuration for it to work with Unity (settings useModernNet to false). Since omnisharp is quite flexible, we can adapt it to work with other editors as well.

Mono

Mono is the framework that enables .NET development on platforms like Linux and macOS, we’ll need it to run Omnisharp on Linux and macOS. For Windows, native omnisharp can be used.

Prerequisites

Before diving into the configuration, let’s make sure the required software are installed. The main component needed to run Omnisharp is .NET SDK. You will also need mono and mono version of msbuild if you’re on Linux or macOS.

On Linux and macOS, to check if you have the required components installed, make sure these commands can be executed:

dotnet --version
msbuild --version
mono --version

Installation Instructions

If you’re using one of the distros/Operating Systems below, the following instructions can be used to install .NET SDK, mono, and mono version of msbuild.

Ubuntu

Since the mono version of msbuild isn’t in the default repository in Ubuntu, you will need to add the mono repository yourself. Follow the instructions at: https://www.mono-project.com/download/stable/

After you added the repository, the following command can be used to install the needed components:

apt install dotnet-sdk-7.0 mono-devel msbuild

Arch Linux

Luckily for Arch and Arch-based distribution, the needed components should be in the default repository. To install, run the following command:

pacman -S dotnet-sdk mono mono-msbuild

macOS

In macOS, dotnet and mono can be downloaded from the official sites.

https://dotnet.microsoft.com/download/

https://www.mono-project.com/

Windows

For Windows, make sure dotnet is executable in your editor. This can be done by installing .NET SDK then set up the Path environment variable.

The configuration

Assuming you have a working Neovim configuration with nvim-lspconfig and mason as the package manager, you can install omnisharp-mono from mason if you’re on macOS / Linux, and omnisharp if you’re on Windows (Git Bash)

Mono Omnisharp

Since nvim-lspconfig doesn’t support configuring omnisharp-mono installed from mason by default, we have to add it as a custom server. To do this, the following code can be used to add the custom server, note that this must be run before server configuration:

if not configs.omnisharp_mono then
  configs.omnisharp_mono = {
    default_config = {
      cmd = { 'omnisharp-mono', '--languageserver', '--hostPID', tostring(vim.fn.getpid()) },
      filetypes = { 'cs' },
      root_dir = lspconfig.util.root_pattern('*.csproj', '*.sln', '.git'),
      settings = {}
    }
  }
end

After the server is added, the following code can be used to set useModernNet to false, which is required for Unity development. In the code below, monoPath = vim.fn.system {'which', 'mono'} is also added to help set correct path for mono executable which also helps make the same config work on both macOS and Linux.

require'lspconfig'.omnisharp_mono.setup{
  settings = {
    useModernNet = false,
    monoPath = vim.fn.system { 'which', 'mono' }
  }
}

Native omnisharp (Windows)

Since native Omnisharp doesn’t require mono to function and omnisharp can be configured in nvim-lspconfig, the following config can be used to set useModernNet to false.

require'lspconfig'.omnisharp.setup{
  settings = {
    useModernNet = false
  }
}

Opening C# file in Neovim

For Omnisharp to start, the following conditions has to be met:

  • Neovim is opening a .cs file
  • .csproj exists in the project root

In case there are no .csproj files in project root, it can be regenerated in Unity in Preferences > External Tools > Regenerate project files. If configured properly, Omnisharp should run. However, give Omnisharp some time to start. From my experience, Omnisharp usually starts up after around 1-2 minutes. Please note that :LspInfo will show Omnisharp as other clients that match the filetype: cs until it is successfully attached.

Troubleshooting

omnisharp-mono not executable

It occured to me once that the run script from omnisharp-mono package has wrong permissions. To fix that, make the run script in /home/naborisk/.local/share/nvim/mason/packages/omnisharp-mono executable by running:

chmod +x ~/.local/share/nvim/mason/packages/omnisharp-mono/run

MonoBehavior not getting recognized

Make sure mono is executable in your PATH

Lastly

My full configuration can be found in my dotfiles repository. It took some effort to get Omnisharp working properly with Unity development, but being able to use the editor you’re used to in development is awesome! Though Omnisharp takes a moment to start up, Neovim starts up pretty fast

Made with by Naborisk