Monday, August 6, 2012

How to implement a Quick Launch search provider for Visual Studio 2012


A new feature in Visual Studio 2012 is the Quick Launch which allows searching menu items, tools options, and various other things in VS. It drives its roots from a similar feature provided in Visual Studio 2012 part of the Productivity Power Pack under the Quick Access name.
QuickLaunch

The following article will tell you how to write a Visual Studio Search Provider integrating with Quick Launch and will demonstrate the functionality with a sample

Visual Studio 2012 comes with only 4 providers out of the box: menu item, tools options, open documents and most-recently used items. Additional providers can be implemented to extend Quick Launch searches. I believe Microsoft will provide more extension packages and samples but until it does, I’m providing here a primer for writing a new search provider and a sample implementing 2 providers: Fruits and Vegetables, providing their results from 2 hardcoded lists of items.
QLFruitsAndVeggies
While Quick Launch is the official feature name, the Visual Studio interfaces supporting the feature use GlobalSearch in the name. The QuickLaunch feature can be accessed from the SVsGlobalSearch service that implements IVsGlobalSeach and IVsGlobalSearchUI interfaces.
Providers for Quick Launch are objects implementing the IVsSearchProvider interface. They are identified by their unique id (GUID), and they also need to have a unique shortcut string (more on this later).
There are 2 ways to register a new provider for Quick Launch:
1) Dynamic: a loaded package can use IVsGlobalSearch.RegisterProvider interface and pass in the provider object. Dynamic providers can also be unregistered when no longer needed; static providers cannot be unregistered. The provider is available only after the package is loaded; packages may need to use auto-load feature in VS to make sure they get loaded before the user needs their search features. Due to an implementation detail, you can’t use in the same package both dynamic and static registered providers (at least in VS2012 RTM).
2) Static: This is the most common way. In the appid’s configuration hive, under the SearchProviders key, create a subkey with the provider’s Guid, and under it declare the Package Guid implementing the provider. The Name is optional, but is recommended to write one so the providers can be quickly identified at a glance in registry.
[HKCU\Software\Microsoft\VisualStudio\11.0_Config\SearchProviders\{9ba8f997-b098-41c9-b360-fecaa397c94f}]
“Name”=”Fruits search provider”
“Package”=”{0bdb8b31-2ee3-4cd9-893a-d0b11d335f06}”


When the providers are loaded, Visual Studio loads the package implementing the provider. The package must implement the IVsPackageExtensionProvider interface, and Visual Studio will call the CreateExtensionInstance with extensionPoint = IVsSearchProvider interface’s guid, and the interface = guid identifier of the search provider (as declared in registry). The package can then create an instance of the search provider and return the object.


When implementing managed search providers, all this extensibility hook-up can be automatically done by using classes from Microsoft.VisualStudio.Shell.11.0.dll.


1) First, make sure the class implementing the search provider is attributed with the Guid identifying the provider


image








2) Derive the package class from the ExtensionPackage class in Microsoft.VisualStudio.Shell namespace


3) Declare the search provider with ProvideSearchProvider registration attribute on the package class.


image


As mentioned before, search providers are identified by 2 things:


- the provider ID, a Guid


- the provider shortcut: this is a fixed string (in the sample case, “fruits” or “veg”) which allows performing searches only against this provider, e.g. “@fruits apple” will search for “apple” only in the fruits search provider


One of the most important functions in a search provider is the CreateSearch function. Providers are called to create search tasks for the user’s input, then tasks are called on background threads to perform the actual search.  To implement a search task I recommend deriving from VsSearchTask in MPF which provides default implementations for IVsSearchTask interface, tracking search status, or notifying the global search manager about the task’s search progress. Usually, if you derive from the class you only have to override and implement the OnStartSearch method, which lets you focus on the important part – perform the actual match/search.


Search tasks have to perform very fast. The search manager will only display results that are returned in the first 1000ms, to avoid results and user’s selection ‘jumping’ in the pane after a certain time. If you don’t see any results from your search provider in the pane, it’s either you haven’t reported any results within 1s, or there are many search providers installed in the system and there wasn’t place in the popup to display results from your provider after displaying up to 3 items from other search providers that reported results faster, or from the built-in providers. When reporting search results resultant of slow operations (such as http:// queries to some online search service), it is advisable to query for only top 5-10 items that match, such that the web query return faster and you get to report at least 1 results in the first second.


Download the Quick Launch Sample



http://www.alinconstantin.net/download/Example.QuickLaunchSearchProvider.zip

2 comments:

PAR said...

I hacked this together with some code from Mads Kristensen and published on VSG:

http://bit.ly/17OHKxL

Mentioned you in dispatches, so thought I would FYI you.

Regards,

Paul

PAR said...

I hacked this together with some code from Mads Kristensen and published to VSG. Mentioned you in dispatches, so thought I would FYI you.

http://bit.ly/17OHKxL

Regards,

Paul