Emacs as a .NET development environment
Bob was tempted to use an integrated development environment (IDE) to work on his .NET project, even though he’s heavily invested in Emacs. Fortunately, Alice knows a thing or two about .NET’s ecosystem and she brought up the idea of building one’s own environment, proposing that he combine the following tools:
- Eglot – a Language Server Protocol (LSP) client
- csharp-ls – a server implementation of LSP
Alice said to install[1] the .NET SDK to start off:
pacman -S dotnet-sdk
She told Bob to run dotnet --info
in the command-line to verify that the installation was successful.
Alice then insisted on adding the .NET tools directory onto the PATH
environment variable, so that when Bob finally installs csharp-ls, the binary will be available from anywhere on his system.
Since Bob is using zsh, he decided to put the following snippet in his .zshenv
, a file that is sourced every time the shell is instantiated.
PATH="$HOME/.dotnet/tools:$PATH"
export PATH
Alice, knowing how unnecessarily complicated it can be to install omnisharp, recommended csharp-ls instead which can be installed like so:
dotnet tool install --global csharp-ls
This time, Bob was told to run csharp-ls --version
in the command-line to verify that the tool was properly installed.
Bob’s almost there, he just needs to install and configure Eglot so that Emacs can learn to communicate the same language as any LSP server. Alice told him to type M-x package-install RET eglot RET
and give the package a second to install. Alice proceeded to explain that Eglot internally consults the eglot-server-programs
to check what LSP server it should use for a specific major mode.
Because languages don’t necessarily have a single LSP server implementation, meaning Eglot may not directly recognize every single one, she told Bob to add csharp-ls to that list like so:
(add-to-list 'eglot-server-programs
'(csharp-mode . ("csharp-ls")))
The next snippet instructs Eglot to automatically start in C# buffers:
(add-hook 'csharp-mode-hook 'eglot-ensure)
These functions may be combined and expressed as such:
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs
'(csharp-mode . ("csharp-ls")))
(add-hook 'csharp-mode-hook 'eglot-ensure))
And that roughly translates to this use-package
form:
(use-package eglot
:commands (eglot eglot-ensure)
:hook ((csharp-mode . eglot-ensure))
:config
(add-to-list 'eglot-server-programs
'(csharp-mode . ("csharp-ls"))))
Bob’s very happy with the result. He’s capable of doing all the smart things a modern programming environment can do from the comfort of his favorite text editor.