Chromium Code Reviews| 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 services.completion.dart; | 5 library services.completion.dart; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart'; | 9 import 'package:analysis_server/src/protocol.dart'; |
| 10 import 'package:analysis_server/src/services/completion/arglist_computer.dart'; | 10 import 'package:analysis_server/src/services/completion/arglist_computer.dart'; |
| 11 import 'package:analysis_server/src/services/completion/combinator_computer.dart '; | 11 import 'package:analysis_server/src/services/completion/combinator_computer.dart '; |
| 12 import 'package:analysis_server/src/services/completion/completion_manager.dart' ; | 12 import 'package:analysis_server/src/services/completion/completion_manager.dart' ; |
| 13 import 'package:analysis_server/src/services/completion/completion_target.dart'; | 13 import 'package:analysis_server/src/services/completion/completion_target.dart'; |
| 14 import 'package:analysis_server/src/services/completion/dart_completion_cache.da rt'; | 14 import 'package:analysis_server/src/services/completion/dart_completion_cache.da rt'; |
| 15 import 'package:analysis_server/src/services/completion/imported_computer.dart'; | 15 import 'package:analysis_server/src/services/completion/imported_computer.dart'; |
| 16 import 'package:analysis_server/src/services/completion/invocation_computer.dart '; | 16 import 'package:analysis_server/src/services/completion/invocation_computer.dart '; |
| 17 import 'package:analysis_server/src/services/completion/keyword_computer.dart'; | 17 import 'package:analysis_server/src/services/completion/keyword_computer.dart'; |
| 18 import 'package:analysis_server/src/services/completion/local_computer.dart'; | 18 import 'package:analysis_server/src/services/completion/local_computer.dart'; |
| 19 import 'package:analysis_server/src/services/completion/optype.dart'; | 19 import 'package:analysis_server/src/services/completion/optype.dart'; |
| 20 import 'package:analysis_server/src/services/search/search_engine.dart'; | 20 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 21 import 'package:analyzer/src/generated/ast.dart'; | 21 import 'package:analyzer/src/generated/ast.dart'; |
| 22 import 'package:analyzer/src/generated/engine.dart'; | 22 import 'package:analyzer/src/generated/engine.dart'; |
| 23 import 'package:analyzer/src/generated/source.dart'; | 23 import 'package:analyzer/src/generated/source.dart'; |
| 24 import 'package:analyzer/src/generated/scanner.dart'; | |
| 24 | 25 |
| 25 // TODO (danrubel) these are temporary constants as we transition completion | 26 // TODO (danrubel) these are temporary constants as we transition completion |
| 26 // relevance from CompletionRelevance.LOW/DEFAULT/HIGH to int. | 27 // relevance from CompletionRelevance.LOW/DEFAULT/HIGH to int. |
| 27 // These should be removed in a subsequent CL | 28 // These should be removed in a subsequent CL |
| 28 const int COMPLETION_RELEVANCE_LOW = 500; | 29 const int COMPLETION_RELEVANCE_LOW = 500; |
| 29 const int COMPLETION_RELEVANCE_DEFAULT = 1000; | 30 const int COMPLETION_RELEVANCE_DEFAULT = 1000; |
| 30 const int COMPLETION_RELEVANCE_HIGH = 2000; | 31 const int COMPLETION_RELEVANCE_HIGH = 2000; |
| 31 | 32 |
| 32 /** | 33 /** |
| 33 * The base class for computing code completion suggestions. | 34 * The base class for computing code completion suggestions. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 54 | 55 |
| 55 /** | 56 /** |
| 56 * Manages code completion for a given Dart file completion request. | 57 * Manages code completion for a given Dart file completion request. |
| 57 */ | 58 */ |
| 58 class DartCompletionManager extends CompletionManager { | 59 class DartCompletionManager extends CompletionManager { |
| 59 final SearchEngine searchEngine; | 60 final SearchEngine searchEngine; |
| 60 final DartCompletionCache cache; | 61 final DartCompletionCache cache; |
| 61 List<DartCompletionComputer> computers; | 62 List<DartCompletionComputer> computers; |
| 62 | 63 |
| 63 DartCompletionManager(AnalysisContext context, this.searchEngine, | 64 DartCompletionManager(AnalysisContext context, this.searchEngine, |
| 64 Source source, this.cache) | 65 Source source, this.cache, [this.computers]) |
| 65 : super(context, source), | 66 : super(context, source) { |
| 66 computers = [ | 67 if (computers == null) { |
| 68 computers = [ | |
| 67 new KeywordComputer(), | 69 new KeywordComputer(), |
| 68 new LocalComputer(), | 70 new LocalComputer(), |
| 69 new ArgListComputer(), | 71 new ArgListComputer(), |
| 70 new CombinatorComputer(), | 72 new CombinatorComputer(), |
| 71 new ImportedComputer(), | 73 new ImportedComputer(), |
| 72 new InvocationComputer()]; | 74 new InvocationComputer()]; |
| 75 } | |
| 76 } | |
| 73 | 77 |
| 74 /** | 78 /** |
| 75 * Create a new initialized Dart source completion manager | 79 * Create a new initialized Dart source completion manager |
| 76 */ | 80 */ |
| 77 factory DartCompletionManager.create(AnalysisContext context, | 81 factory DartCompletionManager.create(AnalysisContext context, |
| 78 SearchEngine searchEngine, Source source) { | 82 SearchEngine searchEngine, Source source) { |
| 79 return new DartCompletionManager( | 83 return new DartCompletionManager( |
| 80 context, | 84 context, |
| 81 searchEngine, | 85 searchEngine, |
| 82 source, | 86 source, |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 97 /** | 101 /** |
| 98 * Compute suggestions based upon cached information only | 102 * Compute suggestions based upon cached information only |
| 99 * then send an initial response to the client. | 103 * then send an initial response to the client. |
| 100 * Return a list of computers for which [computeFull] should be called | 104 * Return a list of computers for which [computeFull] should be called |
| 101 */ | 105 */ |
| 102 List<DartCompletionComputer> computeFast(DartCompletionRequest request) { | 106 List<DartCompletionComputer> computeFast(DartCompletionRequest request) { |
| 103 return request.performance.logElapseTime('computeFast', () { | 107 return request.performance.logElapseTime('computeFast', () { |
| 104 CompilationUnit unit = context.parseCompilationUnit(source); | 108 CompilationUnit unit = context.parseCompilationUnit(source); |
| 105 request.unit = unit; | 109 request.unit = unit; |
| 106 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); | 110 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); |
| 107 request.node.accept(new _ReplacementOffsetBuilder(request)); | |
| 108 request.target = new CompletionTarget.forOffset(unit, request.offset); | 111 request.target = new CompletionTarget.forOffset(unit, request.offset); |
| 112 | |
| 113 request.replacementOffset = request.offset; | |
|
Paul Berry
2015/01/28 16:32:21
Some issues with this code:
- It doesn't handle th
danrubel
2015/01/28 20:10:43
Good eyes. I like that code better. Done with a sl
| |
| 114 request.replacementLength = 0; | |
| 115 var entity = request.target.entity; | |
| 116 if (entity is SimpleIdentifier) { | |
| 117 if (entity.offset <= request.offset) { | |
| 118 request.replacementOffset = entity.offset; | |
| 119 request.replacementLength = entity.length; | |
| 120 } | |
| 121 } else if (entity is AstNode) { | |
| 122 Token token = entity.beginToken; | |
| 123 if (token.offset <= request.offset && | |
| 124 (token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFI ER)) { | |
| 125 request.replacementOffset = token.offset; | |
| 126 request.replacementLength = token.length; | |
| 127 } | |
| 128 } | |
| 129 | |
| 109 List<DartCompletionComputer> todo = new List.from(computers); | 130 List<DartCompletionComputer> todo = new List.from(computers); |
| 110 todo.removeWhere((DartCompletionComputer c) { | 131 todo.removeWhere((DartCompletionComputer c) { |
| 111 return request.performance.logElapseTime( | 132 return request.performance.logElapseTime( |
| 112 'computeFast ${c.runtimeType}', | 133 'computeFast ${c.runtimeType}', |
| 113 () { | 134 () { |
| 114 return c.computeFast(request); | 135 return c.computeFast(request); |
| 115 }); | 136 }); |
| 116 }); | 137 }); |
| 117 sendResults(request, todo.isEmpty); | 138 sendResults(request, todo.isEmpty); |
| 118 return todo; | 139 return todo; |
| 119 }); | 140 }); |
| 120 } | 141 } |
| 121 | 142 |
| 122 /** | 143 /** |
| 123 * If there is remaining work to be done, then wait for the unit to be | 144 * If there is remaining work to be done, then wait for the unit to be |
| 124 * resolved and request that each remaining computer finish their work. | 145 * resolved and request that each remaining computer finish their work. |
| 146 * Return a [Future] that completes when the last notification has been sent. | |
| 125 */ | 147 */ |
| 126 void computeFull(DartCompletionRequest request, | 148 Future computeFull(DartCompletionRequest request, |
| 127 List<DartCompletionComputer> todo) { | 149 List<DartCompletionComputer> todo) { |
| 128 request.performance.logStartTime('waitForAnalysis'); | 150 request.performance.logStartTime('waitForAnalysis'); |
| 129 waitForAnalysis().then((CompilationUnit unit) { | 151 return waitForAnalysis().then((CompilationUnit unit) { |
| 130 if (controller.isClosed) { | |
|
Paul Berry
2015/01/28 16:32:21
Nit: can we keep this? Granted, it's unnecessary
danrubel
2015/01/28 20:10:43
Makes sense. I'll put this back in. I've made the
| |
| 131 return; | |
| 132 } | |
| 133 request.performance.logElapseTime('waitForAnalysis'); | 152 request.performance.logElapseTime('waitForAnalysis'); |
| 134 if (unit == null) { | 153 if (unit == null) { |
| 135 sendResults(request, true); | 154 sendResults(request, true); |
| 136 return; | 155 return; |
| 137 } | 156 } |
| 138 request.performance.logElapseTime('computeFull', () { | 157 request.performance.logElapseTime('computeFull', () { |
| 139 request.unit = unit; | 158 request.unit = unit; |
| 140 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); | 159 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); |
| 141 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder | 160 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder |
| 142 // again? | 161 // again? |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 if (!todo.isEmpty) { | 193 if (!todo.isEmpty) { |
| 175 computeFull(request, todo); | 194 computeFull(request, todo); |
| 176 } | 195 } |
| 177 }); | 196 }); |
| 178 } | 197 } |
| 179 | 198 |
| 180 /** | 199 /** |
| 181 * Send the current list of suggestions to the client. | 200 * Send the current list of suggestions to the client. |
| 182 */ | 201 */ |
| 183 void sendResults(DartCompletionRequest request, bool last) { | 202 void sendResults(DartCompletionRequest request, bool last) { |
| 184 if (controller.isClosed) { | 203 if (controller == null || controller.isClosed) { |
| 185 return; | 204 return; |
| 186 } | 205 } |
| 187 controller.add( | 206 controller.add( |
| 188 new CompletionResult( | 207 new CompletionResult( |
| 189 request.replacementOffset, | 208 request.replacementOffset, |
| 190 request.replacementLength, | 209 request.replacementLength, |
| 191 request.suggestions, | 210 request.suggestions, |
| 192 last)); | 211 last)); |
| 193 if (last) { | 212 if (last) { |
| 194 controller.close(); | 213 controller.close(); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 * Information about the types of suggestions that should be included. | 327 * Information about the types of suggestions that should be included. |
| 309 * The [target] must be set first. | 328 * The [target] must be set first. |
| 310 */ | 329 */ |
| 311 OpType get optype { | 330 OpType get optype { |
| 312 if (_optype == null) { | 331 if (_optype == null) { |
| 313 _optype = new OpType.forCompletion(target, offset); | 332 _optype = new OpType.forCompletion(target, offset); |
| 314 } | 333 } |
| 315 return _optype; | 334 return _optype; |
| 316 } | 335 } |
| 317 } | 336 } |
| 318 | |
| 319 /** | |
| 320 * Visitor used to determine the replacement offset and length | |
| 321 * based upon the cursor location. | |
| 322 */ | |
| 323 class _ReplacementOffsetBuilder extends SimpleAstVisitor { | |
| 324 final DartCompletionRequest request; | |
| 325 | |
| 326 _ReplacementOffsetBuilder(this.request) { | |
| 327 request.replacementOffset = request.offset; | |
| 328 request.replacementLength = 0; | |
| 329 } | |
| 330 | |
| 331 visitSimpleIdentifier(SimpleIdentifier node) { | |
| 332 request.replacementOffset = node.offset; | |
| 333 request.replacementLength = node.length; | |
| 334 } | |
| 335 } | |
| OLD | NEW |