1

ReSharper 8.X ships with a macro that fetches the "Containing Type Name", but what I want to do is manipulate that name. I'm using this in a Visual Studio 2013 Web API project, and I want a template that takes the class name and builds the URL that has to be called. So, for example, suppose I have this:

public class AnnouncementController : ApiController
{
    //Want to put a template here!
    [HttpGet]
    public HttpResponseMessage GetActiveAnnouncements()
    {
        /// ...
    }
 }

now my ReSharper template will look something like this:

    /// This sample shows how to call the <see cref="$METHOD$"/> method of controller $CLASS$ using the Web API.
    ///      https://myurl.mydomain.com/api/$CONTROLLER$/$METHOD$

$Controller$, by convention, is the class name minus the letters 'Controller'. This is because ASP.NET MVC Web API projects expect classes derived from ApiController to end with the string 'Controller',

Since this class is AnnouncementController, the template should output

https://myurl.mydomain.com/api/Announcement/GetActiveAnnouncements

Resharper's Built-In Macros can give me some of what I need, but I want to write a custom macro that fetches the containing type name and chops "Controller" off of it. I would like to do that directly, without storing the containing type name in another parameter.

Also, how do I install this custom macro? I've Googled around, and all I found was a lot of dead links and old walkthroughs written for ReSharper version 7 and below that do NOT work with ReSharper 8.x

2 Answers2

2

After a lot of fighting, here is my solution.

[MacroImplementation(Definition = typeof (ControllerNameMacroDefinition))]
public class ControllerNameMacroImplementation : SimpleMacroImplementation
{

    public ControllerNameMacroImplementation([Optional] IReadOnlyCollection<IMacroParameterValueNew> arguments)
    {

    }

    public override HotspotItems GetLookupItems(IHotspotContext context)
    {
        var ret = "CONTROLLER";
        var fileName = GetFileName(context);
        if (!fileName.IsNullOrEmpty())
        {
            //Replace "Controller.cs" in two separate steps in case the extension is absent
            ret = fileName.Replace("Controller", "").Replace(".cs", "");
        }
        return MacroUtil.SimpleEvaluateResult(ret);
    }

    /// <summary>
    /// Returns the filename of the current hotspot context
    /// </summary>
    private string GetFileName(IHotspotContext context)
    {
        var psiSourceFile = context.ExpressionRange.Document.GetPsiSourceFile(context.SessionContext.Solution);
        return psiSourceFile == null ? string.Empty : psiSourceFile.Name;
    }
}
0

I wanted to do exactly this, but for JavaScript Jasmine tests -- SomethingViewModel.js, with a fixture of SomethingViewModelFixture.js, but wanted to be able to refer to SomethingViewModel in the file. A few slight modifications to the above made it possible.

Unfortunately, there's a ton more things you need to do in order to get your plugin to actually install. Here's a list. I hope it's comprehensive.

  • NuGet package install JetBrains.ReSharper.SDK, make sure you have the correct version installed!
  • Copy your Class Library DLL to C:\Users\<you>\AppData\Local\JetBrains\ReSharper\<version>\plugins\<your plugin name>, creating the plugins directory if needed.
  • You need the plugin Annotations in your AssemblyInfo.cs file:
    • [assembly: PluginTitle("Your extensions for ReSharper")]
    • [assembly: PluginDescription("Some description")] -- this is displayed in ReSharper->Options->Plugins
    • [assembly: PluginVendor("You")]
  • You need a class in your project that defines the MacroDefinition, as well as the above MacroImplementation
    • [MacroDefinition("MyNamespace.MyClassName", ShortDescription = "A short description of what it does.", LongDescription = "A long description of what it does.")]
    • "ShortDescription" - this is displayed in the "Choose Macro" dialog list.
    • "LongDescription" you'd think this would be in the "Choose Macro" description, but it isn't.
    • I just added this annotation to the above file.
  • The file you add the MacroDefinition to needs to implement IMacroDefinition, which has a method (GetPlaceholder) and a property (Parameters) on it. The former can return any string ("a") and the latter can return an empty array.
  • You can ignore the WiX/NuGet stuff if you want. Just for a local install.
  • In VS, the ReSharper->Options->Plugins section has some troubleshooting details on why your plugin might not be loading.

Good luck!

rythos42
  • 1,217
  • 2
  • 11
  • 27