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 |