65.9K
CodeProject is changing. Read more.
Home

Using the Google Desktop and ReSharper APIs

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (2 votes)

Sep 13, 2006

3 min read

viewsIcon

33700

downloadIcon

370

This article describes coding against the Google Desktop API to create a plug-in for ReSharper.

Sample Image

Introduction

The less I have to navigate a directory tree, the happier I become. The arrival of Google Desktop hails the "flattening" of the file structure, as finally there is something that can just find my file for me, right when I want it. I have been a little slow to adopt the Google Desktop Search, because it still wants to open a file in the default way. If I tell it to open a web.config file, a new instance of TextPad will open (fine). I start getting annoyed when I go to open a C# source file, and suddenly I'm waiting for a new copy of VS.NET to open. That's bad.

So I have begun the task of integrating Google Desktop into text editors, with this ReSharper plug-in.

With this plug-in, I hit Ctrl-Alt-Z, type in a file name, and two seconds later, I'm editing it. Yah!

If you use Google Desktop and ReSharper, you might be interested in this plug-in. If you haven't gone to ReSharper yet, maybe you'll be interested in turning this into a VS.NET plug-in?

Background

I chose to use ReSharper because it comes with some fancy PopupList user interface stuff. The next iteration will probably be more like the Common File dialog, and if possible, I will simply integrate with the Windows Common File dialog. Anyone knows how to do this?

I fooled around with the Google Desktop Native API for a long time before deciding that C# isn't the right language for doing that. Eventually, I found this .NET wrapper for the web interface to Google Desktop Search, which I included in the project.

Using the code

First, register the Action, with this bit from AssemblyInfo.cs:

[assembly : PluginTitle("OpenByGoogleDesktopSearch")]
[assembly : PluginVendor("Tyler Gannon")]
[assembly : PluginDescription("Find a file using 
            Google Desktop search and open it.")]
[assembly : ActionsXml("Resharper.GoogleSearchPlugin.Actions.xml")]
//  Don't forget to open Actions.xml and have a look in there.

Then you need a bit in Actions.xml:

The GDS.SearchFiles method returns a sorted array of SearchResult objects, filtered to only include results that correspond to files on the local file system.

Getting the search results looks like this:

IGoogleSearch search = GoogleSearchFactory.CreateGoogleDesktopSearch();
search.ResultsPerPage = 20;
search.ResultType = ResultTypes.DataSet;
IGoogleSearchResult searchResult = search.Search(query);
DataSet currentResult;

Now, iterate through them, and get rid of any junk.

foreach (DataRow row in table.Rows)
{
    if ("file".CompareTo((string) row["category"]) == 0)
    {
        object title = row["title"];
        object url = row["url"];
        if (DBNull.Value.Equals(title) || DBNull.Value.Equals(url))
            continue;

        object snippet = title;
        try
        {
            snippet = row["snippet"];
            if (DBNull.Value.Equals(snippet))
                snippet = title;
        }
        catch (Exception)
        {
            continue;
        }

        string urlString = (string) url;
        if (urlString.StartsWith("archive://"))
        //  I think that means the file is gone.
            continue;

        SearchResult result = new SearchResult((string) title, 
                                  urlString, (string) snippet);
        resultsToReturn.Add(result);
        currentResultCount++;
    }
    if (currentResultCount >= maxResults)
    {
        break;
    }
}

Now, make it so that file names most similar to the actual search query will show up first.

Array.Sort(resultsArray, new SearchResultComparer(query));

Making use of the ReSharper popup requires implementing a few interfaces:

  • IPositionProvider, which tells the system where it can present the popup.
  • IPopupListItemDescriptor, a list of which are given to the PopupList by the PopupListProvider. In this project, SearchResult implements that interface.
  • IPopupListProvider, which is the liaison between the GDS search and the PopUpList.
  • IPopupWindowContext, which provides general functionality around PopupWindows. I inherited my PopupWindowContext from PopupWindowContextBase, and then I only had to implement CreateDefaultPositionProvider(), which is defined as abstract on the base class.

The SearchPopup form code ties it all together:

public SearchPopup()
{
    InitializeComponent();
    textBox1.Enter += new EventHandler(TextBox1_OnEnter);
}

internal void UpdateList()
{
    if (textBox1.Text.Trim().Equals(string.Empty))
    {
        TrimWindowSize();
        return;
    }
    
    list = new EscapingPopupList(new SearchResultListProvider(
           GDS.SearchFiles(textBox1.Text, MAX_RECORDS_TO_SHOW), this));
    list.Escape += new PopupListEscapeEvent(TrimWindowSize);
    list.Show(positionProvider);
}

private void TrimWindowSize()
{
    this.ResizeRedraw = true;
    this.Size = textBox1.Size;
}

protected void TextBox1_OnEnter(Object Sender, EventArgs e)
{
    if (popupWindowContext==null)
        popupWindowContext = new PopupWindowContext(this);
    
    if (positionProvider==null)
        positionProvider = 
          popupWindowContext.CreateDefaultPositionProvider();
    base.OnEnter(e);
}

protected override bool ProcessDialogKey(Keys keyData)
{
    if (keyData == (Keys.Control| Keys.W) || keyData==(Keys.Escape))
        Close();
    
    if (keyData == Keys.Tab || keyData == Keys.Enter)
        UpdateList();
    return base.ProcessDialogKey (keyData);
}

Installation

Once it's built and ready, you need to register the plug-in with ReSharper, and finally you must set up a Command Key. Copy the DLL into its own subdirectory of the PlugIns directory underneath where ReSharper is installed. The directory should be named the same as the plug-in. In this case, the assembly is named Resharper.GoogleSearchPlugin, so that's what I named the directory. Then, start VS.NET, and do the following settings in the ReSharper Plug-Ins dialog, followed by the Keyboard tab on the VS.NET general options:

And you're ready to go! Have fun.

History

  • 0.1 - Initial release.