| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library services.completion.contributor.dart.importuri; |
| |
| import 'dart:async'; |
| import 'dart:collection'; |
| |
| import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/generated/ast.dart'; |
| import 'package:analyzer/src/generated/sdk.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:path/path.dart'; |
| |
| import '../../protocol_server.dart' |
| show CompletionSuggestion, CompletionSuggestionKind; |
| |
| /** |
| * A contributor for calculating uri suggestions |
| * for import and part directives. |
| */ |
| class ImportUriContributor extends DartCompletionContributor { |
| _ImportUriSuggestionBuilder builder; |
| |
| @override |
| bool computeFast(DartCompletionRequest request) { |
| builder = new _ImportUriSuggestionBuilder(request); |
| return builder.computeFast(request.target.containingNode); |
| } |
| |
| @override |
| Future<bool> computeFull(DartCompletionRequest request) { |
| return new Future.value(false); |
| } |
| } |
| |
| class _ImportUriSuggestionBuilder extends SimpleAstVisitor { |
| final DartCompletionRequest request; |
| HashSet<String> _importedUris; |
| |
| _ImportUriSuggestionBuilder(this.request); |
| |
| bool computeFast(AstNode node) { |
| node.accept(this); |
| return true; |
| } |
| |
| @override |
| visitSimpleStringLiteral(SimpleStringLiteral node) { |
| AstNode parent = node.parent; |
| if (parent is ImportDirective && parent.uri == node) { |
| String partial = node.literal.lexeme.substring( |
| node.contentsOffset - node.offset, request.offset - node.offset); |
| _computeImportedUris(); |
| request.replacementOffset = node.contentsOffset; |
| request.replacementLength = node.contentsEnd - node.contentsOffset; |
| _addDartSuggestions(); |
| _addPackageSuggestions(partial); |
| _addFileSuggestions(partial); |
| } else if (parent is PartDirective && parent.uri == node) { |
| String partial = node.literal.lexeme.substring( |
| node.contentsOffset - node.offset, request.offset - node.offset); |
| _computeImportedUris(); |
| request.replacementOffset = node.contentsOffset; |
| request.replacementLength = node.contentsEnd - node.contentsOffset; |
| _addFileSuggestions(partial); |
| } |
| } |
| |
| void _addDartSuggestions() { |
| _addSuggestion('dart:'); |
| SourceFactory factory = request.context.sourceFactory; |
| for (SdkLibrary lib in factory.dartSdk.sdkLibraries) { |
| if (!lib.isInternal && !lib.isImplementation) { |
| if (!lib.shortName.startsWith('dart:_')) { |
| _addSuggestion(lib.shortName); |
| } |
| } |
| } |
| } |
| |
| void _addFileSuggestions(String partial) { |
| Source source = request.source; |
| String sourceFullName = source.fullName; |
| String sourceShortName = source.shortName; |
| String dirPath = (partial.endsWith('/') || partial.endsWith(separator)) |
| ? partial |
| : dirname(partial); |
| String prefix = dirPath == '.' ? '' : dirPath; |
| if (isRelative(dirPath)) { |
| String sourceDir = dirname(sourceFullName); |
| if (isAbsolute(sourceDir)) { |
| dirPath = join(sourceDir, dirPath); |
| } else { |
| return; |
| } |
| } |
| Resource dir = request.resourceProvider.getResource(dirPath); |
| if (dir is Folder) { |
| for (Resource child in dir.getChildren()) { |
| String completion; |
| if (child is Folder) { |
| completion = '$prefix${child.shortName}$separator'; |
| } else { |
| completion = '$prefix${child.shortName}'; |
| } |
| if (completion != sourceShortName && completion != sourceFullName) { |
| _addSuggestion(completion); |
| } |
| } |
| } |
| } |
| |
| void _addPackageFolderSuggestions( |
| String partial, String prefix, Folder folder) { |
| for (Resource child in folder.getChildren()) { |
| if (child is Folder) { |
| String childPrefix = '$prefix${child.shortName}/'; |
| _addSuggestion(childPrefix); |
| if (partial.startsWith(childPrefix)) { |
| _addPackageFolderSuggestions(partial, childPrefix, child); |
| } |
| } else { |
| _addSuggestion('$prefix${child.shortName}'); |
| } |
| } |
| } |
| |
| void _addPackageSuggestions(String partial) { |
| SourceFactory factory = request.context.sourceFactory; |
| Map<String, List<Folder>> packageMap = factory.packageMap; |
| if (packageMap != null) { |
| _addSuggestion('package:'); |
| packageMap.forEach((String pkgName, List<Folder> folders) { |
| String prefix = 'package:$pkgName/'; |
| _addSuggestion(prefix); |
| for (Folder folder in folders) { |
| if (folder.exists) { |
| _addPackageFolderSuggestions(partial, prefix, folder); |
| } |
| } |
| }); |
| } |
| } |
| |
| void _addSuggestion(String completion) { |
| if (!_importedUris.contains(completion)) { |
| request.addSuggestion(new CompletionSuggestion( |
| CompletionSuggestionKind.IMPORT, DART_RELEVANCE_DEFAULT, completion, |
| completion.length, 0, false, false)); |
| } |
| } |
| |
| void _computeImportedUris() { |
| _importedUris = new HashSet<String>(); |
| _importedUris.add('dart:core'); |
| for (Directive directive in request.unit.directives) { |
| if (directive is ImportDirective) { |
| String uri = directive.uriContent; |
| if (uri != null && uri.length > 0) { |
| _importedUris.add(uri); |
| } |
| } |
| } |
| } |
| } |