In my last few blogs (here, here and here) I started implementing a smart dart editor with syntax highlighting, auto complete, … for google dart.
While the first posts have been dedicated to getting syntax highlighting working we’ll now start with the higher level features you are used to from full blown IDEs.
In this first blog post we’ll look how we can interface with the Dart Analysis Server which is the reason I’ve chose dart as the example language.
The communication with the Dart Analysis is done through the input and output stream. An example will probably help.
Let’s suppose we have a /home/tomschindl/dart-samples/test.dart with the following content:
class Rectangle {
num left;
num top;
num width;
num height;
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
// This is where the app starts executing.
main() {
var r = new Rectangle();
r.
}
If you now want to get all auto completetion proposals after r. you issue the following commands/requests to the server:
- You launch the dart analysis server eg on my workstation it is:
/Users/tomschindl/Downloads/dart-sdk/bin/dart \ bin/snapshots/analysis_server.dart.snapshot
- You inform the server about the root directory:
{ "id" : "default_1", "method" : "analysis.setAnalysisRoots" , "params" : { "included":["/Users/tomschindl/dart-samples/"], "excluded":[] } } -
Which will synchronously return the following result
{ "id":"default_1" } -
Requesting all auto completetions at offset
367which is directly afterr.{ "id" : "default_2", "method" : "completion.getSuggestions" , "params" : { "file":"/Users/tomschindl/dart-samples/test.dart", "offset":367 } } - Which will synchronously return the following result
{ "id":"default_2", "result":{ "id":"0" } } -
And asynchronously the following events will occur
{ "event":"completion.results", "params":{ "id":"0", "replacementOffset":367, "replacementLength":0, "results":[], "isLast":false } } { "event":"completion.results", "params":{ "id":"0", "replacementOffset":367, "replacementLength":0, "results": [ { "kind":"INVOCATION", "relevance":1000, "completion":"left", "selectionOffset":4, "selectionLength":0, "isDeprecated":false, "isPotential":false, "declaringType":"Rectangle", "element":{ "kind":"FIELD", "name":"left", "location":{ "file":"/Users/tomschindl/dart-samples/test.dart", "offset":24, "length":4, "startLine":2, "startColumn":7 }, "flags":0, "returnType":"num" },"returnType":"num" }, { "kind":"INVOCATION", "relevance":1000, "completion":"right", "selectionOffset":5, "selectionLength":0, "isDeprecated":false, "isPotential":false, "declaringType":"Rectangle", "element":{ "kind":"GETTER", "name":"right", "location":{ "file":"/Users/tomschindl/dart-samples/test.dart", "offset":95, "length":5, "startLine":7, "startColumn":11 }, "flags":0, "returnType":"num" }, "returnType":"num" } // Many more ], "isLast":true } }
I guess you get the idea – not really rocket science but in java we don’t want to deal with this low-level stuff. So as part of the editor work we also developed a Java interface for the Dart Analysis Server available from maven-central.
If we want to issue the same commands as above through the Java-API.
Create a maven-project and make the pom.xml look like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>at.bestsolution</groupId> <artifactId>at.bestsolution.dart.server.sample</artifactId> <version>0.0.1-SNAPSHOT</version> <repositories> <repository> <id>sonatype-snapshots</id> <url>https://oss.sonatype.org/content/repositories/snapshots/</url> </repository> </repositories> <dependencies> <dependency> <groupId>at.bestsolution.eclipse</groupId> <artifactId>org.eclipse.fx.core</artifactId> <version>2.1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>at.bestsolution</groupId> <artifactId>at.bestsolution.dart.server.api</artifactId> <version>1.0.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
And a java class with the following content:
package at.bestsolution.dart.server.sample;
import java.io.IOException;
import java.util.stream.Stream;
import org.eclipse.fx.core.Util;
import at.bestsolution.dart.server.api.DartServer;
import at.bestsolution.dart.server.api.DartServerFactory;
import at.bestsolution.dart.server.api.Registration;
import at.bestsolution.dart.server.api.model.CompletionResultsNotification;
import at.bestsolution.dart.server.api.services.ServiceAnalysis;
import at.bestsolution.dart.server.api.services.ServiceCompletion;
public class DartServerSample {
public static void main(String[] args) {
// Get the server factory from the service registry
DartServerFactory serverFactory = Util.lookupService(DartServerFactory.class);
// Create a server instance
DartServer server = serverFactory.getServer("server");
// Get the analysis and completion service
ServiceAnalysis analysisService = server.getService(ServiceAnalysis.class);
ServiceCompletion completionService = server.getService(ServiceCompletion.class);
// set the root
analysisService.setAnalysisRoots(new String[] {"/Users/tomschindl/dart-samples/"}, new String[0], null);
// register for completion notifcations
Registration proposalRegistration = completionService.results(DartServerSample::handleHandleResults);
// Request completion at offset 367
completionService.getSuggestions("/Users/tomschindl/dart-samples/test.dart", 367);
// Wait for a key press
try {
System.in.read();
} catch (IOException e) {
}
// unregister the notification listener
proposalRegistration.dispose();
// shutdown the server instance
server.dispose();
}
private static void handleHandleResults(CompletionResultsNotification notification) {
Stream.of(notification.getResults()).forEach( c -> System.err.println(c.getCompletion()));
}
}
And then you have to launch the class with
java -Ddart.sdkdir=/Users/tomschindl/Downloads/dart-sdk at.bestsolution.dart.server.sample.DartServerSample
where you replace /Users/tomschindl/Downloads/dart-sdk with the path to your dart-sdk installation.
Pingback: e(fx)clipse 2.1.0 released | Tomsondev Blog