A typical ReSharper plug-in is nothing more than a simple .NET library application (i.e., a DLL). What distinguishes it from any other library, and makes it work with ReSharper, is two things: its references to ReSharper assemblies; and (ii) a certain amount of metadata required for ReSharper to load the plug-in. In addition, appropriate settings must be defined to allow debugging of a ReSharper plug-in under a separate Visual Studio instance.
To develop your plug-in, you will need to reference the ReSharper assemblies. Of course, you will never need to deploy them (in fact, you must make sure that Copy Local is set to ‘false’), but just by referencing your local copies, you get access to all of ReSharper’s API. If you are using the SDK, you can simply use a ReSharper project template, which comes with all the relevant ReSharper references already added.
Please note that if, instead of using the SDK, you decide to create ‘hard’ references to various ReSharper assemblies, you might encounter difficulties with sharing your project source code with other developers.
In order for ReSharper to load the plugin, the
AssemblyInfo file must have appropriate metadata definitions. At the very least, plugin writers are asked to define the title of the plugin, its description and authorship. This information is then displayed in the Plugins tab of the Options dialog.
[assembly: PluginTitle("title")] [assembly: PluginDescription("my plugin does⋮")] [assembly: PluginVendor("my company")]
No further metadata is necessary as the plug-in functionality is going to be picked up automatically by ReSharper via reflection. There are, however, several optional pieces of metadatathat can also be added. For example, if your plug-in uses images, you must also define an assembly-level
ImagesBaseAttribute. This attribute takes as a paramter the base path of the generated resource. For example, if you plug-in is called
Foo and you are keeping images as embedded resources in a folder called
Resources, then the parameter you have to pass is
Debugging a plug-in implies spinning up an additional instance of Visual Studio with the plug-in loaded. It’s important to note that you’ll be unable to debug a plug-in if another version of this plug-in has already been loaded. If you need to debug a plug-in while using that plug-in for development, simply disable the original plug-in in the Options dialog and restart the debugging session.
Debugging a plug-in is easy -- there are two flags that you can pass to
/ReSharper.Internal--- this flag turns on ReSharper’s internal menu, which is useful for all sorts of debugging. Its main feature, and one you’ll use most, is the ‘Go To Psi Tree’ menu item, which shows you the tree representing the currently edited code. It’s a great way to learn about what code elements are called. So go on – change your VS shortcut to include this flag.
/ReSharper.Plugin <path to your plugin DLL>--- this tells ReSharper to load the specified DLL. You can specify the full path, but if you want to debug the plug-in in your output directory, you can just specify the filename.
If you are debugging your plug-in and its breakpoints are not being triggered, first check that the plug-in has actually been loaded by looking for the the list of loaded plugins in ReSharper’s Options dialog. If the plugin has been loaded, look for exceptions thrown via the
/ReSharper.Internal mode. These would typically appear in the bottom right corner of the window.
Please note that the #1 cause of plugins not debugging is pack of appropriate metadata - not in
AssemblyInfo, but rather next to the component you’re trying to load. ReSharper 6 has stricter rules for metadata -- if previously you could mark up a context action with
ContextAction without specifying any parameters, this will no longer work, and as a result, your component will not be loaded.
The #2 cause of plugins not debugging or acting strangely is that you’ve accidentally let a ReSharper assembly be copied into the same folder as your plug-in binaries. This can happen if you’ve accidentally set
CopyLocal = True on a R# assembly reference or if, for example, you’ve included the tests-related
.Targets file from the SDK.
- This issue concerns plugin developers who use a license file (licenses.licx) in their plugin project. Since the license compiler (
LC.EXE) takes as parameters the full path of each assembly reference, you may run into an exception if the sum total of all reference paths exceeds 32000 characters. Possible workarounds for this issue are:
- Install the ReSharper SDK into a path that is as short as possible; or
- Create your own
.Targetfiles, removing some of the entries that your plug-in does not require.
- Some users of the SDK under Visual Studio 2010 might have problems with debugging their plug-ins. This is typically manifested by the fact that the plug-in works and the breakpoints appear ‘healthy’ but do not fire. This issue appears due to a known Visual Studio bug that will not be fixed in VS2010. As a result, the recommended workaround for plug-in developers experiencing this problem is to start up the additional instance of VS without debugging, and then using Debug | Attach to Process… to attach the correct CLR debugger manually. In this case, breakpoints should trigger correctly.