Chromium Code Reviews| 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..8b0cca6f9270d103d76542ea8dc4db911759cfd5 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,171 @@ 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(); |
|
Johnni Winther
2014/07/17 11:25:11
Double space.
ahe
2014/08/12 13:21:12
Done.
|
| + } 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(); |
| + } |
| }); |
| } |
| +Token findToken(Element element, int position) { |
|
Johnni Winther
2014/07/17 11:25:11
Document this method. What is the semantics/qualit
ahe
2014/08/12 13:21:12
Done.
|
| + Token beginToken; |
| + if (element is PartialElement) { |
| + beginToken = element.beginToken; |
| + } else if (element is PartialClassElement) { |
| + beginToken = element.beginToken; |
| + } else if (element.isLibrary) { |
| + LibraryElement lib = element; |
| + var tag = lib.libraryTag; |
| + if (tag != null) { |
| + beginToken = tag.libraryKeyword; |
|
Johnni Winther
2014/07/17 11:25:11
Why only find a position in the library has a name
ahe
2014/08/12 13:21:12
I could handle more cases, but I'm focusing on oth
|
| + } |
| + } 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 +228,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, |