VSPy #1 – A basic language service
This is the first post in a series adding Python support to Visual Studio. See the table of contents for a brief overview.
The very first step is to install Visual Studio 2008 Standard or Professional (the Express editions are not suitable) and the SDK. (I assume everyone following along is capable of doing this without specific instructions.) When I refer to the install directory of the SDK, I will use $(VSSDK90Install), which is the same macro that the SDK sets inside VS.
Once you’re all set up, you’ll find a set of new project options. Under “Other Project Types\Extensibility”, we want to start a new “Visual Studio Integration Package”. The wizard allows you to select your language (I’ll be using C#) and to specify some details.

The following steps allow you to automatically generate various functionality, none of which is essential. Personally I also uncheck the sets of tests that are available. This generates an empty package, which, when executed, will start an isolated instance of VS with your package loaded. (This “experimental hive” stores all settings in a different location from your main instance, so the first execution will need to be as administrator.)
Before we get too far into coding, Microsoft provide a handy set of base classes known as Managed Babel. These can be found in $(VSSDK90Install)VisualStudioIntegration\Common\Source\CSharp\Babel. Add all of these files to a Babel subfolder in your project, except for Package.cs (some of the later tasks will make it easier to use a central package file, rather than the Babel one). You’ll also need references to Microsoft.VisualStudio.Package.LanguageService.9.0.dll and Microsoft.VisualStudio.TextManager.Interop.8.0.dll.
Into another subfolder (I called it LanguageService), add a new class Babel.LanguageService that inherits from Babel.BabelLanguageService, give it a GuidAttribute and implement GetFormatFilterList(). This method returns a string containing the set of files that this language service should handle. For Python, “Python File (*.py)\n*.py” is sufficient (note the newline termination, rather than the vertical bar used by the common dialog controls).
Before we can get even a basic build working, we need to provide a scanner and parser for Python. My versions for this step are here. Extract the files into your LanguageService folder and add them to your project by manually editing the csproj file and adding the following element:
<ItemGroup>
<MPLexCompile Include=”LanguageService\lexer.lex” />
<MPPGCompile Include=”LanguageService\parser.y” />
<Compile Include=”LanguageService\Configuration.cs” />
<Compile Include=”LanguageService\ErrorHandler.cs” />
<Compile Include=”LanguageService\LexDefs.cs” />
<Compile Include=”LanguageService\LanguageService.cs” />
<Compile Include=”LanguageService\Resolver.cs” />
</ItemGroup>
The first two children associate the grammar files with the lexer and parser generators, while the rest of the files are added normally. (The next post will have a fuller explanation of these files. For now, we are simply getting the package started. Both the scanner and parser have some minor issues that will be fixed)
At this point, we should be able to build successfully. However, we are not ready to begin testing. The basic language service is available but is not yet exposed through the package. Exposing a language service is a case of setting the following attributes:
[ProvideService(typeof(Babel.LanguageService))] [ProvideLanguageExtension(typeof(Babel.LanguageService), ".py")] [ProvideLanguageService(typeof(Babel.LanguageService), "Python", 0, RequestStockColors=true)]
Edit: Added RequestStockColors flag and updated scanner/parser download above.
and adding the following code to the already-overridden Initialize method:
var serviceContainer = this as IServiceContainer; var langService = new Babel.LanguageService(); langService.SetSite(this); serviceContainer.AddService(typeof(Babel.LanguageService), langService, true);
At this stage, it is simply a copy-paste job. In time I will cover the purpose of these sections more thoroughly, but for now we should have a working language service that highlights eight keywords (listed near the start of lexer.lex), strings and numbers in a Python file. You’ll need your own test file to open, since we don’t have any support for starting a new .py file (yet).
Next post I’ll go through this version of the lexer and parser, point out some of the shortcuts and shortcomings and finish highlighting the rest of the keywords (in a more efficient way than what I have done already).

One Response to “VSPy #1 – A basic language service”
Zooba's Blog » Adding new languages to Visual Studio - February 7th, 2010
[...] A basic language service [...]