| Index: dart/site/try/poi/poi.dart
|
| diff --git a/dart/site/try/poi/poi.dart b/dart/site/try/poi/poi.dart
|
| index e93e6c888f61f09039313684003bf06c1d6321a9..d9cdeba2fb3cc6592129f0078894a5af7a97c1f0 100644
|
| --- a/dart/site/try/poi/poi.dart
|
| +++ b/dart/site/try/poi/poi.dart
|
| @@ -5,10 +5,22 @@
|
| library trydart.poi;
|
|
|
| import 'dart:async' show
|
| - Future;
|
| + Completer,
|
| + Future,
|
| + Stream;
|
|
|
| import 'dart:io' show
|
| - Platform;
|
| + HttpClient,
|
| + HttpClientRequest,
|
| + HttpClientResponse,
|
| + Platform,
|
| + stdout;
|
| +
|
| +import 'dart:io' as io;
|
| +
|
| +import 'dart:convert' show
|
| + LineSplitter,
|
| + UTF8;
|
|
|
| import 'package:dart2js_incremental/dart2js_incremental.dart' show
|
| reuseCompiler;
|
| @@ -36,33 +48,176 @@ import 'package:compiler/implementation/elements/elements.dart' show
|
| ScopeContainerElement;
|
|
|
| import 'package:compiler/implementation/scanner/scannerlib.dart' show
|
| + EOF_TOKEN,
|
| + IDENTIFIER_TOKEN,
|
| + KEYWORD_TOKEN,
|
| PartialClassElement,
|
| - PartialElement;
|
| + PartialElement,
|
| + Token;
|
|
|
| import 'package:compiler/implementation/util/uri_extras.dart' show
|
| relativize;
|
|
|
| -main(List<String> arguments) {
|
| - Uri script = Uri.base.resolve(arguments.first);
|
| - int position = int.parse(arguments[1]);
|
| +/// Controls if this program should be querying Dart Mind. Used by tests.
|
| +bool enableDartMind = true;
|
| +
|
| +/// Iterator over lines from standard input (or the argument array).
|
| +Iterator<String> stdin;
|
| +
|
| +/// Iterator for reading lines from [io.stdin].
|
| +class StdinIterator implements Iterator<String> {
|
| + String current;
|
|
|
| + bool moveNext() {
|
| + current = io.stdin.readLineSync();
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +main(List<String> arguments) {
|
| FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler();
|
| handler
|
| - ..verbose = true
|
| + ..verbose = false
|
| ..enableColors = true;
|
| api.CompilerInputProvider inputProvider = handler.provider;
|
|
|
| + if (arguments.length == 0) {
|
| + stdin = new StdinIterator();
|
| + } else {
|
| + stdin = arguments.where((String line) {
|
| + print(line); // Simulates user input in terminal.
|
| + return true;
|
| + }).iterator;
|
| + }
|
| +
|
| + return prompt('Dart file: ').then((String fileName) {
|
| + return prompt('Position: ').then((String position) {
|
| + return parseUserInput(fileName, position, inputProvider, handler);
|
| + });
|
| + });
|
| +}
|
| +
|
| +Future<String> prompt(message) {
|
| + stdout.write(message);
|
| + return stdout.flush().then((_) {
|
| + stdin.moveNext();
|
| + return stdin.current;
|
| + });
|
| +}
|
| +
|
| +Future queryDartMind(String prefix, String info) {
|
| + // TODO(lukechurch): Use [info] for something.
|
| + if (!enableDartMind) return new Future.value("[]");
|
| + String encodedArg0 = Uri.encodeComponent('"$prefix"');
|
| + String mindQuery =
|
| + 'http://dart-mind.appspot.com/rpc'
|
| + '?action=GetExportingPubCompletions'
|
| + '&arg0=$encodedArg0';
|
| + Uri uri = Uri.parse(mindQuery);
|
| +
|
| + HttpClient client = new HttpClient();
|
| + return client.getUrl(uri).then((HttpClientRequest request) {
|
| + return request.close();
|
| + }).then((HttpClientResponse response) {
|
| + Completer<String> completer = new Completer<String>();
|
| + response.transform(UTF8.decoder).listen((contents) {
|
| + completer.complete(contents);
|
| + });
|
| + return completer.future;
|
| + });
|
| +}
|
| +
|
| +Future parseUserInput(
|
| + String fileName,
|
| + String positionString,
|
| + api.CompilerInputProvider inputProvider,
|
| + api.DiagnosticHandler handler) {
|
| + Future repeat() {
|
| + return prompt('Position: ').then((String positionString) {
|
| + return parseUserInput(fileName, positionString, inputProvider, handler);
|
| + });
|
| + }
|
| +
|
| + Uri script = Uri.base.resolveUri(new Uri.file(fileName));
|
| + if (positionString == null) return null;
|
| + int position = int.parse(
|
| + positionString, onError: (_) => print('Please enter an integer.'));
|
| + if (position == null) return repeat();
|
| +
|
| inputProvider(script);
|
| handler(
|
| script, position, position + 1,
|
| - 'Point of interest.', api.Diagnostic.HINT);
|
| + 'Point of interest. Cursor is immediately before highlighted character.',
|
| + api.Diagnostic.HINT);
|
| +
|
| + Stopwatch sw = new Stopwatch()..start();
|
|
|
| Future future = runPoi(script, position, inputProvider, handler);
|
| return future.then((Element element) {
|
| - print(scopeInformation(element, position));
|
| + print('Resolving took ${sw.elapsedMicroseconds}us.');
|
| + sw.reset();
|
| + String info = scopeInformation(element, position);
|
| + print(info);
|
| + print('Scope information took ${sw.elapsedMicroseconds}us.');
|
| + sw.reset();
|
| + Token token = findToken(element, position);
|
| + String prefix;
|
| + if (token != null) {
|
| + if (token.charOffset + token.charCount <= position) {
|
| + // After the token; in whitespace, or in the beginning of another token.
|
| + prefix = "";
|
| + } else if (token.kind == IDENTIFIER_TOKEN ||
|
| + token.kind == KEYWORD_TOKEN) {
|
| + prefix = token.value.substring(0, position - token.charOffset);
|
| + }
|
| + }
|
| + print('Find token took ${sw.elapsedMicroseconds}us.');
|
| + sw.reset();
|
| + if (prefix != null) {
|
| + return queryDartMind(prefix, info).then((String dartMindSuggestion) {
|
| + sw.stop();
|
| + print('Dart Mind ($prefix): $dartMindSuggestion.');
|
| + print('Dart Mind took ${sw.elapsedMicroseconds}us.');
|
| + return repeat();
|
| + });
|
| + } else {
|
| + print("Didn't talk to Dart Mind, no identifier at POI ($token).");
|
| + return repeat();
|
| + }
|
| });
|
| }
|
|
|
| +/// Find the token corresponding to [position] in [element]. The method only
|
| +/// works for instances of [PartialElement] or [LibraryElement]. Support for
|
| +/// [LibraryElement] is currently limited, and works only for named libraries.
|
| +Token findToken(Element element, int position) {
|
| + Token beginToken;
|
| + if (element is PartialElement) {
|
| + beginToken = element.beginToken;
|
| + } else if (element is PartialClassElement) {
|
| + beginToken = element.beginToken;
|
| + } else if (element.isLibrary) {
|
| + // TODO(ahe): Generalize support for library elements (and update above
|
| + // documentation).
|
| + LibraryElement lib = element;
|
| + var tag = lib.libraryTag;
|
| + if (tag != null) {
|
| + beginToken = tag.libraryKeyword;
|
| + }
|
| + } else {
|
| + beginToken = element.position;
|
| + }
|
| + if (beginToken == null) return null;
|
| + for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) {
|
| + if (token.charOffset < position && position <= token.next.charOffset) {
|
| + return token;
|
| + }
|
| + }
|
| + return null;
|
| +}
|
| +
|
| +Compiler cachedCompiler;
|
| +
|
| Future<Element> runPoi(
|
| Uri script, int position,
|
| api.CompilerInputProvider inputProvider,
|
| @@ -78,9 +233,10 @@ Future<Element> runPoi(
|
| '--no-source-maps',
|
| '--verbose',
|
| '--categories=Client,Server',
|
| + '--incremental-support',
|
| + '--disable-type-inference',
|
| ];
|
|
|
| - Compiler cachedCompiler = null;
|
| cachedCompiler = reuseCompiler(
|
| diagnosticHandler: handler,
|
| inputProvider: inputProvider,
|
|
|