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' |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 }); | 139 }); |
140 } | 140 } |
141 | 141 |
142 /** | 142 /** |
143 * Compute suggestions based upon cached information only | 143 * Compute suggestions based upon cached information only |
144 * then send an initial response to the client. | 144 * then send an initial response to the client. |
145 * Return a list of contributors for which [computeFull] should be called | 145 * Return a list of contributors for which [computeFull] should be called |
146 */ | 146 */ |
147 List<DartCompletionContributor> computeFast( | 147 List<DartCompletionContributor> computeFast( |
148 DartCompletionRequest request, CompletionPerformance performance) { | 148 DartCompletionRequest request, CompletionPerformance performance) { |
149 bool isKeywordOrIdentifier(Token token) => | |
150 token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER; | |
151 | |
152 return performance.logElapseTime('computeFast', () { | 149 return performance.logElapseTime('computeFast', () { |
153 CompilationUnit unit = context.parseCompilationUnit(source); | 150 CompilationUnit unit = context.parseCompilationUnit(source); |
154 request.unit = unit; | 151 request.unit = unit; |
155 request.target = new CompletionTarget.forOffset(unit, request.offset); | 152 request.target = new CompletionTarget.forOffset(unit, request.offset); |
156 request.replacementOffset = request.offset; | |
157 request.replacementLength = 0; | |
158 if (request.offset < 0 || request.offset > unit.end) { | 153 if (request.offset < 0 || request.offset > unit.end) { |
| 154 request.replacementOffset = request.offset; |
| 155 request.replacementLength = 0; |
159 sendResults(request, true); | 156 sendResults(request, true); |
160 return []; | 157 return []; |
161 } | 158 } |
162 | 159 |
163 var entity = request.target.entity; | 160 ReplacementRange range = |
164 Token token = entity is AstNode ? entity.beginToken : entity; | 161 new ReplacementRange.compute(request.offset, request.target); |
165 if (token != null && request.offset < token.offset) { | 162 request.replacementOffset = range.offset; |
166 token = token.previous; | 163 request.replacementLength = range.length; |
167 } | |
168 if (token != null) { | |
169 if (request.offset == token.offset && !isKeywordOrIdentifier(token)) { | |
170 // If the insertion point is at the beginning of the current token | |
171 // and the current token is not an identifier | |
172 // then check the previous token to see if it should be replaced | |
173 token = token.previous; | |
174 } | |
175 if (token != null && isKeywordOrIdentifier(token)) { | |
176 if (token.offset <= request.offset && request.offset <= token.end) { | |
177 request.replacementOffset = token.offset; | |
178 request.replacementLength = token.length; | |
179 } | |
180 } | |
181 } | |
182 | 164 |
183 List<DartCompletionContributor> todo = new List.from(contributors); | 165 List<DartCompletionContributor> todo = new List.from(contributors); |
184 todo.removeWhere((DartCompletionContributor c) { | 166 todo.removeWhere((DartCompletionContributor c) { |
185 return performance.logElapseTime('computeFast ${c.runtimeType}', () { | 167 return performance.logElapseTime('computeFast ${c.runtimeType}', () { |
186 return c.computeFast(request); | 168 return c.computeFast(request); |
187 }); | 169 }); |
188 }); | 170 }); |
189 return todo; | 171 return todo; |
190 }); | 172 }); |
191 } | 173 } |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 parameterNames: suggestion.parameterNames, | 426 parameterNames: suggestion.parameterNames, |
445 parameterTypes: suggestion.parameterTypes, | 427 parameterTypes: suggestion.parameterTypes, |
446 requiredParameterCount: suggestion.requiredParameterCount, | 428 requiredParameterCount: suggestion.requiredParameterCount, |
447 hasNamedParameters: suggestion.hasNamedParameters, | 429 hasNamedParameters: suggestion.hasNamedParameters, |
448 returnType: suggestion.returnType, | 430 returnType: suggestion.returnType, |
449 element: suggestion.element); | 431 element: suggestion.element); |
450 } | 432 } |
451 } | 433 } |
452 } | 434 } |
453 } | 435 } |
| 436 |
| 437 /** |
| 438 * Utility class for computing the code completion replacement range |
| 439 */ |
| 440 class ReplacementRange { |
| 441 int offset; |
| 442 int length; |
| 443 |
| 444 ReplacementRange(this.offset, this.length); |
| 445 |
| 446 factory ReplacementRange.compute(int requestOffset, CompletionTarget target) { |
| 447 bool isKeywordOrIdentifier(Token token) => |
| 448 token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER; |
| 449 |
| 450 var entity = target.entity; |
| 451 Token token = entity is AstNode ? entity.beginToken : entity; |
| 452 if (token != null && requestOffset < token.offset) { |
| 453 token = token.previous; |
| 454 } |
| 455 if (token != null) { |
| 456 if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) { |
| 457 // If the insertion point is at the beginning of the current token |
| 458 // and the current token is not an identifier |
| 459 // then check the previous token to see if it should be replaced |
| 460 token = token.previous; |
| 461 } |
| 462 if (token != null && isKeywordOrIdentifier(token)) { |
| 463 if (token.offset <= requestOffset && requestOffset <= token.end) { |
| 464 return new ReplacementRange(token.offset, token.length); |
| 465 } |
| 466 } |
| 467 } |
| 468 return new ReplacementRange(requestOffset, 0); |
| 469 } |
| 470 } |
OLD | NEW |