| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 | 6 |
| 7 import 'package:analysis_server/src/provisional/completion/completion_core.dart' | 7 import 'package:analysis_server/src/provisional/completion/completion_core.dart' |
| 8 show CompletionContributor, CompletionRequest; | 8 show CompletionContributor, CompletionRequest; |
| 9 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; | 9 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; |
| 10 import 'package:analysis_server/src/services/completion/completion_core.dart'; | 10 import 'package:analysis_server/src/services/completion/completion_core.dart'; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 CompletionPerformance performance = | 65 CompletionPerformance performance = |
| 66 (request as CompletionRequestImpl).performance; | 66 (request as CompletionRequestImpl).performance; |
| 67 DartCompletionRequestImpl dartRequest = | 67 DartCompletionRequestImpl dartRequest = |
| 68 await DartCompletionRequestImpl.from(request); | 68 await DartCompletionRequestImpl.from(request); |
| 69 | 69 |
| 70 // Don't suggest in comments. | 70 // Don't suggest in comments. |
| 71 if (dartRequest.target.isCommentText) { | 71 if (dartRequest.target.isCommentText) { |
| 72 return EMPTY_LIST; | 72 return EMPTY_LIST; |
| 73 } | 73 } |
| 74 | 74 |
| 75 ReplacementRange range = | 75 SourceRange range = |
| 76 new ReplacementRange.compute(dartRequest.offset, dartRequest.target); | 76 dartRequest.target.computeReplacementRange(dartRequest.offset); |
| 77 (request as CompletionRequestImpl) | 77 (request as CompletionRequestImpl) |
| 78 ..replacementOffset = range.offset | 78 ..replacementOffset = range.offset |
| 79 ..replacementLength = range.length; | 79 ..replacementLength = range.length; |
| 80 | 80 |
| 81 // Request Dart specific completions from each contributor | 81 // Request Dart specific completions from each contributor |
| 82 Map<String, CompletionSuggestion> suggestionMap = | 82 Map<String, CompletionSuggestion> suggestionMap = |
| 83 <String, CompletionSuggestion>{}; | 83 <String, CompletionSuggestion>{}; |
| 84 List<DartCompletionContributor> contributors = <DartCompletionContributor>[ | 84 List<DartCompletionContributor> contributors = <DartCompletionContributor>[ |
| 85 new ArgListContributor(), | 85 new ArgListContributor(), |
| 86 new CombinatorContributor(), | 86 new CombinatorContributor(), |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 request.source, | 272 request.source, |
| 273 request.offset, | 273 request.offset, |
| 274 unit, | 274 unit, |
| 275 request, | 275 request, |
| 276 performance); | 276 performance); |
| 277 | 277 |
| 278 performance.logElapseTime(BUILD_REQUEST_TAG); | 278 performance.logElapseTime(BUILD_REQUEST_TAG); |
| 279 return dartRequest; | 279 return dartRequest; |
| 280 } | 280 } |
| 281 } | 281 } |
| 282 | |
| 283 /** | |
| 284 * Utility class for computing the code completion replacement range | |
| 285 */ | |
| 286 class ReplacementRange { | |
| 287 int offset; | |
| 288 int length; | |
| 289 | |
| 290 ReplacementRange(this.offset, this.length); | |
| 291 | |
| 292 factory ReplacementRange.compute(int requestOffset, CompletionTarget target) { | |
| 293 bool isKeywordOrIdentifier(Token token) => | |
| 294 token.type.isKeyword || token.type == TokenType.IDENTIFIER; | |
| 295 | |
| 296 //TODO(danrubel) Ideally this needs to be pushed down into the contributors | |
| 297 // but that implies that each suggestion can have a different | |
| 298 // replacement offsent/length which would mean an API change | |
| 299 | |
| 300 var entity = target.entity; | |
| 301 Token token = entity is AstNode ? entity.beginToken : entity; | |
| 302 if (token != null && requestOffset < token.offset) { | |
| 303 token = token.previous; | |
| 304 } | |
| 305 if (token != null) { | |
| 306 if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) { | |
| 307 // If the insertion point is at the beginning of the current token | |
| 308 // and the current token is not an identifier | |
| 309 // then check the previous token to see if it should be replaced | |
| 310 token = token.previous; | |
| 311 } | |
| 312 if (token != null && isKeywordOrIdentifier(token)) { | |
| 313 if (token.offset <= requestOffset && requestOffset <= token.end) { | |
| 314 // Replacement range for typical identifier completion | |
| 315 return new ReplacementRange(token.offset, token.length); | |
| 316 } | |
| 317 } | |
| 318 if (token is StringToken) { | |
| 319 SimpleStringLiteral uri = | |
| 320 astFactory.simpleStringLiteral(token, token.lexeme); | |
| 321 Keyword keyword = token.previous?.keyword; | |
| 322 if (keyword == Keyword.IMPORT || | |
| 323 keyword == Keyword.EXPORT || | |
| 324 keyword == Keyword.PART) { | |
| 325 int start = uri.contentsOffset; | |
| 326 var end = uri.contentsEnd; | |
| 327 if (start <= requestOffset && requestOffset <= end) { | |
| 328 // Replacement range for import URI | |
| 329 return new ReplacementRange(start, end - start); | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 } | |
| 334 return new ReplacementRange(requestOffset, 0); | |
| 335 } | |
| 336 } | |
| OLD | NEW |