| 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; |
| 114 request.replacementLength = 0; |
| 115 var entity = request.target.entity; |
| 116 Token token = entity is AstNode ? entity.beginToken : entity; |
| 117 if (token != null && |
| 118 token.offset <= request.offset && |
| 119 (token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER
)) { |
| 120 request.replacementOffset = token.offset; |
| 121 request.replacementLength = token.length; |
| 122 } |
| 123 |
| 109 List<DartCompletionComputer> todo = new List.from(computers); | 124 List<DartCompletionComputer> todo = new List.from(computers); |
| 110 todo.removeWhere((DartCompletionComputer c) { | 125 todo.removeWhere((DartCompletionComputer c) { |
| 111 return request.performance.logElapseTime( | 126 return request.performance.logElapseTime( |
| 112 'computeFast ${c.runtimeType}', | 127 'computeFast ${c.runtimeType}', |
| 113 () { | 128 () { |
| 114 return c.computeFast(request); | 129 return c.computeFast(request); |
| 115 }); | 130 }); |
| 116 }); | 131 }); |
| 117 sendResults(request, todo.isEmpty); | 132 sendResults(request, todo.isEmpty); |
| 118 return todo; | 133 return todo; |
| 119 }); | 134 }); |
| 120 } | 135 } |
| 121 | 136 |
| 122 /** | 137 /** |
| 123 * If there is remaining work to be done, then wait for the unit to be | 138 * 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. | 139 * resolved and request that each remaining computer finish their work. |
| 140 * Return a [Future] that completes when the last notification has been sent. |
| 125 */ | 141 */ |
| 126 void computeFull(DartCompletionRequest request, | 142 Future computeFull(DartCompletionRequest request, |
| 127 List<DartCompletionComputer> todo) { | 143 List<DartCompletionComputer> todo) { |
| 128 request.performance.logStartTime('waitForAnalysis'); | 144 request.performance.logStartTime('waitForAnalysis'); |
| 129 waitForAnalysis().then((CompilationUnit unit) { | 145 return waitForAnalysis().then((CompilationUnit unit) { |
| 130 if (controller.isClosed) { | 146 if (controller.isClosed) { |
| 131 return; | 147 return; |
| 132 } | 148 } |
| 133 request.performance.logElapseTime('waitForAnalysis'); | 149 request.performance.logElapseTime('waitForAnalysis'); |
| 134 if (unit == null) { | 150 if (unit == null) { |
| 135 sendResults(request, true); | 151 sendResults(request, true); |
| 136 return; | 152 return; |
| 137 } | 153 } |
| 138 request.performance.logElapseTime('computeFull', () { | 154 request.performance.logElapseTime('computeFull', () { |
| 139 request.unit = unit; | 155 request.unit = unit; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 if (!todo.isEmpty) { | 190 if (!todo.isEmpty) { |
| 175 computeFull(request, todo); | 191 computeFull(request, todo); |
| 176 } | 192 } |
| 177 }); | 193 }); |
| 178 } | 194 } |
| 179 | 195 |
| 180 /** | 196 /** |
| 181 * Send the current list of suggestions to the client. | 197 * Send the current list of suggestions to the client. |
| 182 */ | 198 */ |
| 183 void sendResults(DartCompletionRequest request, bool last) { | 199 void sendResults(DartCompletionRequest request, bool last) { |
| 184 if (controller.isClosed) { | 200 if (controller == null || controller.isClosed) { |
| 185 return; | 201 return; |
| 186 } | 202 } |
| 187 controller.add( | 203 controller.add( |
| 188 new CompletionResult( | 204 new CompletionResult( |
| 189 request.replacementOffset, | 205 request.replacementOffset, |
| 190 request.replacementLength, | 206 request.replacementLength, |
| 191 request.suggestions, | 207 request.suggestions, |
| 192 last)); | 208 last)); |
| 193 if (last) { | 209 if (last) { |
| 194 controller.close(); | 210 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. | 324 * Information about the types of suggestions that should be included. |
| 309 * The [target] must be set first. | 325 * The [target] must be set first. |
| 310 */ | 326 */ |
| 311 OpType get optype { | 327 OpType get optype { |
| 312 if (_optype == null) { | 328 if (_optype == null) { |
| 313 _optype = new OpType.forCompletion(target, offset); | 329 _optype = new OpType.forCompletion(target, offset); |
| 314 } | 330 } |
| 315 return _optype; | 331 return _optype; |
| 316 } | 332 } |
| 317 } | 333 } |
| 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 |