| 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/plugin/protocol/protocol.dart'; | 9 import 'package:analysis_server/plugin/protocol/protocol.dart'; |
| 10 import 'package:analysis_server/src/provisional/completion/completion_core.dart' | 10 import 'package:analysis_server/src/provisional/completion/completion_core.dart' |
| 11 show AnalysisRequest, CompletionContributor, CompletionRequest; | 11 show AnalysisRequest, CompletionContributor, CompletionRequest; |
| 12 import 'package:analysis_server/src/services/completion/completion_core.dart'; | 12 import 'package:analysis_server/src/services/completion/completion_core.dart'; |
| 13 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; | 13 import 'package:analysis_server/src/services/completion/completion_manager.dart'
; |
| 14 import 'package:analysis_server/src/services/search/search_engine.dart'; | 14 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 15 import 'package:analyzer/file_system/file_system.dart'; | |
| 16 import 'package:analyzer/src/generated/ast.dart'; | 15 import 'package:analyzer/src/generated/ast.dart'; |
| 17 import 'package:analyzer/src/generated/engine.dart'; | 16 import 'package:analyzer/src/generated/engine.dart'; |
| 18 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 19 | 18 |
| 20 /** | 19 /** |
| 21 * The base class for contributing code completion suggestions. | |
| 22 */ | |
| 23 abstract class DartCompletionContributor { | |
| 24 /** | |
| 25 * Computes the initial set of [CompletionSuggestion]s based on | |
| 26 * the given completion context. The compilation unit and completion node | |
| 27 * in the given completion context may not be resolved. | |
| 28 * This method should execute quickly and not block waiting for any analysis. | |
| 29 * Returns `true` if the contributor's work is complete | |
| 30 * or `false` if [computeFull] should be called to complete the work. | |
| 31 */ | |
| 32 bool computeFast(DartCompletionRequest request); | |
| 33 | |
| 34 /** | |
| 35 * Computes the complete set of [CompletionSuggestion]s based on | |
| 36 * the given completion context. The compilation unit and completion node | |
| 37 * in the given completion context are resolved. | |
| 38 * Returns `true` if the receiver modified the list of suggestions. | |
| 39 */ | |
| 40 Future<bool> computeFull(DartCompletionRequest request); | |
| 41 } | |
| 42 | |
| 43 /** | |
| 44 * Manages code completion for a given Dart file completion request. | 20 * Manages code completion for a given Dart file completion request. |
| 45 */ | 21 */ |
| 46 class DartCompletionManager extends CompletionManager { | 22 class DartCompletionManager extends CompletionManager { |
| 47 final SearchEngine searchEngine; | 23 final SearchEngine searchEngine; |
| 48 Iterable<CompletionContributor> newContributors; | 24 Iterable<CompletionContributor> newContributors; |
| 49 | 25 |
| 50 DartCompletionManager( | 26 DartCompletionManager( |
| 51 AnalysisContext context, this.searchEngine, Source source, | 27 AnalysisContext context, this.searchEngine, Source source, |
| 52 [this.newContributors]) | 28 [this.newContributors]) |
| 53 : super(context, source) { | 29 : super(context, source) { |
| 54 if (newContributors == null) { | 30 if (newContributors == null) { |
| 55 newContributors = <CompletionContributor>[]; | 31 newContributors = <CompletionContributor>[]; |
| 56 } | 32 } |
| 57 } | 33 } |
| 58 | 34 |
| 59 /** | 35 /** |
| 60 * Create a new initialized Dart source completion manager | 36 * Create a new initialized Dart source completion manager |
| 61 */ | 37 */ |
| 62 factory DartCompletionManager.create( | 38 factory DartCompletionManager.create( |
| 63 AnalysisContext context, | 39 AnalysisContext context, |
| 64 SearchEngine searchEngine, | 40 SearchEngine searchEngine, |
| 65 Source source, | 41 Source source, |
| 66 Iterable<CompletionContributor> newContributors) { | 42 Iterable<CompletionContributor> newContributors) { |
| 67 return new DartCompletionManager( | 43 return new DartCompletionManager( |
| 68 context, searchEngine, source, newContributors); | 44 context, searchEngine, source, newContributors); |
| 69 } | 45 } |
| 70 | 46 |
| 71 /** | 47 /** |
| 72 * Compute suggestions based upon cached information only | |
| 73 * then send an initial response to the client. | |
| 74 * Return a list of contributors for which [computeFull] should be called | |
| 75 */ | |
| 76 List<DartCompletionContributor> computeFast( | |
| 77 DartCompletionRequest request, CompletionPerformance performance) { | |
| 78 return []; | |
| 79 } | |
| 80 | |
| 81 /** | |
| 82 * If there is remaining work to be done, then wait for the unit to be | 48 * If there is remaining work to be done, then wait for the unit to be |
| 83 * resolved and request that each remaining contributor finish their work. | 49 * resolved and request that each remaining contributor finish their work. |
| 84 * Return a [Future] that completes when the last notification has been sent. | 50 * Return a [Future] that completes when the last notification has been sent. |
| 85 */ | 51 */ |
| 86 Future computeFull( | 52 Future computeFull( |
| 87 DartCompletionRequest request, | 53 CompletionRequestImpl request, CompletionPerformance performance) async { |
| 88 CompletionPerformance performance, | 54 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; |
| 89 List<DartCompletionContributor> todo) async { | 55 |
| 90 // Compute suggestions using the new API | |
| 91 performance.logStartTime('computeSuggestions'); | 56 performance.logStartTime('computeSuggestions'); |
| 92 for (CompletionContributor contributor in newContributors) { | 57 for (CompletionContributor contributor in newContributors) { |
| 93 String contributorTag = 'computeSuggestions - ${contributor.runtimeType}'; | 58 String contributorTag = 'computeSuggestions - ${contributor.runtimeType}'; |
| 94 performance.logStartTime(contributorTag); | 59 performance.logStartTime(contributorTag); |
| 95 List<CompletionSuggestion> newSuggestions = | 60 suggestions.addAll(await contributor.computeSuggestions(request)); |
| 96 await contributor.computeSuggestions(request); | |
| 97 for (CompletionSuggestion suggestion in newSuggestions) { | |
| 98 request.addSuggestion(suggestion); | |
| 99 } | |
| 100 performance.logElapseTime(contributorTag); | 61 performance.logElapseTime(contributorTag); |
| 101 } | 62 } |
| 102 performance.logElapseTime('computeSuggestions'); | 63 performance.logElapseTime('computeSuggestions'); |
| 103 performance.logStartTime('waitForAnalysis'); | |
| 104 | 64 |
| 105 // TODO (danrubel) if request is obsolete | 65 // TODO (danrubel) if request is obsolete |
| 106 // (processAnalysisRequest returns false) | 66 // (processAnalysisRequest returns false) |
| 107 // then send empty results | 67 // then send empty results |
| 108 sendResults(request, true); | 68 |
| 109 return new Future.value(); | 69 if (controller != null && !controller.isClosed) { |
| 70 controller.add(new CompletionResultImpl(request.replacementOffset, |
| 71 request.replacementLength, suggestions, true)); |
| 72 controller.close(); |
| 73 } |
| 110 } | 74 } |
| 111 | 75 |
| 112 @override | 76 @override |
| 113 void computeSuggestions(CompletionRequest completionRequest) { | 77 void computeSuggestions(CompletionRequest request) { |
| 114 DartCompletionRequest request = | |
| 115 new DartCompletionRequest.from(completionRequest); | |
| 116 CompletionPerformance performance = new CompletionPerformance(); | 78 CompletionPerformance performance = new CompletionPerformance(); |
| 117 performance.logElapseTime('compute', () { | 79 performance.logElapseTime('compute', () { |
| 118 List<DartCompletionContributor> todo = computeFast(request, performance); | 80 computeFull(request, performance); |
| 119 computeFull(request, performance, todo); | |
| 120 }); | 81 }); |
| 121 } | 82 } |
| 122 | 83 |
| 123 /** | 84 /** |
| 124 * Send the current list of suggestions to the client. | |
| 125 */ | |
| 126 void sendResults(DartCompletionRequest request, bool last) { | |
| 127 if (controller == null || controller.isClosed) { | |
| 128 return; | |
| 129 } | |
| 130 controller.add(new CompletionResultImpl(request.replacementOffset, | |
| 131 request.replacementLength, request.suggestions, last)); | |
| 132 if (last) { | |
| 133 controller.close(); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 /** | |
| 138 * Return a future that either (a) completes with the resolved compilation | 85 * Return a future that either (a) completes with the resolved compilation |
| 139 * unit when analysis is complete, or (b) completes with null if the | 86 * unit when analysis is complete, or (b) completes with null if the |
| 140 * compilation unit is never going to be resolved. | 87 * compilation unit is never going to be resolved. |
| 141 */ | 88 */ |
| 142 Future<CompilationUnit> waitForAnalysis() { | 89 Future<CompilationUnit> waitForAnalysis() { |
| 143 List<Source> libraries = context.getLibrariesContaining(source); | 90 List<Source> libraries = context.getLibrariesContaining(source); |
| 144 assert(libraries != null); | 91 assert(libraries != null); |
| 145 if (libraries.length == 0) { | 92 if (libraries.length == 0) { |
| 146 return new Future.value(null); | 93 return new Future.value(null); |
| 147 } | 94 } |
| 148 Source libSource = libraries[0]; | 95 Source libSource = libraries[0]; |
| 149 assert(libSource != null); | 96 assert(libSource != null); |
| 150 return context | 97 return context |
| 151 .computeResolvedCompilationUnitAsync(source, libSource) | 98 .computeResolvedCompilationUnitAsync(source, libSource) |
| 152 .catchError((_) { | 99 .catchError((_) { |
| 153 // This source file is not scheduled for analysis, so a resolved | 100 // This source file is not scheduled for analysis, so a resolved |
| 154 // compilation unit is never going to get computed. | 101 // compilation unit is never going to get computed. |
| 155 return null; | 102 return null; |
| 156 }, test: (e) => e is AnalysisNotScheduledError); | 103 }, test: (e) => e is AnalysisNotScheduledError); |
| 157 } | 104 } |
| 158 } | 105 } |
| 159 | |
| 160 /** | |
| 161 * The context in which the completion is requested. | |
| 162 */ | |
| 163 class DartCompletionRequest extends CompletionRequestImpl { | |
| 164 /** | |
| 165 * The list of suggestions to be sent to the client. | |
| 166 */ | |
| 167 final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[]; | |
| 168 | |
| 169 /** | |
| 170 * The set of completions used to prevent duplicates | |
| 171 */ | |
| 172 final Set<String> _completions = new Set<String>(); | |
| 173 | |
| 174 DartCompletionRequest( | |
| 175 AnalysisContext context, | |
| 176 ResourceProvider resourceProvider, | |
| 177 SearchEngine searchEngine, | |
| 178 Source source, | |
| 179 int offset) | |
| 180 : super(context, resourceProvider, searchEngine, source, offset); | |
| 181 | |
| 182 factory DartCompletionRequest.from(CompletionRequestImpl request) => | |
| 183 new DartCompletionRequest(request.context, request.resourceProvider, | |
| 184 request.searchEngine, request.source, request.offset); | |
| 185 | |
| 186 /** | |
| 187 * The list of suggestions to be sent to the client. | |
| 188 */ | |
| 189 Iterable<CompletionSuggestion> get suggestions => _suggestions; | |
| 190 | |
| 191 /** | |
| 192 * Add the given suggestion to the list that is returned to the client as long | |
| 193 * as a suggestion with an identical completion has not already been added. | |
| 194 */ | |
| 195 void addSuggestion(CompletionSuggestion suggestion) { | |
| 196 if (_completions.add(suggestion.completion)) { | |
| 197 _suggestions.add(suggestion); | |
| 198 } | |
| 199 } | |
| 200 } | |
| OLD | NEW |