Providing Navigation

Navigation information is used by clients to allow users to navigate to the location at which an identifier is defined.

Implementation details

Navigation information can be requested both by an analysis.getNavigation request and by a subscription. If the server has subscribed for navigation information in some set of files, the plugin should send the information in an analysis.navigation notification whenever the information needs to be updated.

When an analysis.getNavigation request is received, the method handleAnalysisGetNavigation will be invoked. This method is responsible for returning a response that contains the available navigation information.

When a notification needs to be sent, the method sendNavigationNotification will be invoked. This method is responsible for sending the notification.

The easiest way to add support for both the request and the notification is by adding the classes NavigationMixin and DartNavigationMixin (from package:analyzer_plugin/plugin/navigation_mixin.dart) to the list of mixins for your subclass of ServerPlugin. This will leave you with one abstract method that you need to implement: getNavigationContributors. That method is responsible for returning a list of NavigationContributors. It is the navigation contributors that produce the actual navigation information. (Most plugins will only need a single navigation contributor.)

To write a navigation contributor, create a class that implements NavigationContributor. The interface defines a single method named computeNavigation. The method has two arguments: a NavigationRequest that describes the region of the file for which navigation is being requested and a NavigationCollector through which navigation information is to be added.

If you mix in the class DartNavigationMixin, then the request will be an instance of DartNavigationRequest, which also has analysis results.

Example

Start by creating a class that implements NavigationContributor, then implement the method computeNavigation. This method is typically implemented by creating a visitor (such as an AstVisitor) that can visit the results of the analysis (such as a CompilationUnit) and extract the navigation information from the analysis result.

For example, your contributor might look something like the following:

class MyNavigationContributor implements NavigationContributor {
  @override
  void computeNavigation(
      NavigationRequest request, NavigationCollector collector) {
    if (request is DartNavigationRequest) {
      NavigationVisitor visitor = new NavigationVisitor(collector);
      request.result.unit.accept(visitor);
    }
  }
}

class NavigationVisitor extends RecursiveAstVisitor {
  final NavigationCollector collector;

  NavigationVisitor(this.collector);

  @override
  void visitSimpleIdentifier(SimpleIdentifier node) {
    // ...
  }
}

Given a contributor like the one above, you can implement your plugin similar to the following:

class MyPlugin extends ServerPlugin with NavigationMixin, DartNavigationMixin {
  // ...

  @override
  List<NavigationContributor> getNavigationContributors(String path) {
    return <NavigationContributor>[new MyNavigationContributor()];
  }
}