Merge branch 'master' into specJakeTask

This commit is contained in:
Anders Hejlsberg 2014-09-26 15:15:11 -07:00
commit 391a477ba0
12 changed files with 299 additions and 115 deletions

View file

@ -18,7 +18,7 @@ There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob
* [Quick tutorial](http://www.typescriptlang.org/Tutorial)
* [Programming handbook](http://www.typescriptlang.org/Handbook)
* [Language specification](http://go.microsoft.com/fwlink/?LinkId=267238)
* [Language specification](https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md)
* [Homepage](http://www.typescriptlang.org/)
## Building

View file

@ -102,9 +102,9 @@ TypeScript is a trademark of Microsoft Corporation.
* [4.14.5 The void Operator](#4.14.5)
* [4.14.6 The typeof Operator](#4.14.6)
* [4.15 Binary Operators](#4.15)
* [4.15.1 The *, /, %, , <<, >>, >>>, &, ^, and | operators](#4.15.1)
* [4.15.1 The *, /, %, , &lt;&lt;, >>, >>>, &, ^, and | operators](#4.15.1)
* [4.15.2 The + operator](#4.15.2)
* [4.15.3 The <, >, <=, >=, ==, !=, ===, and !== operators](#4.15.3)
* [4.15.3 The &lt;, >, &lt;=, >=, ==, !=, ===, and !== operators](#4.15.3)
* [4.15.4 The instanceof operator](#4.15.4)
* [4.15.5 The in operator](#4.15.5)
* [4.15.6 The && operator](#4.15.6)
@ -1088,7 +1088,7 @@ Since a type parameter represents a multitude of different type arguments, type
### <a name="3.4.1"/>3.4.1 Type Parameter Lists
Class, interface, and function declarations may optionally include lists of type parameters enclosed in < and > brackets. Type parameters are also permitted in call signatures of object, function, and constructor type literals.
Class, interface, and function declarations may optionally include lists of type parameters enclosed in &lt; and > brackets. Type parameters are also permitted in call signatures of object, function, and constructor type literals.
&emsp;&emsp;*TypeParameters:*
&emsp;&emsp;&emsp;`<`&emsp;*TypeParameterList*&emsp;`>`
@ -1149,7 +1149,7 @@ Given the declaration
interface G<T, U extends Function> { }
```
a type reference of the form G<A, B> places no requirements on A but requires B to be assignable to Function.
a type reference of the form G&lt;A, B> places no requirements on A but requires B to be assignable to Function.
The process of substituting type arguments for type parameters in a generic type or generic signature is known as ***instantiating*** the generic type or signature. Instantiation of a generic type or signature can fail if the supplied type arguments do not satisfy the constraints of their corresponding type parameters.
@ -1354,13 +1354,13 @@ Object type literals are the primary form of type literals and are described in
As the table above illustrates, an array type literal is shorthand for a reference to the generic interface type Array in the global module, a function type literal is shorthand for an object type containing a single call signature, and a constructor type literal is shorthand for an object type containing a single construct signature. Note that function and constructor types with multiple call or construct signatures cannot be written as function or constructor type literals but must instead be written as object type literals.
In order to avoid grammar ambiguities, array type literals permit only a restricted set of notations for the element type. Specifically, an *ArrayType* cannot start with a *FunctionType* or *ConstructorType*. To use one of those forms for the element type, an array type must be written using the Array<T> notation. For example, the type
In order to avoid grammar ambiguities, array type literals permit only a restricted set of notations for the element type. Specifically, an *ArrayType* cannot start with a *FunctionType* or *ConstructorType*. To use one of those forms for the element type, an array type must be written using the Array&lt;T> notation. For example, the type
```TypeScript
() => string[]
```
denotes a function returning a string array, not an array of functions returning string. The latter can be expressed using Array<T> notation
denotes a function returning a string array, not an array of functions returning string. The latter can be expressed using Array&lt;T> notation
```TypeScript
Array<() => string>
@ -1833,7 +1833,7 @@ interface List<T> {
}
```
List<T> has a member owner of type List<List<T>>, which has a member owner of type List<List<List<T>>>, which has a member owner of type List<List<List<List<T>>>> and so on, ad infinitum. Since type relationships are determined structurally, possibly exploring the constituent types to their full depth, in order to determine type relationships involving infinitely expanding generic types it may be necessary for the compiler to terminate the recursion at some point with the assumption that no further exploration will change the outcome.
List&lt;T> has a member owner of type List&lt;List&lt;T>>, which has a member owner of type List&lt;List&lt;List&lt;T>>>, which has a member owner of type List&lt;List&lt;List&lt;List&lt;T>>>> and so on, ad infinitum. Since type relationships are determined structurally, possibly exploring the constituent types to their full depth, in order to determine type relationships involving infinitely expanding generic types it may be necessary for the compiler to terminate the recursion at some point with the assumption that no further exploration will change the outcome.
## <a name="3.9"/>3.9 Widened Types
@ -2247,7 +2247,7 @@ A signature is said to be an ***applicable signature*** with respect to an argum
### <a name="4.12.2"/>4.12.2 Type Argument Inference
Given a signature < *T<sub>1</sub>* , *T<sub>2</sub>* , … , *T<sub>n</sub>* > ( *p<sub>1</sub>* : *P<sub>1</sub>* , *p<sub>2</sub>* : *P<sub>2</sub>* , … , *p<sub>m</sub>* : *P<sub>m</sub>* ), where each parameter type *P* references zero or more of the type parameters *T*, and an argument list ( *e<sub>1</sub>* , *e<sub>2</sub>* , … , *e<sub>m</sub>* ), the task of type argument inference is to find a set of type arguments *A<sub>1</sub>*…*A<sub>n</sub>* to substitute for *T<sub>1</sub>*…*T<sub>n</sub>* such that the argument list becomes an applicable signature.
Given a signature &lt; *T<sub>1</sub>* , *T<sub>2</sub>* , … , *T<sub>n</sub>* > ( *p<sub>1</sub>* : *P<sub>1</sub>* , *p<sub>2</sub>* : *P<sub>2</sub>* , … , *p<sub>m</sub>* : *P<sub>m</sub>* ), where each parameter type *P* references zero or more of the type parameters *T*, and an argument list ( *e<sub>1</sub>* , *e<sub>2</sub>* , … , *e<sub>m</sub>* ), the task of type argument inference is to find a set of type arguments *A<sub>1</sub>*…*A<sub>n</sub>* to substitute for *T<sub>1</sub>*…*T<sub>n</sub>* such that the argument list becomes an applicable signature.
The inferred type argument for a particular type parameter is determined from a set of candidate types. Given a type parameter *T*, let *C* denote the widened form (section [3.9](#3.9)) of the best common type (section [3.10](#3.10)) of the set of candidate types *T*. Then,
@ -2337,7 +2337,7 @@ The inclusion of type arguments in the *Arguments* production (section [4.12](#4
f(g<A, B>(7));
```
could be interpreted as a call to f with two arguments, g < A and B > (7). Alternatively, it could be interpreted as a call to f with one argument, which is a call to a generic function g with two type arguments and one regular argument.
could be interpreted as a call to f with two arguments, g &lt; A and B > (7). Alternatively, it could be interpreted as a call to f with one argument, which is a call to a generic function g with two type arguments and one regular argument.
The grammar ambiguity is resolved as follows: In a context where one possible interpretation of a sequence of tokens is an *Arguments* production, if the initial sequence of tokens forms a syntactically correct *TypeArguments* production and is followed by a `(` token, then the sequence of tokens is processed an *Arguments* production, and any other possible interpretation is discarded. Otherwise, the sequence of tokens is not considered an *Arguments* production.
@ -2449,7 +2449,7 @@ In the example above,
The subsections that follow specify the compile-time processing rules of the binary operators. In general, if the operands of a binary operator do not meet the stated requirements, a compile-time error occurs and the result of the operation defaults to type any in further processing. Tables that summarize the compile-time processing rules for operands of the Any type, the Boolean, Number, and String primitive types, and all object types and type parameters (the Object column in the tables) are provided.
### <a name="4.15.1"/>4.15.1 The *, /, %, , <<, >>, >>>, &, ^, and | operators
### <a name="4.15.1"/>4.15.1 The *, /, %, , &lt;&lt;, >>, >>>, &, ^, and | operators
These operators require their operands to be of type Any, the Number primitive type, or an enum type. Operands of an enum type are treated as having the primitive type Number. If one operand is the `null` or `undefine``d` value, it is treated as having the type of the other operand. The result is always of the Number primitive type.
@ -2483,7 +2483,7 @@ var s = getValue() + "";
The example above converts the result of getValue() to a string if it isnt a string already. The type inferred for s is the String primitive type regardless of the return type of getValue.
### <a name="4.15.3"/>4.15.3 The <, >, <=, >=, ==, !=, ===, and !== operators
### <a name="4.15.3"/>4.15.3 The &lt;, >, &lt;=, >=, ==, !=, ===, and !== operators
These operators require one operand type to be identical to or a subtype of the other operand type. The result is always of the Boolean primitive type.
@ -4398,7 +4398,7 @@ The source elements permitted in a TypeScript implementation source file are a s
Declaration source files are restricted to contain declarations only. Declaration source files can be used to declare the static type information associated with existing JavaScript code in an adjunct manner. They are entirely optional but enable the TypeScript compiler and tools to provide better verification and assistance when integrating existing JavaScript code and libraries in a TypeScript application.
Implementation and declaration source files that contain no import or export declarations form the single ***global module***. Entities declared in the global module are in scope everywhere in a program. Initialization order of the source files that make up the global module ultimately depends on the order in which the generated JavaScript files are loaded at run-time (which, for example, may be controlled by <script/> tags that reference the generated JavaScript files).
Implementation and declaration source files that contain no import or export declarations form the single ***global module***. Entities declared in the global module are in scope everywhere in a program. Initialization order of the source files that make up the global module ultimately depends on the order in which the generated JavaScript files are loaded at run-time (which, for example, may be controlled by &lt;script/> tags that reference the generated JavaScript files).
Implementation and declaration source files that contain at least one external import declaration, export assignment, or top-level exported declaration are considered separate ***external modules***. Entities declared in an external module are in scope only in that module, but exported entities can be imported into other modules using import declarations. Initialization order of external modules is determined by the module loader being and is not specified by the TypeScript language. However, it is generally the case that non-circularly dependent modules are automatically loaded and initialized in the correct order.
@ -4408,7 +4408,7 @@ External modules can additionally be declared using *AmbientExternalModuleDeclar
The TypeScript compiler automatically determines a source files dependencies and includes those dependencies in the program being compiled. The determination is made from “reference comments” and external import declarations as follows:
* A comment of the form /// <reference path="…"/> adds a dependency on the source file specified in the path argument. The path is resolved relative to the directory of the containing source file.
* A comment of the form /// &lt;reference path="…"/> adds a dependency on the source file specified in the path argument. The path is resolved relative to the directory of the containing source file.
* An external import declaration that specifies a relative external module name (section [11.2.1](#11.2.1)) resolves the name relative to the directory of the containing source file. If a source file with the resulting path and file extension .ts exists, that file is added as a dependency. Otherwise, if a source file with the resulting path and file extension .d.ts exists, that file is added as a dependency.
* An external import declaration that specifies a top-level external module name (section [11.2.1](#11.2.1)) resolves the name in a host dependent manner (typically by resolving the name relative to a module name space root or searching for the name in a series of directories). If a source file with extension .ts or .d.ts corresponding to the reference is located, that file is added as a dependency.
@ -4619,7 +4619,7 @@ The special
# <a name="12"/>12 Ambients
Ambient declarations are used to provide static typing over existing JavaScript code. Ambient declarations differ from regular declarations in that no JavaScript code is emitted for them. Instead of introducing new variables, functions, classes, enums, or modules, ambient declarations provide type information for entities that exist “ambiently” and are included in a program by external means, for example by referencing a JavaScript library in a <script/> tag.
Ambient declarations are used to provide static typing over existing JavaScript code. Ambient declarations differ from regular declarations in that no JavaScript code is emitted for them. Instead of introducing new variables, functions, classes, enums, or modules, ambient declarations provide type information for entities that exist “ambiently” and are included in a program by external means, for example by referencing a JavaScript library in a &lt;script/> tag.
## <a name="12.1"/>12.1 Ambient Declarations

View file

@ -29,13 +29,13 @@ function convertDocumentToMarkdown(doc) {
}
}
}
function findReplace(findText, findProps, replaceText, replaceProps) {
function findReplace(findText, findOptions, replaceText, replaceOptions) {
var find = doc.range().find;
find.clearFormatting();
setProperties(find, findProps);
setProperties(find, findOptions);
var replace = find.replacement;
replace.clearFormatting();
setProperties(replace, replaceProps);
setProperties(replace, replaceOptions);
find.execute(findText, false, false, false, false, false, true, 0, true, replaceText, 2);
}
function write(s) {
@ -154,6 +154,10 @@ function convertDocumentToMarkdown(doc) {
}
writeBlockEnd();
}
findReplace("<", {}, "&lt;", {});
findReplace("&lt;", { style: "Code" }, "<", {});
findReplace("&lt;", { style: "Code Fragment" }, "<", {});
findReplace("&lt;", { style: "Terminal" }, "<", {});
findReplace("", { font: { subscript: true } }, "<sub>^&</sub>", { font: { subscript: false } });
findReplace("", { style: "Code Fragment" }, "`^&`", { style: -66 });
findReplace("", { style: "Production" }, "*^&*", { style: -66 });

View file

@ -129,6 +129,15 @@ var sys = (function () {
};
})();
interface FindReplaceOptions {
style?: any;
font?: {
bold?: boolean;
italic?: boolean;
subscript?: boolean;
};
}
function convertDocumentToMarkdown(doc: Word.Document): string {
var result: string = "";
@ -152,13 +161,13 @@ function convertDocumentToMarkdown(doc: Word.Document): string {
}
}
function findReplace(findText: string, findProps: {}, replaceText: string, replaceProps: {}) {
function findReplace(findText: string, findOptions: FindReplaceOptions, replaceText: string, replaceOptions: FindReplaceOptions) {
var find = doc.range().find;
find.clearFormatting();
setProperties(find, findProps);
setProperties(find, findOptions);
var replace = find.replacement;
replace.clearFormatting();
setProperties(replace, replaceProps);
setProperties(replace, replaceOptions);
find.execute(findText, false, false, false, false, false, true, 0, true, replaceText, 2);
}
@ -295,6 +304,10 @@ function convertDocumentToMarkdown(doc: Word.Document): string {
writeBlockEnd();
}
findReplace("<", {}, "&lt;", {});
findReplace("&lt;", { style: "Code" }, "<", {});
findReplace("&lt;", { style: "Code Fragment" }, "<", {});
findReplace("&lt;", { style: "Terminal" }, "<", {});
findReplace("", { font: { subscript: true } }, "<sub>^&</sub>", { font: { subscript: false } });
findReplace("", { style: "Code Fragment" }, "`^&`", { style: -66 /* default font */ });
findReplace("", { style: "Production" }, "*^&*", { style: -66 /* default font */});

View file

@ -925,38 +925,17 @@ module ts {
var displayPartWriters: DisplayPartsSymbolWriter[] = [];
var stringWriters: StringSymbolWriter[] = [];
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
var flags = symbol.flags;
if (flags & SymbolFlags.Variable) {
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter
? SymbolDisplayPartKind.parameterName
: SymbolDisplayPartKind.localName;
}
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
return SymbolDisplayPartKind.text;
}
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
if (displayPartWriters.length == 0) {
var displayParts: SymbolDisplayPart[] = [];
return {
displayParts: () => displayParts,
writeKind: (text, kind) => displayParts.push(new SymbolDisplayPart(text, kind, undefined)),
writeSymbol: (text, symbol) => displayParts.push(new SymbolDisplayPart(text, displayPartKind(symbol), symbol)),
writeSymbol: (text, symbol) => displayParts.push(symbolPart(text, symbol)),
// Completely ignore indentation for display part writers. And map newlines to
// a single space.
writeLine: () => displayParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)),
writeLine: () => displayParts.push(spacePart()),
increaseIndent: () => { },
decreaseIndent: () => { },
clear: () => displayParts = [],
@ -7693,4 +7672,49 @@ module ts {
return checker;
}
export function spacePart() {
return new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined);
}
export function keywordPart(kind: SyntaxKind) {
return new SymbolDisplayPart(tokenToString(kind), SymbolDisplayPartKind.keyword, undefined);
}
export function punctuationPart(kind: SyntaxKind) {
return new SymbolDisplayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation, undefined);
}
export function operatorPart(kind: SyntaxKind) {
return new SymbolDisplayPart(tokenToString(kind), SymbolDisplayPartKind.operator, undefined);
}
export function textPart(text: string) {
return new SymbolDisplayPart(text, SymbolDisplayPartKind.text, undefined);
}
export function symbolPart(text: string, symbol: Symbol) {
return new SymbolDisplayPart(text, displayPartKind(symbol), symbol)
}
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
var flags = symbol.flags;
if (flags & SymbolFlags.Variable) {
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter
? SymbolDisplayPartKind.parameterName
: SymbolDisplayPartKind.localName;
}
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
return SymbolDisplayPartKind.text;
}
}

View file

@ -1199,6 +1199,10 @@ module ts {
kind: SymbolDisplayPartKind[this.kind]
};
}
public static toString(parts: SymbolDisplayPart[]) {
return parts.map(p => p.text).join("");
}
}
export enum SymbolDisplayPartKind {

View file

@ -820,7 +820,10 @@ module FourSlash {
this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI';
var help = this.getActiveSignatureHelpItem();
assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected);
assert.equal(
ts.SymbolDisplayPart.toString(help.prefixDisplayParts) +
help.parameters.map(p => ts.SymbolDisplayPart.toString(p.displayParts)).join(ts.SymbolDisplayPart.toString(help.separatorDisplayParts)) +
ts.SymbolDisplayPart.toString(help.suffixDisplayParts), expected);
}
public verifyCurrentParameterIsVariable(isVariable: boolean) {
@ -844,7 +847,7 @@ module FourSlash {
var activeSignature = this.getActiveSignatureHelpItem();
var activeParameter = this.getActiveParameter();
assert.equal(activeParameter.display, parameter);
assert.equal(ts.SymbolDisplayPart.toString(activeParameter.displayParts), parameter);
}
public verifyCurrentParameterHelpDocComment(docComment: string) {
@ -956,10 +959,9 @@ module FourSlash {
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var item = help.items[help.selectedItemIndex];
var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start());
// Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed
var currentParam = state === undefined ? 0 : state.argumentIndex;
var currentParam = help.argumentIndex < 0 ? 0 : help.argumentIndex;
return item.parameters[currentParam];
}

View file

@ -7,7 +7,7 @@ class UnitTestRunner extends RunnerBase {
}
public initializeTests() {
this.tests = this.enumerateFiles('tests/cases/unittests/services');
this.tests = this.enumerateFiles('tests/cases/unittests/services', /\.ts/i);
var outfile = new Harness.Compiler.WriterAggregator()
var outerr = new Harness.Compiler.WriterAggregator();

View file

@ -151,7 +151,7 @@ module TypeScript.Services {
}
}
private getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems?: ts.NavigationBarItem[], indent: number = 0): ts.NavigationBarItem {
private getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[]= [], indent: number = 0): ts.NavigationBarItem {
return {
text: text,
kind: kind,

View file

@ -651,15 +651,19 @@ module ts {
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo;
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails;
getTypeAtPosition(fileName: string, position: number): TypeInfo;
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo;
// Obsolete. Use getQuickInfoAtPosition instead.
getTypeAtPosition(fileName: string, position: number): TypeInfo;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TypeScript.TextSpan;
getBreakpointStatementAtPosition(fileName: string, position: number): TypeScript.TextSpan;
getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems;
getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): SignatureHelpState;
// Obsolete. Use getSignatureHelpItems instead.
getSignatureAtPosition(fileName: string, position: number): SignatureInfo;
getRenameInfo(fileName: string, position: number): RenameInfo;
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
@ -686,6 +690,41 @@ module ts {
dispose(): void;
}
export interface SignatureInfo {
actual: ActualSignatureInfo;
formal: FormalSignatureItemInfo[]; // Formal signatures
activeFormal: number; // Index of the "best match" formal signature
}
export interface FormalSignatureItemInfo {
signatureInfo: string;
typeParameters: FormalTypeParameterInfo[];
parameters: FormalParameterInfo[]; // Array of parameters
docComment: string; // Help for the signature
}
export interface FormalTypeParameterInfo {
name: string; // Type parameter name
docComment: string; // Comments that contain help for the parameter
minChar: number; // minChar for parameter info in the formal signature info string
limChar: number; // lim char for parameter info in the formal signature info string
}
export interface FormalParameterInfo {
name: string; // Parameter name
isVariable: boolean; // true if parameter is var args
docComment: string; // Comments that contain help for the parameter
minChar: number; // minChar for parameter info in the formal signature info string
limChar: number; // lim char for parameter info in the formal signature info string
}
export interface ActualSignatureInfo {
parameterMinChar: number;
parameterLimChar: number;
currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument
currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array
}
export interface ClassifiedSpan {
textSpan: TypeScript.TextSpan;
classificationType: string; // ClassificationTypeNames
@ -796,8 +835,8 @@ module ts {
export interface SignatureHelpParameter {
name: string;
documentation: string;
display: string;
documentation: SymbolDisplayPart[];
displayParts: SymbolDisplayPart[];
isOptional: boolean;
}
@ -810,11 +849,11 @@ module ts {
*/
export interface SignatureHelpItem {
isVariadic: boolean;
prefix: string;
suffix: string;
separator: string;
prefixDisplayParts: SymbolDisplayPart[];
suffixDisplayParts: SymbolDisplayPart[];
separatorDisplayParts: SymbolDisplayPart[];
parameters: SignatureHelpParameter[];
documentation: string;
documentation: SymbolDisplayPart[];
}
/**
@ -824,9 +863,6 @@ module ts {
items: SignatureHelpItem[];
applicableSpan: TypeScript.TextSpan;
selectedItemIndex: number;
}
export interface SignatureHelpState {
argumentIndex: number;
argumentCount: number;
}
@ -1585,6 +1621,11 @@ module ts {
});
}
export function getSymbolDocumentationDisplayParts(symbol: Symbol): SymbolDisplayPart[] {
var documentation = symbol.getDocumentationComment();
return documentation === "" ? [] : [new SymbolDisplayPart(documentation, SymbolDisplayPartKind.text, /*symbol:*/ null)];
}
export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry): LanguageService {
var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider;
@ -2335,42 +2376,41 @@ module ts {
return undefined;
}
var documentation = symbol.getDocumentationComment();
var documentationParts = documentation === "" ? [] : [new SymbolDisplayPart(documentation, SymbolDisplayPartKind.text, /*symbol:*/ null)];
var documentationParts = getSymbolDocumentationDisplayParts(symbol);
// Having all this logic here is pretty unclean. Consider moving to the roslyn model
// where all symbol display logic is encapsulated into visitors and options.
var totalParts: SymbolDisplayPart[] = [];
if (symbol.flags & SymbolFlags.Class) {
totalParts.push(new SymbolDisplayPart("class", SymbolDisplayPartKind.keyword, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(keywordPart(SyntaxKind.ClassKeyword));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
}
else if (symbol.flags & SymbolFlags.Interface) {
totalParts.push(new SymbolDisplayPart("interface", SymbolDisplayPartKind.keyword, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
}
else if (symbol.flags & SymbolFlags.Enum) {
totalParts.push(new SymbolDisplayPart("enum", SymbolDisplayPartKind.keyword, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(keywordPart(SyntaxKind.EnumKeyword));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
}
else if (symbol.flags & SymbolFlags.Module) {
totalParts.push(new SymbolDisplayPart("module", SymbolDisplayPartKind.keyword, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(keywordPart(SyntaxKind.ModuleKeyword));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile));
}
else if (symbol.flags & SymbolFlags.TypeParameter) {
totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined));
totalParts.push(punctuationPart(SyntaxKind.OpenParenToken));
totalParts.push(new SymbolDisplayPart("type parameter", SymbolDisplayPartKind.text, undefined));
totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(punctuationPart(SyntaxKind.CloseParenToken));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol));
}
else {
totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined));
totalParts.push(punctuationPart(SyntaxKind.OpenParenToken));
var text: string;
if (symbol.flags & SymbolFlags.Property) { text = "property" }
@ -2384,8 +2424,8 @@ module ts {
}
totalParts.push(new SymbolDisplayPart(text, SymbolDisplayPartKind.text, undefined));
totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(punctuationPart(SyntaxKind.CloseParenToken));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, getContainerNode(node)));
@ -2395,8 +2435,8 @@ module ts {
symbol.flags & SymbolFlags.Variable) {
if (type) {
totalParts.push(new SymbolDisplayPart(":", SymbolDisplayPartKind.punctuation, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(punctuationPart(SyntaxKind.ColonToken));
totalParts.push(spacePart());
totalParts.push.apply(totalParts, typeInfoResolver.typeToDisplayParts(type, getContainerNode(node)));
}
}
@ -2411,9 +2451,9 @@ module ts {
if (declaration.kind === SyntaxKind.EnumMember) {
var constantValue = typeInfoResolver.getEnumMemberValue(<EnumMember>declaration);
if (constantValue !== undefined) {
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(new SymbolDisplayPart("=", SymbolDisplayPartKind.operator, undefined));
totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined));
totalParts.push(spacePart());
totalParts.push(operatorPart(SyntaxKind.EqualsToken));
totalParts.push(spacePart());
totalParts.push(new SymbolDisplayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral, undefined));
}
}
@ -3724,14 +3764,66 @@ module ts {
return SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken);
}
/**
* This is a syntactic operation
*/
function getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): SignatureHelpState {
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getCurrentSourceFile(fileName);
function getSignatureAtPosition(filename: string, position: number): SignatureInfo {
var signatureHelpItems = getSignatureHelpItems(filename, position);
return SignatureHelp.getSignatureHelpCurrentArgumentState(sourceFile, position, applicableSpanStart);
if (!signatureHelpItems) {
return undefined;
}
var currentArgumentState = { argumentIndex: signatureHelpItems.argumentIndex, argumentCount: signatureHelpItems.argumentCount };
var formalSignatures: FormalSignatureItemInfo[] = [];
forEach(signatureHelpItems.items, signature => {
var signatureInfoString = ts.SymbolDisplayPart.toString(signature.prefixDisplayParts);
var parameters: FormalParameterInfo[] = [];
if (signature.parameters) {
for (var i = 0, n = signature.parameters.length; i < n; i++) {
var parameter = signature.parameters[i];
// add the parameter to the string
if (i) {
signatureInfoString += ts.SymbolDisplayPart.toString(signature.separatorDisplayParts);
}
var start = signatureInfoString.length;
signatureInfoString += ts.SymbolDisplayPart.toString(parameter.displayParts);
var end = signatureInfoString.length - 1;
// add the parameter to the list
parameters.push({
name: parameter.name,
isVariable: i == n - 1 && signature.isVariadic,
docComment: ts.SymbolDisplayPart.toString(parameter.documentation),
minChar: start,
limChar: end
});
}
}
signatureInfoString += ts.SymbolDisplayPart.toString(signature.suffixDisplayParts);
formalSignatures.push({
signatureInfo: signatureInfoString,
docComment: ts.SymbolDisplayPart.toString(signature.documentation),
parameters: parameters,
typeParameters: [],
});
});
var actualSignature: ActualSignatureInfo = {
parameterMinChar: signatureHelpItems.applicableSpan.start(),
parameterLimChar: signatureHelpItems.applicableSpan.end(),
currentParameterIsTypeParameter: false,
currentParameter: currentArgumentState.argumentIndex
};
return {
actual: actualSignature,
formal: formalSignatures,
activeFormal: 0
};
}
/// Syntactic features
@ -4362,7 +4454,6 @@ module ts {
getCompletionEntryDetails: getCompletionEntryDetails,
getTypeAtPosition: getTypeAtPosition,
getSignatureHelpItems: getSignatureHelpItems,
getSignatureHelpCurrentArgumentState: getSignatureHelpCurrentArgumentState,
getQuickInfoAtPosition: getQuickInfoAtPosition,
getDefinitionAtPosition: getDefinitionAtPosition,
getReferencesAtPosition: getReferencesAtPosition,
@ -4381,6 +4472,7 @@ module ts {
getFormattingEditsForDocument: getFormattingEditsForDocument,
getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke,
getEmitOutput: getEmitOutput,
getSignatureAtPosition: getSignatureAtPosition,
};
}

View file

@ -84,13 +84,17 @@ module ts {
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
getQuickInfoAtPosition(fileName: string, position: number): string;
// Obsolete. Use getQuickInfoAtPosition instead.
getTypeAtPosition(fileName: string, position: number): string;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
getBreakpointStatementAtPosition(fileName: string, position: number): string;
getSignatureHelpItems(fileName: string, position: number): string;
getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): string;
// Obsolete. Use getSignatureHelpItems instead.
getSignatureAtPosition(fileName: string, position: number): string;
/**
* Returns a JSON-encoded value of the type:
@ -621,16 +625,14 @@ module ts {
});
}
public getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): string {
public getSignatureAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getSignatureHelpCurrentArgumentState('" + fileName + "', " + position + ", " + applicableSpanStart + ")",
"getSignatureAtPosition('" + fileName + "', " + position + ")",
() => {
var signatureHelpState = this.languageService.getSignatureHelpCurrentArgumentState(fileName, position, applicableSpanStart);
return signatureHelpState;
return this.languageService.getSignatureAtPosition(fileName, position);
});
}
/// GOTO DEFINITION
/**

View file

@ -249,39 +249,78 @@ module ts.SignatureHelp {
}
function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListOrTypeArgumentList: Node): SignatureHelpItems {
var items = map(candidates, candidateSignature => {
var items: SignatureHelpItem[] = map(candidates, candidateSignature => {
var parameters = candidateSignature.parameters;
var parameterHelpItems = parameters.length === 0 ? emptyArray : map(parameters, p => {
var display = p.name;
var parameterHelpItems: SignatureHelpParameter[] = parameters.length === 0 ? emptyArray : map(parameters, p => {
var displayParts: SymbolDisplayPart[] = [];
if (candidateSignature.hasRestParameter && parameters[parameters.length - 1] === p) {
display = "..." + display;
displayParts.push(punctuationPart(SyntaxKind.DotDotDotToken));
}
displayParts.push(symbolPart(p.name, p));
var isOptional = !!(p.valueDeclaration.flags & NodeFlags.QuestionMark);
if (isOptional) {
display += "?";
displayParts.push(punctuationPart(SyntaxKind.QuestionToken));
}
display += ": " + typeInfoResolver.typeToString(typeInfoResolver.getTypeOfSymbol(p), argumentListOrTypeArgumentList);
return { name: p.name, documentation: "", display: display, isOptiona: isOptional };
displayParts.push(punctuationPart(SyntaxKind.ColonToken));
displayParts.push(spacePart());
var typeParts = typeInfoResolver.typeToDisplayParts(typeInfoResolver.getTypeOfSymbol(p), argumentListOrTypeArgumentList);
displayParts.push.apply(displayParts, typeParts);
return {
name: p.name,
documentation: getSymbolDocumentationDisplayParts(p),
displayParts: displayParts,
isOptional: isOptional
};
});
var callTargetNode = (<CallExpression>argumentListOrTypeArgumentList.parent).func;
var callTargetSymbol = typeInfoResolver.getSymbolInfo(callTargetNode);
var signatureName = callTargetSymbol ? typeInfoResolver.symbolToString(callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : "";
var prefix = signatureName;
var prefixParts = callTargetSymbol ? typeInfoResolver.symbolToDisplayParts(callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : [];
var separatorParts = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
// TODO(jfreeman): Constraints?
if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) {
prefix += "<" + map(candidateSignature.typeParameters, tp => tp.symbol.name).join(", ") + ">";
prefixParts.push(punctuationPart(SyntaxKind.LessThanToken));
for (var i = 0, n = candidateSignature.typeParameters.length; i < n; i++) {
if (i) {
prefixParts.push.apply(prefixParts, separatorParts);
}
var tp = candidateSignature.typeParameters[i].symbol;
prefixParts.push(symbolPart(tp.name, tp));
}
prefixParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
}
prefix += "(";
var suffix = "): " + typeInfoResolver.typeToString(candidateSignature.getReturnType(), argumentListOrTypeArgumentList);
prefixParts.push(punctuationPart(SyntaxKind.OpenParenToken));
var suffixParts = [punctuationPart(SyntaxKind.CloseParenToken)];
suffixParts.push(punctuationPart(SyntaxKind.ColonToken));
suffixParts.push(spacePart());
var typeParts = typeInfoResolver.typeToDisplayParts(candidateSignature.getReturnType(), argumentListOrTypeArgumentList);
suffixParts.push.apply(suffixParts, typeParts);
return {
isVariadic: candidateSignature.hasRestParameter,
prefix: prefix,
suffix: suffix,
separator: ", ",
prefixDisplayParts: prefixParts,
suffixDisplayParts: suffixParts,
separatorDisplayParts: separatorParts,
parameters: parameterHelpItems,
documentation: ""
documentation: <SymbolDisplayPart[]>null
};
});
var selectedItemIndex = candidates.indexOf(bestSignature);
if (selectedItemIndex < 0) {
selectedItemIndex = 0;
@ -298,15 +337,19 @@ module ts.SignatureHelp {
var applicableSpanStart = argumentListOrTypeArgumentList.getFullStart();
var applicableSpanEnd = skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false);
var applicableSpan = new TypeScript.TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
var state = getSignatureHelpCurrentArgumentState(sourceFile, position, applicableSpanStart);
return {
items: items,
applicableSpan: applicableSpan,
selectedItemIndex: selectedItemIndex
selectedItemIndex: selectedItemIndex,
argumentIndex: state.argumentIndex,
argumentCount: state.argumentCount
};
}
}
export function getSignatureHelpCurrentArgumentState(sourceFile: SourceFile, position: number, applicableSpanStart: number): SignatureHelpState {
function getSignatureHelpCurrentArgumentState(sourceFile: SourceFile, position: number, applicableSpanStart: number): { argumentIndex: number; argumentCount: number } {
var tokenPrecedingSpanStart = findPrecedingToken(applicableSpanStart, sourceFile);
if (!tokenPrecedingSpanStart) {
return undefined;