Monday, September 29, 2008

Vim C# Compiling

This is the first post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

The most important thing to be able to do comes in two parts:
  1. Compile
  2. Step through errors
In college we did development in Java without any kind of IDE. So you typed in your text editor. Then switched to the DOS prompt and "javac"ed. When there were errors, which there always were, you opened the file with the error and navigated to the line where it occurred. This was slow and tedious, but not the end of the world. Until you get used to Visual Studio and being able to F5, and then simply double click on an error.

How do we do the same thing in Vim? First, we have to compile. To start with, I'm going to compile using the following command:
devenv slnname.sln /Build Debug

This will perform the build exactly like Visual Studio would, just without opening Visual Studio. I put this command in a .bat file in the same directory as the .sln called build.bat.

To get Vim to use this batch file to compile:
set makeprg=build.bat

Now from within Vim just type :make when your current directory (:cd) is the one containing the build.bat file, and your solution will build.

What about parsing out the errors? Easy:
set errorformat=\ %#%f(%l\\\,%c):\ %m

This tells Vim how to parse the error output.

Now if there are errors, hitting Enter will take you directly to the file and line where the first error occurred. :cn will take you to the next and :cp will take you to the previous. :cl will list all errors. Read :help quickfix.txt for more.

You could also use msbuild to compile your solution. The command for this is simply msbuild /nologo /v:q. It will find the .sln in the current directory and build it for you. However, with this command you have to modify your .csproj so that the error output includes full paths (otherwise the errorformat wont be able to parse it). To do that, just add the following line to the common PropertyGroup element of your .csproj:
<GenerateFullPaths>True</GenerateFullPaths>

The error format is the same as for devenv. But you don't need the build.bat (if you will always have only one solution in the directory at a time), instead you can use this:
set makeprg=msbuild\ /nologo\ /v:q

Now you can happily compile C# solutions and step through errors from right inside Vim.

If you don't like having to add the GenerateFullPaths node to your project file, you can add it to the msbuild command line instead as follows:
:set makeprg=msbuild\ /nologo\ /v:q\ /property:GenerateFullPaths=true

There is one more enhancement we can make. Vim has the ability to easily switch between compilers and set all the settings that the compiler needs as part of the switch. You can enable this by creating a "devenv.vim" file in vimfiles\compiler (on windows) containing the following code:
" Vim compiler file
" Compiler: DevEnv

if exists("current_compiler")
finish
endif
let current_compiler = "devenv"

if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif

" default errorformat
CompilerSet errorformat=\ %#%f(%l\\\,%c):\ %m

" default make
CompilerSet makeprg=build.bat

To use this, just type :compiler devenv. Or, if you want Vim to always use this anytime you're editing a C# file (a file with a .cs extension) add the following to your _vimrc:
" setup C# building
if !exists("autocommands_loaded")
let autocommands_loaded = 1
autocmd BufNewFile,BufRead *.cs compiler devenv
endif

If you have any improvements to add, please let me know in the comments!