| 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/completion/completion_core.dart' |
| 10 show CompletionRequest; |
| 11 import 'package:analysis_server/src/analysis_server.dart'; |
| 9 import 'package:analysis_server/src/protocol.dart'; | 12 import 'package:analysis_server/src/protocol.dart'; |
| 10 import 'package:analysis_server/src/services/completion/arglist_contributor.dart
'; | 13 import 'package:analysis_server/src/services/completion/arglist_contributor.dart
'; |
| 11 import 'package:analysis_server/src/services/completion/combinator_contributor.d
art'; | 14 import 'package:analysis_server/src/services/completion/combinator_contributor.d
art'; |
| 12 import 'package:analysis_server/src/services/completion/common_usage_computer.da
rt'; | 15 import 'package:analysis_server/src/services/completion/common_usage_computer.da
rt'; |
| 13 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; | 16 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; |
| 14 import 'package:analysis_server/src/services/completion/completion_target.dart'; | 17 import 'package:analysis_server/src/services/completion/completion_target.dart'; |
| 15 import 'package:analysis_server/src/services/completion/dart_completion_cache.da
rt'; | 18 import 'package:analysis_server/src/services/completion/dart_completion_cache.da
rt'; |
| 16 import 'package:analysis_server/src/services/completion/import_uri_contributor.d
art'; | 19 import 'package:analysis_server/src/services/completion/import_uri_contributor.d
art'; |
| 17 import 'package:analysis_server/src/services/completion/imported_reference_contr
ibutor.dart'; | 20 import 'package:analysis_server/src/services/completion/imported_reference_contr
ibutor.dart'; |
| 18 import 'package:analysis_server/src/services/completion/keyword_contributor.dart
'; | 21 import 'package:analysis_server/src/services/completion/keyword_contributor.dart
'; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 return new Future.value(false); | 117 return new Future.value(false); |
| 115 } | 118 } |
| 116 }); | 119 }); |
| 117 } | 120 } |
| 118 | 121 |
| 119 /** | 122 /** |
| 120 * Compute suggestions based upon cached information only | 123 * Compute suggestions based upon cached information only |
| 121 * then send an initial response to the client. | 124 * then send an initial response to the client. |
| 122 * Return a list of contributors for which [computeFull] should be called | 125 * Return a list of contributors for which [computeFull] should be called |
| 123 */ | 126 */ |
| 124 List<DartCompletionContributor> computeFast(DartCompletionRequest request) { | 127 List<DartCompletionContributor> computeFast( |
| 125 return request.performance.logElapseTime('computeFast', () { | 128 DartCompletionRequest request, CompletionPerformance performance) { |
| 129 return performance.logElapseTime('computeFast', () { |
| 126 CompilationUnit unit = context.parseCompilationUnit(source); | 130 CompilationUnit unit = context.parseCompilationUnit(source); |
| 127 request.unit = unit; | 131 request.unit = unit; |
| 128 request.target = new CompletionTarget.forOffset(unit, request.offset); | 132 request.target = new CompletionTarget.forOffset(unit, request.offset); |
| 129 request.replacementOffset = request.offset; | 133 request.replacementOffset = request.offset; |
| 130 request.replacementLength = 0; | 134 request.replacementLength = 0; |
| 131 if (request.offset < 0 || request.offset > unit.end) { | 135 if (request.offset < 0 || request.offset > unit.end) { |
| 132 sendResults(request, true); | 136 sendResults(request, true); |
| 133 return []; | 137 return []; |
| 134 } | 138 } |
| 135 | 139 |
| 136 var entity = request.target.entity; | 140 var entity = request.target.entity; |
| 137 Token token = entity is AstNode ? entity.beginToken : entity; | 141 Token token = entity is AstNode ? entity.beginToken : entity; |
| 138 if (token != null && | 142 if (token != null && |
| 139 token.offset <= request.offset && | 143 token.offset <= request.offset && |
| 140 (token.type == TokenType.KEYWORD || | 144 (token.type == TokenType.KEYWORD || |
| 141 token.type == TokenType.IDENTIFIER)) { | 145 token.type == TokenType.IDENTIFIER)) { |
| 142 request.replacementOffset = token.offset; | 146 request.replacementOffset = token.offset; |
| 143 request.replacementLength = token.length; | 147 request.replacementLength = token.length; |
| 144 } | 148 } |
| 145 | 149 |
| 146 List<DartCompletionContributor> todo = new List.from(contributors); | 150 List<DartCompletionContributor> todo = new List.from(contributors); |
| 147 todo.removeWhere((DartCompletionContributor c) { | 151 todo.removeWhere((DartCompletionContributor c) { |
| 148 return request.performance.logElapseTime('computeFast ${c.runtimeType}', | 152 return performance.logElapseTime('computeFast ${c.runtimeType}', () { |
| 149 () { | |
| 150 return c.computeFast(request); | 153 return c.computeFast(request); |
| 151 }); | 154 }); |
| 152 }); | 155 }); |
| 153 commonUsageComputer.computeFast(request); | 156 commonUsageComputer.computeFast(request); |
| 154 sendResults(request, todo.isEmpty); | 157 sendResults(request, todo.isEmpty); |
| 155 return todo; | 158 return todo; |
| 156 }); | 159 }); |
| 157 } | 160 } |
| 158 | 161 |
| 159 /** | 162 /** |
| 160 * If there is remaining work to be done, then wait for the unit to be | 163 * If there is remaining work to be done, then wait for the unit to be |
| 161 * resolved and request that each remaining contributor finish their work. | 164 * resolved and request that each remaining contributor finish their work. |
| 162 * Return a [Future] that completes when the last notification has been sent. | 165 * Return a [Future] that completes when the last notification has been sent. |
| 163 */ | 166 */ |
| 164 Future computeFull( | 167 Future computeFull(DartCompletionRequest request, |
| 165 DartCompletionRequest request, List<DartCompletionContributor> todo) { | 168 CompletionPerformance performance, List<DartCompletionContributor> todo) { |
| 166 request.performance.logStartTime('waitForAnalysis'); | 169 performance.logStartTime('waitForAnalysis'); |
| 167 return waitForAnalysis().then((CompilationUnit unit) { | 170 return waitForAnalysis().then((CompilationUnit unit) { |
| 168 if (controller.isClosed) { | 171 if (controller.isClosed) { |
| 169 return; | 172 return; |
| 170 } | 173 } |
| 171 request.performance.logElapseTime('waitForAnalysis'); | 174 performance.logElapseTime('waitForAnalysis'); |
| 172 if (unit == null) { | 175 if (unit == null) { |
| 173 sendResults(request, true); | 176 sendResults(request, true); |
| 174 return; | 177 return; |
| 175 } | 178 } |
| 176 request.performance.logElapseTime('computeFull', () { | 179 performance.logElapseTime('computeFull', () { |
| 177 request.unit = unit; | 180 request.unit = unit; |
| 178 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder | 181 // TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder |
| 179 // again? | 182 // again? |
| 180 request.target = new CompletionTarget.forOffset(unit, request.offset); | 183 request.target = new CompletionTarget.forOffset(unit, request.offset); |
| 181 int count = todo.length; | 184 int count = todo.length; |
| 182 todo.forEach((DartCompletionContributor c) { | 185 todo.forEach((DartCompletionContributor c) { |
| 183 String name = c.runtimeType.toString(); | 186 String name = c.runtimeType.toString(); |
| 184 String completeTag = 'computeFull $name complete'; | 187 String completeTag = 'computeFull $name complete'; |
| 185 request.performance.logStartTime(completeTag); | 188 performance.logStartTime(completeTag); |
| 186 request.performance.logElapseTime('computeFull $name', () { | 189 performance.logElapseTime('computeFull $name', () { |
| 187 c.computeFull(request).then((bool changed) { | 190 c.computeFull(request).then((bool changed) { |
| 188 request.performance.logElapseTime(completeTag); | 191 performance.logElapseTime(completeTag); |
| 189 bool last = --count == 0; | 192 bool last = --count == 0; |
| 190 if (changed || last) { | 193 if (changed || last) { |
| 191 commonUsageComputer.computeFull(request); | 194 commonUsageComputer.computeFull(request); |
| 192 sendResults(request, last); | 195 sendResults(request, last); |
| 193 } | 196 } |
| 194 }); | 197 }); |
| 195 }); | 198 }); |
| 196 }); | 199 }); |
| 197 }); | 200 }); |
| 198 }); | 201 }); |
| 199 } | 202 } |
| 200 | 203 |
| 201 @override | 204 @override |
| 202 void computeSuggestions(CompletionRequest completionRequest) { | 205 void computeSuggestions(CompletionRequest completionRequest) { |
| 203 DartCompletionRequest request = new DartCompletionRequest(context, | 206 DartCompletionRequest request = |
| 204 searchEngine, source, completionRequest.offset, cache, | 207 new DartCompletionRequest.from(completionRequest, cache); |
| 205 completionRequest.performance); | 208 CompletionPerformance performance = new CompletionPerformance(); |
| 206 request.performance.logElapseTime('compute', () { | 209 performance.logElapseTime('compute', () { |
| 207 List<DartCompletionContributor> todo = computeFast(request); | 210 List<DartCompletionContributor> todo = computeFast(request, performance); |
| 208 if (!todo.isEmpty) { | 211 if (!todo.isEmpty) { |
| 209 computeFull(request, todo); | 212 computeFull(request, performance, todo); |
| 210 } | 213 } |
| 211 }); | 214 }); |
| 212 } | 215 } |
| 213 | 216 |
| 214 /** | 217 /** |
| 215 * Send the current list of suggestions to the client. | 218 * Send the current list of suggestions to the client. |
| 216 */ | 219 */ |
| 217 void sendResults(DartCompletionRequest request, bool last) { | 220 void sendResults(DartCompletionRequest request, bool last) { |
| 218 if (controller == null || controller.isClosed) { | 221 if (controller == null || controller.isClosed) { |
| 219 return; | 222 return; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 244 // This source file is not scheduled for analysis, so a resolved | 247 // This source file is not scheduled for analysis, so a resolved |
| 245 // compilation unit is never going to get computed. | 248 // compilation unit is never going to get computed. |
| 246 return null; | 249 return null; |
| 247 }, test: (e) => e is AnalysisNotScheduledError); | 250 }, test: (e) => e is AnalysisNotScheduledError); |
| 248 } | 251 } |
| 249 } | 252 } |
| 250 | 253 |
| 251 /** | 254 /** |
| 252 * The context in which the completion is requested. | 255 * The context in which the completion is requested. |
| 253 */ | 256 */ |
| 254 class DartCompletionRequest extends CompletionRequest { | 257 class DartCompletionRequest extends CompletionRequestImpl { |
| 255 /** | |
| 256 * The analysis context in which the completion is requested. | |
| 257 */ | |
| 258 final AnalysisContext context; | |
| 259 | |
| 260 /** | |
| 261 * The search engine for use when building suggestions. | |
| 262 */ | |
| 263 final SearchEngine searchEngine; | |
| 264 | |
| 265 /** | |
| 266 * The source in which the completion is requested. | |
| 267 */ | |
| 268 final Source source; | |
| 269 | |
| 270 /** | 258 /** |
| 271 * Cached information from a prior code completion operation. | 259 * Cached information from a prior code completion operation. |
| 272 */ | 260 */ |
| 273 final DartCompletionCache cache; | 261 final DartCompletionCache cache; |
| 274 | 262 |
| 275 /** | 263 /** |
| 276 * The compilation unit in which the completion was requested. This unit | 264 * The compilation unit in which the completion was requested. This unit |
| 277 * may or may not be resolved when [DartCompletionContributor.computeFast] | 265 * may or may not be resolved when [DartCompletionContributor.computeFast] |
| 278 * is called but is resolved when [DartCompletionContributor.computeFull]. | 266 * is called but is resolved when [DartCompletionContributor.computeFull]. |
| 279 */ | 267 */ |
| (...skipping 29 matching lines...) Expand all Loading... |
| 309 /** | 297 /** |
| 310 * The list of suggestions to be sent to the client. | 298 * The list of suggestions to be sent to the client. |
| 311 */ | 299 */ |
| 312 final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[]; | 300 final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[]; |
| 313 | 301 |
| 314 /** | 302 /** |
| 315 * The set of completions used to prevent duplicates | 303 * The set of completions used to prevent duplicates |
| 316 */ | 304 */ |
| 317 final Set<String> _completions = new Set<String>(); | 305 final Set<String> _completions = new Set<String>(); |
| 318 | 306 |
| 319 DartCompletionRequest(this.context, this.searchEngine, this.source, | 307 DartCompletionRequest(AnalysisServer server, AnalysisContext context, |
| 320 int offset, this.cache, CompletionPerformance performance) | 308 Source source, int offset, this.cache) |
| 321 : super(offset, performance); | 309 : super(server, context, source, offset); |
| 310 |
| 311 factory DartCompletionRequest.from(CompletionRequestImpl request, |
| 312 DartCompletionCache cache) => new DartCompletionRequest( |
| 313 request.server, request.context, request.source, request.offset, cache); |
| 322 | 314 |
| 323 /** | 315 /** |
| 324 * Return the original text from the [replacementOffset] to the [offset] | 316 * Return the original text from the [replacementOffset] to the [offset] |
| 325 * that can be used to filter the suggestions on the server side. | 317 * that can be used to filter the suggestions on the server side. |
| 326 */ | 318 */ |
| 327 String get filterText { | 319 String get filterText { |
| 328 return context.getContents(source).data.substring( | 320 return context.getContents(source).data.substring( |
| 329 replacementOffset, offset); | 321 replacementOffset, offset); |
| 330 } | 322 } |
| 331 | 323 |
| 332 /** | 324 /** |
| 333 * Information about the types of suggestions that should be included. | 325 * Information about the types of suggestions that should be included. |
| 334 * The [target] must be set first. | 326 * The [target] must be set first. |
| 335 */ | 327 */ |
| 336 OpType get optype { | 328 OpType get optype { |
| 337 if (_optype == null) { | 329 if (_optype == null) { |
| 338 _optype = new OpType.forCompletion(target, offset); | 330 _optype = new OpType.forCompletion(target, offset); |
| 339 } | 331 } |
| 340 return _optype; | 332 return _optype; |
| 341 } | 333 } |
| 342 | 334 |
| 343 /** | 335 /** |
| 336 * The search engine for use when building suggestions. |
| 337 */ |
| 338 SearchEngine get searchEngine => server.searchEngine; |
| 339 |
| 340 /** |
| 344 * The list of suggestions to be sent to the client. | 341 * The list of suggestions to be sent to the client. |
| 345 */ | 342 */ |
| 346 Iterable<CompletionSuggestion> get suggestions => _suggestions; | 343 Iterable<CompletionSuggestion> get suggestions => _suggestions; |
| 347 | 344 |
| 348 /** | 345 /** |
| 349 * Add the given suggestion to the list that is returned to the client as long | 346 * Add the given suggestion to the list that is returned to the client as long |
| 350 * as a suggestion with an identical completion has not already been added. | 347 * as a suggestion with an identical completion has not already been added. |
| 351 */ | 348 */ |
| 352 void addSuggestion(CompletionSuggestion suggestion) { | 349 void addSuggestion(CompletionSuggestion suggestion) { |
| 353 if (_completions.add(suggestion.completion)) { | 350 if (_completions.add(suggestion.completion)) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 375 parameterNames: suggestion.parameterNames, | 372 parameterNames: suggestion.parameterNames, |
| 376 parameterTypes: suggestion.parameterTypes, | 373 parameterTypes: suggestion.parameterTypes, |
| 377 requiredParameterCount: suggestion.requiredParameterCount, | 374 requiredParameterCount: suggestion.requiredParameterCount, |
| 378 hasNamedParameters: suggestion.hasNamedParameters, | 375 hasNamedParameters: suggestion.hasNamedParameters, |
| 379 returnType: suggestion.returnType, | 376 returnType: suggestion.returnType, |
| 380 element: suggestion.element); | 377 element: suggestion.element); |
| 381 } | 378 } |
| 382 } | 379 } |
| 383 } | 380 } |
| 384 } | 381 } |
| OLD | NEW |