| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library trydart.poi; | 5 library trydart.poi; |
| 6 | 6 |
| 7 import 'dart:async' show | 7 import 'dart:async' show |
| 8 Future; | 8 Completer, |
| 9 Future, |
| 10 Stream; |
| 9 | 11 |
| 10 import 'dart:io' show | 12 import 'dart:io' show |
| 11 Platform; | 13 HttpClient, |
| 14 HttpClientRequest, |
| 15 HttpClientResponse, |
| 16 Platform, |
| 17 stdout; |
| 18 |
| 19 import 'dart:io' as io; |
| 20 |
| 21 import 'dart:convert' show |
| 22 LineSplitter, |
| 23 UTF8; |
| 12 | 24 |
| 13 import 'package:dart2js_incremental/dart2js_incremental.dart' show | 25 import 'package:dart2js_incremental/dart2js_incremental.dart' show |
| 14 reuseCompiler; | 26 reuseCompiler; |
| 15 | 27 |
| 16 import 'package:compiler/implementation/source_file_provider.dart' show | 28 import 'package:compiler/implementation/source_file_provider.dart' show |
| 17 FormattingDiagnosticHandler, | 29 FormattingDiagnosticHandler, |
| 18 SourceFileProvider; | 30 SourceFileProvider; |
| 19 | 31 |
| 20 import 'package:compiler/compiler.dart' as api; | 32 import 'package:compiler/compiler.dart' as api; |
| 21 | 33 |
| 22 import 'package:compiler/implementation/dart2jslib.dart' show | 34 import 'package:compiler/implementation/dart2jslib.dart' show |
| 23 Compiler, | 35 Compiler, |
| 24 Enqueuer, | 36 Enqueuer, |
| 25 QueueFilter, | 37 QueueFilter, |
| 26 WorkItem; | 38 WorkItem; |
| 27 | 39 |
| 28 import 'package:compiler/implementation/elements/visitor.dart' show | 40 import 'package:compiler/implementation/elements/visitor.dart' show |
| 29 ElementVisitor; | 41 ElementVisitor; |
| 30 | 42 |
| 31 import 'package:compiler/implementation/elements/elements.dart' show | 43 import 'package:compiler/implementation/elements/elements.dart' show |
| 32 ClassElement, | 44 ClassElement, |
| 33 CompilationUnitElement, | 45 CompilationUnitElement, |
| 34 Element, | 46 Element, |
| 35 LibraryElement, | 47 LibraryElement, |
| 36 ScopeContainerElement; | 48 ScopeContainerElement; |
| 37 | 49 |
| 38 import 'package:compiler/implementation/scanner/scannerlib.dart' show | 50 import 'package:compiler/implementation/scanner/scannerlib.dart' show |
| 51 EOF_TOKEN, |
| 52 IDENTIFIER_TOKEN, |
| 53 KEYWORD_TOKEN, |
| 39 PartialClassElement, | 54 PartialClassElement, |
| 40 PartialElement; | 55 PartialElement, |
| 56 Token; |
| 41 | 57 |
| 42 import 'package:compiler/implementation/util/uri_extras.dart' show | 58 import 'package:compiler/implementation/util/uri_extras.dart' show |
| 43 relativize; | 59 relativize; |
| 44 | 60 |
| 61 /// Controls if this program should be querying Dart Mind. Used by tests. |
| 62 bool enableDartMind = true; |
| 63 |
| 64 /// Iterator over lines from standard input (or the argument array). |
| 65 Iterator<String> stdin; |
| 66 |
| 67 /// Iterator for reading lines from [io.stdin]. |
| 68 class StdinIterator implements Iterator<String> { |
| 69 String current; |
| 70 |
| 71 bool moveNext() { |
| 72 current = io.stdin.readLineSync(); |
| 73 return true; |
| 74 } |
| 75 } |
| 76 |
| 45 main(List<String> arguments) { | 77 main(List<String> arguments) { |
| 46 Uri script = Uri.base.resolve(arguments.first); | |
| 47 int position = int.parse(arguments[1]); | |
| 48 | |
| 49 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler(); | 78 FormattingDiagnosticHandler handler = new FormattingDiagnosticHandler(); |
| 50 handler | 79 handler |
| 51 ..verbose = true | 80 ..verbose = false |
| 52 ..enableColors = true; | 81 ..enableColors = true; |
| 53 api.CompilerInputProvider inputProvider = handler.provider; | 82 api.CompilerInputProvider inputProvider = handler.provider; |
| 54 | 83 |
| 84 if (arguments.length == 0) { |
| 85 stdin = new StdinIterator(); |
| 86 } else { |
| 87 stdin = arguments.where((String line) { |
| 88 print(line); // Simulates user input in terminal. |
| 89 return true; |
| 90 }).iterator; |
| 91 } |
| 92 |
| 93 return prompt('Dart file: ').then((String fileName) { |
| 94 return prompt('Position: ').then((String position) { |
| 95 return parseUserInput(fileName, position, inputProvider, handler); |
| 96 }); |
| 97 }); |
| 98 } |
| 99 |
| 100 Future<String> prompt(message) { |
| 101 stdout.write(message); |
| 102 return stdout.flush().then((_) { |
| 103 stdin.moveNext(); |
| 104 return stdin.current; |
| 105 }); |
| 106 } |
| 107 |
| 108 Future queryDartMind(String prefix, String info) { |
| 109 // TODO(lukechurch): Use [info] for something. |
| 110 if (!enableDartMind) return new Future.value("[]"); |
| 111 String encodedArg0 = Uri.encodeComponent('"$prefix"'); |
| 112 String mindQuery = |
| 113 'http://dart-mind.appspot.com/rpc' |
| 114 '?action=GetExportingPubCompletions' |
| 115 '&arg0=$encodedArg0'; |
| 116 Uri uri = Uri.parse(mindQuery); |
| 117 |
| 118 HttpClient client = new HttpClient(); |
| 119 return client.getUrl(uri).then((HttpClientRequest request) { |
| 120 return request.close(); |
| 121 }).then((HttpClientResponse response) { |
| 122 Completer<String> completer = new Completer<String>(); |
| 123 response.transform(UTF8.decoder).listen((contents) { |
| 124 completer.complete(contents); |
| 125 }); |
| 126 return completer.future; |
| 127 }); |
| 128 } |
| 129 |
| 130 Future parseUserInput( |
| 131 String fileName, |
| 132 String positionString, |
| 133 api.CompilerInputProvider inputProvider, |
| 134 api.DiagnosticHandler handler) { |
| 135 Future repeat() { |
| 136 return prompt('Position: ').then((String positionString) { |
| 137 return parseUserInput(fileName, positionString, inputProvider, handler); |
| 138 }); |
| 139 } |
| 140 |
| 141 Uri script = Uri.base.resolveUri(new Uri.file(fileName)); |
| 142 if (positionString == null) return null; |
| 143 int position = int.parse( |
| 144 positionString, onError: (_) => print('Please enter an integer.')); |
| 145 if (position == null) return repeat(); |
| 146 |
| 55 inputProvider(script); | 147 inputProvider(script); |
| 56 handler( | 148 handler( |
| 57 script, position, position + 1, | 149 script, position, position + 1, |
| 58 'Point of interest.', api.Diagnostic.HINT); | 150 'Point of interest. Cursor is immediately before highlighted character.', |
| 151 api.Diagnostic.HINT); |
| 152 |
| 153 Stopwatch sw = new Stopwatch()..start(); |
| 59 | 154 |
| 60 Future future = runPoi(script, position, inputProvider, handler); | 155 Future future = runPoi(script, position, inputProvider, handler); |
| 61 return future.then((Element element) { | 156 return future.then((Element element) { |
| 62 print(scopeInformation(element, position)); | 157 print('Resolving took ${sw.elapsedMicroseconds}us.'); |
| 158 sw.reset(); |
| 159 String info = scopeInformation(element, position); |
| 160 print(info); |
| 161 print('Scope information took ${sw.elapsedMicroseconds}us.'); |
| 162 sw.reset(); |
| 163 Token token = findToken(element, position); |
| 164 String prefix; |
| 165 if (token != null) { |
| 166 if (token.charOffset + token.charCount <= position) { |
| 167 // After the token; in whitespace, or in the beginning of another token. |
| 168 prefix = ""; |
| 169 } else if (token.kind == IDENTIFIER_TOKEN || |
| 170 token.kind == KEYWORD_TOKEN) { |
| 171 prefix = token.value.substring(0, position - token.charOffset); |
| 172 } |
| 173 } |
| 174 print('Find token took ${sw.elapsedMicroseconds}us.'); |
| 175 sw.reset(); |
| 176 if (prefix != null) { |
| 177 return queryDartMind(prefix, info).then((String dartMindSuggestion) { |
| 178 sw.stop(); |
| 179 print('Dart Mind ($prefix): $dartMindSuggestion.'); |
| 180 print('Dart Mind took ${sw.elapsedMicroseconds}us.'); |
| 181 return repeat(); |
| 182 }); |
| 183 } else { |
| 184 print("Didn't talk to Dart Mind, no identifier at POI ($token)."); |
| 185 return repeat(); |
| 186 } |
| 63 }); | 187 }); |
| 64 } | 188 } |
| 65 | 189 |
| 190 /// Find the token corresponding to [position] in [element]. The method only |
| 191 /// works for instances of [PartialElement] or [LibraryElement]. Support for |
| 192 /// [LibraryElement] is currently limited, and works only for named libraries. |
| 193 Token findToken(Element element, int position) { |
| 194 Token beginToken; |
| 195 if (element is PartialElement) { |
| 196 beginToken = element.beginToken; |
| 197 } else if (element is PartialClassElement) { |
| 198 beginToken = element.beginToken; |
| 199 } else if (element.isLibrary) { |
| 200 // TODO(ahe): Generalize support for library elements (and update above |
| 201 // documentation). |
| 202 LibraryElement lib = element; |
| 203 var tag = lib.libraryTag; |
| 204 if (tag != null) { |
| 205 beginToken = tag.libraryKeyword; |
| 206 } |
| 207 } else { |
| 208 beginToken = element.position; |
| 209 } |
| 210 if (beginToken == null) return null; |
| 211 for (Token token = beginToken; token.kind != EOF_TOKEN; token = token.next) { |
| 212 if (token.charOffset < position && position <= token.next.charOffset) { |
| 213 return token; |
| 214 } |
| 215 } |
| 216 return null; |
| 217 } |
| 218 |
| 219 Compiler cachedCompiler; |
| 220 |
| 66 Future<Element> runPoi( | 221 Future<Element> runPoi( |
| 67 Uri script, int position, | 222 Uri script, int position, |
| 68 api.CompilerInputProvider inputProvider, | 223 api.CompilerInputProvider inputProvider, |
| 69 api.DiagnosticHandler handler) { | 224 api.DiagnosticHandler handler) { |
| 70 | 225 |
| 71 Uri libraryRoot = Uri.base.resolve('sdk/'); | 226 Uri libraryRoot = Uri.base.resolve('sdk/'); |
| 72 Uri packageRoot = Uri.base.resolveUri( | 227 Uri packageRoot = Uri.base.resolveUri( |
| 73 new Uri.file('${Platform.packageRoot}/')); | 228 new Uri.file('${Platform.packageRoot}/')); |
| 74 | 229 |
| 75 var options = [ | 230 var options = [ |
| 76 '--analyze-main', | 231 '--analyze-main', |
| 77 '--analyze-only', | 232 '--analyze-only', |
| 78 '--no-source-maps', | 233 '--no-source-maps', |
| 79 '--verbose', | 234 '--verbose', |
| 80 '--categories=Client,Server', | 235 '--categories=Client,Server', |
| 236 '--incremental-support', |
| 237 '--disable-type-inference', |
| 81 ]; | 238 ]; |
| 82 | 239 |
| 83 Compiler cachedCompiler = null; | |
| 84 cachedCompiler = reuseCompiler( | 240 cachedCompiler = reuseCompiler( |
| 85 diagnosticHandler: handler, | 241 diagnosticHandler: handler, |
| 86 inputProvider: inputProvider, | 242 inputProvider: inputProvider, |
| 87 options: options, | 243 options: options, |
| 88 cachedCompiler: cachedCompiler, | 244 cachedCompiler: cachedCompiler, |
| 89 libraryRoot: libraryRoot, | 245 libraryRoot: libraryRoot, |
| 90 packageRoot: packageRoot, | 246 packageRoot: packageRoot, |
| 91 packagesAreImmutable: true); | 247 packagesAreImmutable: true); |
| 92 | 248 |
| 93 cachedCompiler.enqueuerFilter = new ScriptOnlyFilter(script); | 249 cachedCompiler.enqueuerFilter = new ScriptOnlyFilter(script); |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 if (!omitEnclosing) { | 401 if (!omitEnclosing) { |
| 246 buffer.write(',\n'); | 402 buffer.write(',\n'); |
| 247 indented.write('"enclosing": '); | 403 indented.write('"enclosing": '); |
| 248 element.enclosingElement.accept(this); | 404 element.enclosingElement.accept(this); |
| 249 } | 405 } |
| 250 indentationLevel--; | 406 indentationLevel--; |
| 251 buffer.write('\n'); | 407 buffer.write('\n'); |
| 252 indented.write('}'); | 408 indented.write('}'); |
| 253 } | 409 } |
| 254 } | 410 } |
| OLD | NEW |