| 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'; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 * in the given completion context are resolved. | 41 * in the given completion context are resolved. |
| 42 * Returns `true` if the receiver modified the list of suggestions. | 42 * Returns `true` if the receiver modified the list of suggestions. |
| 43 */ | 43 */ |
| 44 Future<bool> computeFull(DartCompletionRequest request); | 44 Future<bool> computeFull(DartCompletionRequest request); |
| 45 } | 45 } |
| 46 | 46 |
| 47 /** | 47 /** |
| 48 * Manages code completion for a given Dart file completion request. | 48 * Manages code completion for a given Dart file completion request. |
| 49 */ | 49 */ |
| 50 class DartCompletionManager extends CompletionManager { | 50 class DartCompletionManager extends CompletionManager { |
| 51 final DartCompletionRequest request; | 51 final SearchEngine searchEngine; |
| 52 final AnalysisContext context; | |
| 53 final Source source; | |
| 54 final int offset; | |
| 55 final CompletionPerformance performance; | |
| 56 final DartCompletionCache cache; | 52 final DartCompletionCache cache; |
| 57 List<DartCompletionComputer> computers; | 53 List<DartCompletionComputer> computers; |
| 58 | 54 |
| 59 DartCompletionManager(this.request, this.context, this.source, this.offset, | 55 DartCompletionManager(AnalysisContext context, this.searchEngine, |
| 60 this.cache, this.performance) | 56 Source source, this.cache) |
| 61 : computers = [ | 57 : super(context, source), |
| 58 computers = [ |
| 62 new KeywordComputer(), | 59 new KeywordComputer(), |
| 63 new LocalComputer(), | 60 new LocalComputer(), |
| 64 new ArgListComputer(), | 61 new ArgListComputer(), |
| 65 new CombinatorComputer(), | 62 new CombinatorComputer(), |
| 66 new ImportedComputer(), | 63 new ImportedComputer(), |
| 67 new InvocationComputer()]; | 64 new InvocationComputer()]; |
| 68 | 65 |
| 69 /** | 66 /** |
| 70 * Create a new initialized Dart source completion manager | 67 * Create a new initialized Dart source completion manager |
| 71 */ | 68 */ |
| 72 factory DartCompletionManager.create(AnalysisContext context, | 69 factory DartCompletionManager.create(AnalysisContext context, |
| 73 SearchEngine searchEngine, Source source, int offset, CompletionCache oldC
ache, | 70 SearchEngine searchEngine, Source source, CompletionCache oldCache) { |
| 74 CompletionPerformance performance) { | |
| 75 DartCompletionCache newCache; | 71 DartCompletionCache newCache; |
| 76 if (oldCache is DartCompletionCache) { | 72 if (oldCache is DartCompletionCache) { |
| 77 if (oldCache.context == context && oldCache.source == source) { | 73 if (oldCache.context == context && oldCache.source == source) { |
| 78 newCache = oldCache; | 74 newCache = oldCache; |
| 79 } | 75 } |
| 80 } | 76 } |
| 81 if (newCache == null) { | 77 if (newCache == null) { |
| 82 newCache = new DartCompletionCache(context, source); | 78 newCache = new DartCompletionCache(context, source); |
| 83 } | 79 } |
| 84 return new DartCompletionManager( | 80 return new DartCompletionManager(context, searchEngine, source, newCache); |
| 85 new DartCompletionRequest(context, searchEngine, source, offset, newCach
e), | |
| 86 context, | |
| 87 source, | |
| 88 offset, | |
| 89 newCache, | |
| 90 performance); | |
| 91 } | 81 } |
| 92 | 82 |
| 93 @override | 83 @override |
| 94 CompletionCache get completionCache => cache; | 84 void compute(CompletionRequest completionRequest) { |
| 95 | 85 DartCompletionRequest request = new DartCompletionRequest( |
| 96 @override | 86 context, |
| 97 void compute() { | 87 searchEngine, |
| 98 performance.logElapseTime('compute', () { | 88 source, |
| 99 computeFast(); | 89 completionRequest.offset, |
| 90 cache, |
| 91 completionRequest.performance); |
| 92 request.performance.logElapseTime('compute', () { |
| 93 computeFast(request); |
| 100 if (!computers.isEmpty) { | 94 if (!computers.isEmpty) { |
| 101 computeFull(); | 95 computeFull(request); |
| 102 } | 96 } |
| 103 }); | 97 }); |
| 104 } | 98 } |
| 105 | 99 |
| 106 /** | 100 /** |
| 107 * Compute suggestions based upon cached information only | 101 * Compute suggestions based upon cached information only |
| 108 * then send an initial response to the client. | 102 * then send an initial response to the client. |
| 109 */ | 103 */ |
| 110 void computeFast() { | 104 void computeFast(DartCompletionRequest request) { |
| 111 performance.logElapseTime('computeFast', () { | 105 request.performance.logElapseTime('computeFast', () { |
| 112 CompilationUnit unit = context.parseCompilationUnit(source); | 106 CompilationUnit unit = context.parseCompilationUnit(source); |
| 113 request.unit = unit; | 107 request.unit = unit; |
| 114 request.node = new NodeLocator.con1(offset).searchWithin(unit); | 108 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); |
| 115 request.node.accept(new _ReplacementOffsetBuilder(request)); | 109 request.node.accept(new _ReplacementOffsetBuilder(request)); |
| 116 computers.removeWhere((DartCompletionComputer c) { | 110 computers.removeWhere((DartCompletionComputer c) { |
| 117 return performance.logElapseTime('computeFast ${c.runtimeType}', () { | 111 return request.performance.logElapseTime( |
| 112 'computeFast ${c.runtimeType}', |
| 113 () { |
| 118 return c.computeFast(request); | 114 return c.computeFast(request); |
| 119 }); | 115 }); |
| 120 }); | 116 }); |
| 121 sendResults(computers.isEmpty); | 117 sendResults(request, computers.isEmpty); |
| 122 }); | 118 }); |
| 123 } | 119 } |
| 124 | 120 |
| 125 /** | 121 /** |
| 126 * If there is remaining work to be done, then wait for the unit to be | 122 * If there is remaining work to be done, then wait for the unit to be |
| 127 * resolved and request that each remaining computer finish their work. | 123 * resolved and request that each remaining computer finish their work. |
| 128 */ | 124 */ |
| 129 void computeFull() { | 125 void computeFull(DartCompletionRequest request) { |
| 130 performance.logStartTime('waitForAnalysis'); | 126 request.performance.logStartTime('waitForAnalysis'); |
| 131 waitForAnalysis().then((CompilationUnit unit) { | 127 waitForAnalysis().then((CompilationUnit unit) { |
| 132 performance.logElapseTime('waitForAnalysis'); | 128 request.performance.logElapseTime('waitForAnalysis'); |
| 133 if (unit == null) { | 129 if (unit == null) { |
| 134 sendResults(true); | 130 sendResults(request, true); |
| 135 return; | 131 return; |
| 136 } | 132 } |
| 137 performance.logElapseTime('computeFull', () { | 133 request.performance.logElapseTime('computeFull', () { |
| 138 request.unit = unit; | 134 request.unit = unit; |
| 139 request.node = new NodeLocator.con1(offset).searchWithin(unit); | 135 request.node = new NodeLocator.con1(request.offset).searchWithin(unit); |
| 140 int count = computers.length; | 136 int count = computers.length; |
| 141 computers.forEach((DartCompletionComputer c) { | 137 computers.forEach((DartCompletionComputer c) { |
| 142 String name = c.runtimeType.toString(); | 138 String name = c.runtimeType.toString(); |
| 143 String completeTag = 'computeFull $name complete'; | 139 String completeTag = 'computeFull $name complete'; |
| 144 performance.logStartTime(completeTag); | 140 request.performance.logStartTime(completeTag); |
| 145 performance.logElapseTime('computeFull $name', () { | 141 request.performance.logElapseTime('computeFull $name', () { |
| 146 c.computeFull(request).then((bool changed) { | 142 c.computeFull(request).then((bool changed) { |
| 147 performance.logElapseTime(completeTag); | 143 request.performance.logElapseTime(completeTag); |
| 148 bool last = --count == 0; | 144 bool last = --count == 0; |
| 149 if (changed || last) { | 145 if (changed || last) { |
| 150 sendResults(last); | 146 sendResults(request, last); |
| 151 } | 147 } |
| 152 }); | 148 }); |
| 153 }); | 149 }); |
| 154 }); | 150 }); |
| 155 }); | 151 }); |
| 156 }); | 152 }); |
| 157 } | 153 } |
| 158 | 154 |
| 159 /** | 155 /** |
| 160 * Send the current list of suggestions to the client. | 156 * Send the current list of suggestions to the client. |
| 161 */ | 157 */ |
| 162 void sendResults(bool last) { | 158 void sendResults(DartCompletionRequest request, bool last) { |
| 163 controller.add( | 159 controller.add( |
| 164 new CompletionResult( | 160 new CompletionResult( |
| 165 request.replacementOffset, | 161 request.replacementOffset, |
| 166 request.replacementLength, | 162 request.replacementLength, |
| 167 request.suggestions, | 163 request.suggestions, |
| 168 last)); | 164 last)); |
| 169 if (last) { | 165 if (last) { |
| 170 controller.close(); | 166 controller.close(); |
| 171 } | 167 } |
| 172 } | 168 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 185 } | 181 } |
| 186 } | 182 } |
| 187 //TODO (danrubel) Determine if analysis is complete but unit not resolved | 183 //TODO (danrubel) Determine if analysis is complete but unit not resolved |
| 188 return new Future(waitForAnalysis); | 184 return new Future(waitForAnalysis); |
| 189 } | 185 } |
| 190 } | 186 } |
| 191 | 187 |
| 192 /** | 188 /** |
| 193 * The context in which the completion is requested. | 189 * The context in which the completion is requested. |
| 194 */ | 190 */ |
| 195 class DartCompletionRequest { | 191 class DartCompletionRequest extends CompletionRequest { |
| 196 /** | 192 /** |
| 197 * The analysis context in which the completion is requested. | 193 * The analysis context in which the completion is requested. |
| 198 */ | 194 */ |
| 199 final AnalysisContext context; | 195 final AnalysisContext context; |
| 200 | 196 |
| 201 /** | 197 /** |
| 202 * The search engine for use when building suggestions. | 198 * The search engine for use when building suggestions. |
| 203 */ | 199 */ |
| 204 final SearchEngine searchEngine; | 200 final SearchEngine searchEngine; |
| 205 | 201 |
| 206 /** | 202 /** |
| 207 * The source in which the completion is requested. | 203 * The source in which the completion is requested. |
| 208 */ | 204 */ |
| 209 final Source source; | 205 final Source source; |
| 210 | 206 |
| 211 /** | 207 /** |
| 212 * The offset within the source at which the completion is requested. | |
| 213 */ | |
| 214 final int offset; | |
| 215 | |
| 216 /** | |
| 217 * Cached information from a prior code completion operation. | 208 * Cached information from a prior code completion operation. |
| 218 */ | 209 */ |
| 219 final DartCompletionCache cache; | 210 final DartCompletionCache cache; |
| 220 | 211 |
| 221 /** | 212 /** |
| 222 * The compilation unit in which the completion was requested. This unit | 213 * The compilation unit in which the completion was requested. This unit |
| 223 * may or may not be resolved when [DartCompletionComputer.computeFast] | 214 * may or may not be resolved when [DartCompletionComputer.computeFast] |
| 224 * is called but is resolved when [DartCompletionComputer.computeFull]. | 215 * is called but is resolved when [DartCompletionComputer.computeFull]. |
| 225 */ | 216 */ |
| 226 CompilationUnit unit; | 217 CompilationUnit unit; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 247 * (that is, the number of characters in the existing identifier). | 238 * (that is, the number of characters in the existing identifier). |
| 248 */ | 239 */ |
| 249 int replacementLength; | 240 int replacementLength; |
| 250 | 241 |
| 251 /** | 242 /** |
| 252 * The list of suggestions to be sent to the client. | 243 * The list of suggestions to be sent to the client. |
| 253 */ | 244 */ |
| 254 final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; | 245 final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; |
| 255 | 246 |
| 256 DartCompletionRequest(this.context, this.searchEngine, this.source, | 247 DartCompletionRequest(this.context, this.searchEngine, this.source, |
| 257 this.offset, this.cache); | 248 int offset, this.cache, CompletionPerformance performance) |
| 249 : super(offset, performance); |
| 258 } | 250 } |
| 259 | 251 |
| 260 /** | 252 /** |
| 261 * Visitor used to determine the replacement offset and length | 253 * Visitor used to determine the replacement offset and length |
| 262 * based upon the cursor location. | 254 * based upon the cursor location. |
| 263 */ | 255 */ |
| 264 class _ReplacementOffsetBuilder extends SimpleAstVisitor { | 256 class _ReplacementOffsetBuilder extends SimpleAstVisitor { |
| 265 final DartCompletionRequest request; | 257 final DartCompletionRequest request; |
| 266 | 258 |
| 267 _ReplacementOffsetBuilder(this.request) { | 259 _ReplacementOffsetBuilder(this.request) { |
| 268 request.replacementOffset = request.offset; | 260 request.replacementOffset = request.offset; |
| 269 request.replacementLength = 0; | 261 request.replacementLength = 0; |
| 270 } | 262 } |
| 271 | 263 |
| 272 visitSimpleIdentifier(SimpleIdentifier node) { | 264 visitSimpleIdentifier(SimpleIdentifier node) { |
| 273 request.replacementOffset = node.offset; | 265 request.replacementOffset = node.offset; |
| 274 request.replacementLength = node.length; | 266 request.replacementLength = node.length; |
| 275 } | 267 } |
| 276 } | 268 } |
| OLD | NEW |