Program comprehension requires developers to reason about many kinds of highly interconnected software entities. Dealing with this reality prompts developers to continuously intertwine searching and navigation. Nevertheless, current integrated development environments (IDEs) address searching by means of many independent and disconnected search tools. This not only impedes developers from reusing search results produced by one search tool as input for another search tool, but it also makes it difficult to find appropriate search tools, in the multitude of other tools provided by an IDE.
To address this problem we start from the realization that having disconnected search tools within an IDE, each designed to work in isolation and on different data types, is part of the problem. We propose Spotter, a model for expressing and combining search tools in a unified way. Spotter has two main goals:
Searching for classes or packages is a common code search requirement. Although very similar in nature, these two searches are too often supported through separated search interfaces. Spotter integrates them easily in one. In the example below we see the basic interface that is triggered via Cmd+Enter. On top, the user can enter a textual query, and below the search is executed through multiple search categories. In our case, entering GTSpo, leads to matching 39 classes (of which only 5 are shown) and 1 package. For each element, the matching substring is underlined.
The interface is fully controllable through the keyboard. The user can move with ArrowUp/ArrowDown between items or Cmd+Shift+ArrowUp/ArrowDown through categories. At the same time, the search field has the focus, so the user can switch seamlessly between selecting items and refining the search. Pressing Enter reveals the code browser.
While packages and classes are typical structural entities, annotations can be equally important. Spotter searches for annotations (named ‘pragmas’ in the target language for our implementation) in the same interface. In this case, pressing Enter opens an inspector on the
Searching for implementors is another common code search use case. Until now, the way to search for implementors in Pharo is to open a Playground/Workspace, enter a the symbol, press Cmd+m and then close the Playground/Workspace window. Spotter makes it easier.
It’s not just code that is interesting for search. Finding a tool is a search activity as well. That is why, the Spotter offers, by default, through menu items.
GTPlayground remembers all snippets ever used within the image. This is nice, but it can quickly become hard to find a previous snippet. That is why, Spotter makes this list searchable. Pressing Enter reveals a Playground populated with the desired code.
Since a while, the GTPlayground has the ability of publishing the contents to the sharing service available at: http://ws.stfx.eu. However, until now, the playground offered no easy way to load the contents of a published page. Spotter fixes the situation: simply pasting the url offers an object with the remote page. Pressing Enter opens a playground with the page contents.
Spotter can find various types of objects rather fast. Yet, often we just want to get to the objects we just visited recently. It is for this reason that Spotter offers the history of previously spotted objects by default. For example, the picture below shows a history of 5 most recent objects.
Typical IDE search tools behave like general search tools in that they offer only one level of search. However, software systems have structure, and we often need to be able to search inside a found object. To this end, Spotter allows the user to dive in an object and continue searching through the same interface. This is accomplished by pressing Cmd+RightArrow.
For example, the below picture shows the case of going inside the Spotter class. The context of the current search is shown in the breadcrumb on top of the window. For this method, the user can search through class related facts such as methods, variables or references.
Diving in a method, again offers the same interface through which the user can search for senders or implementors.
Diving in a sender reveals the senders and implementors. Thus, this simple interface provides the basic block for replacing other interfaces that are dedicated to showing the list of senders, implementors or references in a separate window.
But, Spotter is about objects, not about code. To exemplify the implication of this, let’s consider the typical use case of looking for a file somewhere in the directory structure inside the current directory. In the below picture, the main Spotter finds a directory.
Diving in the directory, allows the user to continue searching for deeper items.
The GTSpotter implements the ideas behind the Moldable Spotter model as part of the GToolkit project. It is available in the latest Moose image which can be downloaded from the Moose website. It is also integrate in Pharo.
The existing implementations already comes with more than 100 various categories that support a rather extensive set of common search actions. However, the true power of GTSpotter comes from it being moldable.
Custom searches for an object are defined as extension methods in class of that object.
By default, the main GTSpotter opens on itself. Thus, all the top level categories are defined as extensions of the
GTSpotter class. For example, searching for all classes in the image, is achieved as follows:
GTSpotter>>spotterForClassesFor: aStep <spotterOrder: 10> aStep listProcessor allCandidates: [ Smalltalk allClasses ]; title: 'Classes'; matchSubstring; itemIcon: #systemIcon
Similarly, searching for the instance side methods inside a class, is achieved through an extension method of
Class>>spotterMethodsFor: aStep <spotterOrder: 10> aStep listProcessor title: 'Instance methods'; allCandidates: [ self methods ]; itemName: [ :method | method selector ]; matchSubstring
The histogram below shows the the size distribution (in LOC) for 106 custom extensions.
On average an extension takes 8 lines of code. That means that you can get your objects to be equally searchable with just a handful of lines of code.
|Finding asClass usages in Glamour using GTSpotter|
|Scoping for a specific search category in GTSpotter|
|Managing external Pharo scripts with GTInspector and GTSpotter|
|Spotting objects from GTInspector|
|Searching the file system with GTSpotter|
|Boosting GTSpotter with preview capabilities|
|Sharing code using Playground and Spotter|