Merge pull request #2134 from Microsoft/completionForExports

Completion for exports
This commit is contained in:
Vladimir Matveev
2015-02-24 18:46:04 -08:00
13 changed files with 146 additions and 13 deletions
+22 -13
View File
@@ -2,6 +2,11 @@
module ts.formatting {
export module SmartIndenter {
const enum Value {
Unknown = -1
}
export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number {
if (position > sourceFile.text.length) {
return 0; // past EOF
@@ -29,7 +34,7 @@ module ts.formatting {
if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) {
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
var actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options);
if (actualIndentation !== -1) {
if (actualIndentation !== Value.Unknown) {
return actualIndentation;
}
}
@@ -57,7 +62,7 @@ module ts.formatting {
// check if current node is a list item - if yes, take indentation from it
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
if (actualIndentation !== -1) {
if (actualIndentation !== Value.Unknown) {
return actualIndentation;
}
@@ -101,7 +106,7 @@ module ts.formatting {
if (useActualIndentation) {
// check if current node is a list item - if yes, take indentation from it
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
if (actualIndentation !== -1) {
if (actualIndentation !== Value.Unknown) {
return actualIndentation + indentationDelta;
}
}
@@ -113,7 +118,7 @@ module ts.formatting {
if (useActualIndentation) {
// try to fetch actual indentation for current node from source text
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
if (actualIndentation !== -1) {
if (actualIndentation !== Value.Unknown) {
return actualIndentation + indentationDelta;
}
}
@@ -142,18 +147,22 @@ module ts.formatting {
}
/*
* Function returns -1 if indentation cannot be determined
* Function returns Value.Unknown if indentation cannot be determined
*/
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number {
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
var commaItemInfo = findListItemInfo(commaToken);
Debug.assert(commaItemInfo && commaItemInfo.listItemIndex > 0);
// The item we're interested in is right before the comma
return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options);
if (commaItemInfo && commaItemInfo.listItemIndex > 0) {
return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options);
}
else {
// handle broken code gracefully
return Value.Unknown;
}
}
/*
* Function returns -1 if actual indentation for node should not be used (i.e because node is nested expression)
* Function returns Value.Unknown if actual indentation for node should not be used (i.e because node is nested expression)
*/
function getActualIndentationForNode(current: Node,
parent: Node,
@@ -170,7 +179,7 @@ module ts.formatting {
(parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine);
if (!useActualIndentation) {
return -1;
return Value.Unknown;
}
return findColumnForFirstNonWhitespaceCharacterInLine(currentLineAndChar, sourceFile, options);
@@ -271,11 +280,11 @@ module ts.formatting {
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number {
var containingList = getContainingList(node, sourceFile);
return containingList ? getActualIndentationFromList(containingList) : -1;
return containingList ? getActualIndentationFromList(containingList) : Value.Unknown;
function getActualIndentationFromList(list: Node[]): number {
var index = indexOf(list, node);
return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : -1;
return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : Value.Unknown;
}
}
@@ -298,7 +307,7 @@ module ts.formatting {
lineAndCharacter = getStartLineAndCharacterForNode(list[i], sourceFile);
}
return -1;
return Value.Unknown;
}
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number {
+49
View File
@@ -2403,6 +2403,19 @@ module ts {
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
}
}
else if (getAncestor(previousToken, SyntaxKind.ImportClause)) {
// cursor is in import clause
// try to show exported member for imported module
isMemberCompletion = true;
isNewIdentifierLocation = true;
if (showCompletionsInImportsClause(previousToken)) {
var importDeclaration = <ImportDeclaration>getAncestor(previousToken, SyntaxKind.ImportDeclaration);
Debug.assert(importDeclaration !== undefined);
var exports = typeInfoResolver.getExportsOfExternalModule(importDeclaration);
var filteredExports = filterModuleExports(exports, importDeclaration);
getCompletionEntriesFromSymbols(filteredExports, activeCompletionSession);
}
}
else {
// Get scope members
isMemberCompletion = false;
@@ -2453,6 +2466,18 @@ module ts {
return result;
}
function showCompletionsInImportsClause(node: Node): boolean {
if (node) {
// import {|
// import {a,|
if (node.kind === SyntaxKind.OpenBraceToken || node.kind === SyntaxKind.CommaToken) {
return node.parent.kind === SyntaxKind.NamedImports;
}
}
return false;
}
function isNewIdentifierDefinitionLocation(previousToken: Node): boolean {
if (previousToken) {
var containingNodeKind = previousToken.parent.kind;
@@ -2664,6 +2689,28 @@ module ts {
return false;
}
function filterModuleExports(exports: Symbol[], importDeclaration: ImportDeclaration): Symbol[] {
var exisingImports: Map<boolean> = {};
if (!importDeclaration.importClause) {
return exports;
}
if (importDeclaration.importClause.namedBindings &&
importDeclaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
forEach((<NamedImports>importDeclaration.importClause.namedBindings).elements, el => {
var name = el.propertyName || el.name;
exisingImports[name.text] = true;
});
}
if (isEmpty(exisingImports)) {
return exports;
}
return filter(exports, e => !lookUp(exisingImports, e.name));
}
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
return contextualMemberSymbols;
@@ -4694,6 +4741,8 @@ module ts {
return SemanticMeaning.Namespace;
}
case SyntaxKind.NamedImports:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;