| 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 domain.completion; | 5 library domain.completion; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
| 10 import 'package:analysis_server/src/analysis_server.dart'; | 10 import 'package:analysis_server/src/analysis_server.dart'; |
| 11 import 'package:analysis_server/src/constants.dart'; | 11 import 'package:analysis_server/src/constants.dart'; |
| 12 import 'package:analysis_server/src/context_manager.dart'; | |
| 13 import 'package:analysis_server/src/provisional/completion/completion_core.dart' | 12 import 'package:analysis_server/src/provisional/completion/completion_core.dart' |
| 14 show CompletionRequest, CompletionResult; | 13 show CompletionRequest, CompletionResult; |
| 15 import 'package:analysis_server/src/services/completion/completion_core.dart'; | 14 import 'package:analysis_server/src/services/completion/completion_core.dart'; |
| 16 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; | 15 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; |
| 17 import 'package:analysis_server/src/services/search/search_engine.dart'; | |
| 18 import 'package:analyzer/src/generated/engine.dart'; | 16 import 'package:analyzer/src/generated/engine.dart'; |
| 19 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 20 | 18 |
| 21 export 'package:analysis_server/src/services/completion/completion_manager.dart' | 19 export 'package:analysis_server/src/services/completion/completion_manager.dart' |
| 22 show CompletionPerformance, CompletionRequest, OperationPerformance; | 20 show CompletionPerformance, CompletionRequest, OperationPerformance; |
| 23 | 21 |
| 24 /** | 22 /** |
| 25 * Instances of the class [CompletionDomainHandler] implement a [RequestHandler] | 23 * Instances of the class [CompletionDomainHandler] implement a [RequestHandler] |
| 26 * that handles requests in the search domain. | 24 * that handles requests in the search domain. |
| 27 */ | 25 */ |
| 28 class CompletionDomainHandler implements RequestHandler { | 26 class CompletionDomainHandler implements RequestHandler { |
| 29 /** | 27 /** |
| 30 * The maximum number of performance measurements to keep. | 28 * The maximum number of performance measurements to keep. |
| 31 */ | 29 */ |
| 32 static const int performanceListMaxLength = 50; | 30 static const int performanceListMaxLength = 50; |
| 33 | 31 |
| 34 /** | 32 /** |
| 35 * The analysis server that is using this handler to process requests. | 33 * The analysis server that is using this handler to process requests. |
| 36 */ | 34 */ |
| 37 final AnalysisServer server; | 35 final AnalysisServer server; |
| 38 | 36 |
| 39 /** | 37 /** |
| 40 * The [SearchEngine] for this server. | |
| 41 */ | |
| 42 SearchEngine searchEngine; | |
| 43 | |
| 44 /** | |
| 45 * The next completion response id. | 38 * The next completion response id. |
| 46 */ | 39 */ |
| 47 int _nextCompletionId = 0; | 40 int _nextCompletionId = 0; |
| 48 | 41 |
| 49 /** | 42 /** |
| 50 * The completion manager for most recent [Source] and [AnalysisContext], | |
| 51 * or `null` if none. | |
| 52 */ | |
| 53 CompletionManager _manager; | |
| 54 | |
| 55 /** | |
| 56 * The subscription for the cached context's source change stream. | |
| 57 */ | |
| 58 StreamSubscription<SourcesChangedEvent> _sourcesChangedSubscription; | |
| 59 | |
| 60 /** | |
| 61 * Code completion performance for the last completion operation. | 43 * Code completion performance for the last completion operation. |
| 62 */ | 44 */ |
| 63 CompletionPerformance performance; | 45 CompletionPerformance performance; |
| 64 | 46 |
| 65 /** | 47 /** |
| 66 * A list of code completion performance measurements for the latest | 48 * A list of code completion performance measurements for the latest |
| 67 * completion operation up to [performanceListMaxLength] measurements. | 49 * completion operation up to [performanceListMaxLength] measurements. |
| 68 */ | 50 */ |
| 69 final List<CompletionPerformance> performanceList = | 51 final List<CompletionPerformance> performanceList = |
| 70 new List<CompletionPerformance>(); | 52 new List<CompletionPerformance>(); |
| 71 | 53 |
| 72 /** | 54 /** |
| 73 * Performance for the last priority change event. | 55 * Performance for the last priority change event. |
| 74 */ | 56 */ |
| 75 CompletionPerformance computeCachePerformance; | 57 CompletionPerformance computeCachePerformance; |
| 76 | 58 |
| 77 /** | 59 /** |
| 78 * Initialize a new request handler for the given [server]. | 60 * Initialize a new request handler for the given [server]. |
| 79 */ | 61 */ |
| 80 CompletionDomainHandler(this.server) { | 62 CompletionDomainHandler(this.server); |
| 81 server.onContextsChanged.listen(contextsChanged); | |
| 82 server.onPriorityChange.listen(priorityChanged); | |
| 83 searchEngine = server.searchEngine; | |
| 84 } | |
| 85 | |
| 86 /** | |
| 87 * Return the completion manager for most recent [Source] and [AnalysisContext
], | |
| 88 * or `null` if none. | |
| 89 */ | |
| 90 CompletionManager get manager => _manager; | |
| 91 | 63 |
| 92 /** | 64 /** |
| 93 * Return the [CompletionManager] for the given [context] and [source], | 65 * Return the [CompletionManager] for the given [context] and [source], |
| 94 * creating a new manager or returning an existing manager as necessary. | 66 * creating a new manager or returning an existing manager as necessary. |
| 95 */ | 67 */ |
| 96 CompletionManager completionManagerFor( | 68 CompletionManager completionManagerFor( |
| 97 AnalysisContext context, Source source) { | 69 AnalysisContext context, Source source) { |
| 98 if (_manager != null) { | 70 return createCompletionManager(server, context, source); |
| 99 if (_manager.context == context && _manager.source == source) { | |
| 100 return _manager; | |
| 101 } | |
| 102 _discardManager(); | |
| 103 } | |
| 104 _manager = createCompletionManager(server, context, source); | |
| 105 if (context != null) { | |
| 106 _sourcesChangedSubscription = | |
| 107 context.onSourcesChanged.listen(sourcesChanged); | |
| 108 } | |
| 109 return _manager; | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * If the context associated with the cache has changed or been removed | |
| 114 * then discard the cache. | |
| 115 */ | |
| 116 void contextsChanged(ContextsChangedEvent event) { | |
| 117 if (_manager != null) { | |
| 118 AnalysisContext context = _manager.context; | |
| 119 if (event.changed.contains(context) || event.removed.contains(context)) { | |
| 120 _discardManager(); | |
| 121 } | |
| 122 } | |
| 123 } | 71 } |
| 124 | 72 |
| 125 CompletionManager createCompletionManager( | 73 CompletionManager createCompletionManager( |
| 126 AnalysisServer server, AnalysisContext context, Source source) { | 74 AnalysisServer server, AnalysisContext context, Source source) { |
| 127 return new CompletionManager.create(context, source, server.searchEngine, | 75 return new CompletionManager.create(context, source, server.searchEngine, |
| 128 server.serverPlugin.completionContributors); | 76 server.serverPlugin.completionContributors); |
| 129 } | 77 } |
| 130 | 78 |
| 131 @override | 79 @override |
| 132 Response handleRequest(Request request) { | 80 Response handleRequest(Request request) { |
| 133 if (searchEngine == null) { | 81 if (server.searchEngine == null) { |
| 134 return new Response.noIndexGenerated(request); | 82 return new Response.noIndexGenerated(request); |
| 135 } | 83 } |
| 136 return runZoned(() { | 84 return runZoned(() { |
| 137 try { | 85 try { |
| 138 String requestName = request.method; | 86 String requestName = request.method; |
| 139 if (requestName == COMPLETION_GET_SUGGESTIONS) { | 87 if (requestName == COMPLETION_GET_SUGGESTIONS) { |
| 140 return processRequest(request); | 88 return processRequest(request); |
| 141 } | 89 } |
| 142 } on RequestFailure catch (exception) { | 90 } on RequestFailure catch (exception) { |
| 143 return exception.response; | 91 return exception.response; |
| 144 } | 92 } |
| 145 return null; | 93 return null; |
| 146 }, onError: (exception, stackTrace) { | 94 }, onError: (exception, stackTrace) { |
| 147 server.sendServerErrorNotification( | 95 server.sendServerErrorNotification( |
| 148 'Failed to handle completion domain request: ${request.toJson()}', | 96 'Failed to handle completion domain request: ${request.toJson()}', |
| 149 exception, | 97 exception, |
| 150 stackTrace); | 98 stackTrace); |
| 151 }); | 99 }); |
| 152 } | 100 } |
| 153 | 101 |
| 154 /** | 102 /** |
| 155 * If the set the priority files has changed, then pre-cache completion | |
| 156 * information related to the first priority file. | |
| 157 */ | |
| 158 void priorityChanged(PriorityChangeEvent event) { | |
| 159 Source source = event.firstSource; | |
| 160 CompletionPerformance performance = new CompletionPerformance(); | |
| 161 computeCachePerformance = performance; | |
| 162 if (source == null) { | |
| 163 performance.complete('priorityChanged caching: no source'); | |
| 164 return; | |
| 165 } | |
| 166 performance.source = source; | |
| 167 AnalysisContext context = server.getAnalysisContextForSource(source); | |
| 168 if (context != null) { | |
| 169 String computeTag = 'computeCache'; | |
| 170 performance.logStartTime(computeTag); | |
| 171 CompletionManager manager = completionManagerFor(context, source); | |
| 172 manager.computeCache().catchError((_) => false).then((bool success) { | |
| 173 performance.logElapseTime(computeTag); | |
| 174 performance.complete('priorityChanged caching: $success'); | |
| 175 }); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 /** | |
| 180 * Process a `completion.getSuggestions` request. | 103 * Process a `completion.getSuggestions` request. |
| 181 */ | 104 */ |
| 182 Response processRequest(Request request, [CompletionManager manager]) { | 105 Response processRequest(Request request, [CompletionManager manager]) { |
| 183 performance = new CompletionPerformance(); | 106 performance = new CompletionPerformance(); |
| 184 | 107 |
| 185 // extract and validate params | 108 // extract and validate params |
| 186 CompletionGetSuggestionsParams params = | 109 CompletionGetSuggestionsParams params = |
| 187 new CompletionGetSuggestionsParams.fromRequest(request); | 110 new CompletionGetSuggestionsParams.fromRequest(request); |
| 188 ContextSourcePair contextSource = server.getContextSourcePair(params.file); | 111 ContextSourcePair contextSource = server.getContextSourcePair(params.file); |
| 189 AnalysisContext context = contextSource.context; | 112 AnalysisContext context = contextSource.context; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 | 174 |
| 252 /** | 175 /** |
| 253 * Send completion notification results. | 176 * Send completion notification results. |
| 254 */ | 177 */ |
| 255 void sendCompletionNotification(String completionId, int replacementOffset, | 178 void sendCompletionNotification(String completionId, int replacementOffset, |
| 256 int replacementLength, Iterable<CompletionSuggestion> results) { | 179 int replacementLength, Iterable<CompletionSuggestion> results) { |
| 257 server.sendNotification(new CompletionResultsParams( | 180 server.sendNotification(new CompletionResultsParams( |
| 258 completionId, replacementOffset, replacementLength, results, true) | 181 completionId, replacementOffset, replacementLength, results, true) |
| 259 .toNotification()); | 182 .toNotification()); |
| 260 } | 183 } |
| 261 | |
| 262 /** | |
| 263 * Discard the cache if a source other than the source referenced by | |
| 264 * the cache changes or if any source is added, removed, or deleted. | |
| 265 */ | |
| 266 void sourcesChanged(SourcesChangedEvent event) { | |
| 267 bool shouldDiscardManager(SourcesChangedEvent event) { | |
| 268 if (_manager == null) { | |
| 269 return false; | |
| 270 } | |
| 271 if (event.wereSourcesAdded || event.wereSourcesRemovedOrDeleted) { | |
| 272 return true; | |
| 273 } | |
| 274 var changedSources = event.changedSources; | |
| 275 return changedSources.length > 2 || | |
| 276 (changedSources.length == 1 && | |
| 277 !changedSources.contains(_manager.source)); | |
| 278 } | |
| 279 | |
| 280 if (shouldDiscardManager(event)) { | |
| 281 _discardManager(); | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 /** | |
| 286 * Discard the sourcesChanged subscription if any | |
| 287 */ | |
| 288 void _discardManager() { | |
| 289 if (_sourcesChangedSubscription != null) { | |
| 290 _sourcesChangedSubscription.cancel(); | |
| 291 _sourcesChangedSubscription = null; | |
| 292 } | |
| 293 if (_manager != null) { | |
| 294 _manager.dispose(); | |
| 295 _manager = null; | |
| 296 } | |
| 297 } | |
| 298 } | 184 } |
| OLD | NEW |