blob: 574931b90149738f5d7565e4991c0c2df7d3030a [file] [log] [blame]
// 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 'dart:core' hide Resource;
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);
}
}
}
}
}