From 782275924fbb6ae3cee4fdea1c445a3b2372d7fb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 1 Oct 2014 18:51:58 -0700 Subject: [PATCH 1/9] Only show first overload in a series of consecutive overload signatures for navigateTo --- src/services/services.ts | 32 +++++++++++++++---- .../fourslash/navigationItemsOverloads1.ts | 30 +++++++++++++++++ .../fourslash/navigationItemsOverloads2.ts | 12 +++++++ .../navigationItemsOverloadsBroken.ts | 29 +++++++++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/navigationItemsOverloads1.ts create mode 100644 tests/cases/fourslash/navigationItemsOverloads2.ts create mode 100644 tests/cases/fourslash/navigationItemsOverloadsBroken.ts diff --git a/src/services/services.ts b/src/services/services.ts index a35c1213956..a7a3b43afd1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -504,17 +504,36 @@ module ts { if (!this.namedDeclarations) { var sourceFile = this; var namedDeclarations: Declaration[] = []; - var isExternalModule = ts.isExternalModule(sourceFile); + + // This keeps track of the last encountered function/method/method signature + // so that we may ignore all but the first overload. + var overloadDeclaration: FunctionDeclaration; forEachChild(sourceFile, function visit(node: Node): boolean { switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.Method: + var functionDeclaration = node; + + // We can assume that overloadDeclaration will never be "trampled" + // between consecutive overloads because we never dive into parameter initializers. + if (functionDeclaration.name) { + if (overloadDeclaration && + functionDeclaration.name.text === overloadDeclaration.name.text && + node.parent === overloadDeclaration.parent) { + break; + } + + namedDeclarations.push(functionDeclaration); + overloadDeclaration = functionDeclaration; + } + break; + case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: - case SyntaxKind.Method: - case SyntaxKind.FunctionDeclaration: case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -522,9 +541,7 @@ module ts { if ((node).name) { namedDeclarations.push(node); } - forEachChild(node, visit); - break; - + // fall through case SyntaxKind.VariableStatement: case SyntaxKind.ModuleBlock: case SyntaxKind.FunctionBlock: @@ -532,10 +549,11 @@ module ts { break; case SyntaxKind.Parameter: + // Only consider properties defined as constructor parameters if (!(node.flags & NodeFlags.AccessibilityModifier)) { - // Only consider properties defined as constructor parameters break; } + // fall through case SyntaxKind.VariableDeclaration: case SyntaxKind.EnumMember: case SyntaxKind.Property: diff --git a/tests/cases/fourslash/navigationItemsOverloads1.ts b/tests/cases/fourslash/navigationItemsOverloads1.ts new file mode 100644 index 00000000000..5f1981fe917 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloads1.ts @@ -0,0 +1,30 @@ +/// + +////function overload(a: string): boolean; +////function overload(b: boolean): boolean; +////function overload(b: number): boolean; +////function overload(f: typeof overload): boolean; +////function overload(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} +//// +////interface I { +//// interfaceMethodSignature(a: string): boolean; +//// interfaceMethodSignature(b: boolean): boolean; +//// interfaceMethodSignature(b: number): boolean; +//// interfaceMethodSignature(f: I): boolean; +////} +//// +////class C { +//// methodOverload(a: string): boolean; +//// methodOverload(b: boolean): boolean; +//// methodOverload(b: number): boolean; +//// methodOverload(f: I): boolean; +//// methodOverload(x: any, b = (function overload() { return false })): boolean { +//// throw C; +//// } +////} + +verify.navigationItemsListCount(1, "overload", "exact"); +verify.navigationItemsListCount(1, "interfaceMethodSignature", "exact"); +verify.navigationItemsListCount(1, "methodOverload", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloads2.ts b/tests/cases/fourslash/navigationItemsOverloads2.ts new file mode 100644 index 00000000000..c5824b639bc --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloads2.ts @@ -0,0 +1,12 @@ +/// + +////interface I { +//// interfaceMethodSignature(a: string): boolean; +//// interfaceMethodSignature(b: number): boolean; +//// interfaceMethodSignature(f: I): boolean; +////} +////interface I { +//// interfaceMethodSignature(b: boolean): boolean; +////} + +verify.navigationItemsListCount(2, "interfaceMethodSignature", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken.ts new file mode 100644 index 00000000000..f9501948272 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken.ts @@ -0,0 +1,29 @@ +/// + +////function overload1(a: string): boolean; +////function overload1(b: boolean): boolean; +////function overload1(b: number): boolean; +//// +////var heyImNotInterruptingAnythingAmI = '?'; +//// +////function overload1(f: typeof overload): boolean; +////function overload1(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} + +////function overload2(a: string): boolean; +////function overload2(b: boolean): boolean; +////function overload2(b: number): boolean; +//// +////function iJustRuinEverything(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} +//// +////function overload2(f: typeof overload): boolean; +////function overload2(x: any, b = (function overload() { return false })): boolean { +//// throw overload; +////} + +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(2, "overload2", "exact"); +verify.navigationItemsListCount(3, "overload", "prefix"); \ No newline at end of file From 4069e0a0d00a1bed4654a9c252a895e8ae4b8bf2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 15:53:35 -0700 Subject: [PATCH 2/9] Finished up "overload collapsing" for navigate-to. Current semantics: - If an overload lacks an implementation, go to the first implementation. - If an overload has any implementation, go to the first one. - If there are any declarations between an implementation and any overload, this will split the series of overloads (note that this is invalid code). --- src/services/services.ts | 36 +++++++++---------- ....ts => navigationItemsOverloadsBroken1.ts} | 4 +-- .../navigationItemsOverloadsBroken2.ts | 23 ++++++++++++ 3 files changed, 43 insertions(+), 20 deletions(-) rename tests/cases/fourslash/{navigationItemsOverloadsBroken.ts => navigationItemsOverloadsBroken1.ts} (88%) create mode 100644 tests/cases/fourslash/navigationItemsOverloadsBroken2.ts diff --git a/src/services/services.ts b/src/services/services.ts index a7a3b43afd1..11a84a42635 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -504,28 +504,31 @@ module ts { if (!this.namedDeclarations) { var sourceFile = this; var namedDeclarations: Declaration[] = []; - - // This keeps track of the last encountered function/method/method signature - // so that we may ignore all but the first overload. - var overloadDeclaration: FunctionDeclaration; - forEachChild(sourceFile, function visit(node: Node): boolean { + forEachChild(sourceFile, function visit(node: Node): void { switch (node.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.Method: var functionDeclaration = node; - // We can assume that overloadDeclaration will never be "trampled" - // between consecutive overloads because we never dive into parameter initializers. - if (functionDeclaration.name) { - if (overloadDeclaration && - functionDeclaration.name.text === overloadDeclaration.name.text && - node.parent === overloadDeclaration.parent) { - break; + if (functionDeclaration.name && functionDeclaration.name.kind !== SyntaxKind.Missing) { + var lastDeclaration = namedDeclarations.length > 0 ? + namedDeclarations[namedDeclarations.length - 1] : + undefined; + + // Check whether this declaration belongs to an "overload group". + if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) { + // Overwrite the last declaration if it was an overload + // and this one is an implementation. + if (functionDeclaration.body && !(lastDeclaration).body) { + namedDeclarations[namedDeclarations.length - 1] = functionDeclaration; + } + } + else { + namedDeclarations.push(node); } - namedDeclarations.push(functionDeclaration); - overloadDeclaration = functionDeclaration; + forEachChild(node, visit); } break; @@ -534,7 +537,6 @@ module ts { case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: - case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeLiteral: @@ -542,6 +544,7 @@ module ts { namedDeclarations.push(node); } // fall through + case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: case SyntaxKind.ModuleBlock: case SyntaxKind.FunctionBlock: @@ -560,9 +563,6 @@ module ts { namedDeclarations.push(node); break; } - - // do not go any deeper - return undefined; }); this.namedDeclarations = namedDeclarations; diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts similarity index 88% rename from tests/cases/fourslash/navigationItemsOverloadsBroken.ts rename to tests/cases/fourslash/navigationItemsOverloadsBroken1.ts index f9501948272..7b8ebc9181f 100644 --- a/tests/cases/fourslash/navigationItemsOverloadsBroken.ts +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts @@ -24,6 +24,6 @@ //// throw overload; ////} -verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(2, "overload1", "exact"); verify.navigationItemsListCount(2, "overload2", "exact"); -verify.navigationItemsListCount(3, "overload", "prefix"); \ No newline at end of file +verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts new file mode 100644 index 00000000000..c1f6ccae2f5 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken2.ts @@ -0,0 +1,23 @@ +/// + +////function overload1(a: string): boolean; +////function overload1(b: boolean): boolean; +////function overload1(x: any, b = (function overload() { return false })): boolean { +//// throw overload1; +////} +////function overload1(b: number): boolean; +////function overload1(f: typeof overload): boolean; + +////function overload2(a: string): boolean; +////function overload2(b: boolean): boolean; +////function overload2(x: any, b = (function overload() { return false })): boolean { +//// function overload2(): boolean; +//// function overload2(x: any): boolean; +//// throw overload2; +////} +////function overload2(b: number): boolean; +////function overload2(f: typeof overload): boolean; + +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(3, "overload2", "exact"); +verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file From be02f962c7f4324f608064b69ce80bb262cb830a Mon Sep 17 00:00:00 2001 From: Yui T Date: Mon, 6 Oct 2014 18:34:01 -0700 Subject: [PATCH 3/9] Fix compileOnSave with external module --- src/compiler/emitter.ts | 22 ++++++++++++++-------- src/services/services.ts | 7 ++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index fb40117fb9b..74520b3fc6c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3228,21 +3228,27 @@ module ts { } if (targetSourceFile === undefined) { + // No targetSourceFile is specified (i.e. calling emitter from batch compiler) forEach(program.getSourceFiles(), sourceFile => { if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js"); emitFile(jsFilePath, sourceFile); } }); - } - else { - // Emit only one file specified in targetFilename. This is mainly used in compilerOnSave feature - var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js"); - emitFile(jsFilePath, targetSourceFile); - } - if (compilerOptions.out) { - emitFile(compilerOptions.out); + if (compilerOptions.out) { + emitFile(compilerOptions.out); + } + } else { + // targetSourceFile is specified (i.e. calling emitter from language service) + if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { + // If shouldEmitToOwnFile is true or targetSouceFile is an external module file, then emit targetSourceFile in its own output file + var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js"); + emitFile(jsFilePath, targetSourceFile); + } else { + // If shouldEmitToOwnFile is false, then emit all, non-external-module file, into one single output file + emitFile(compilerOptions.out); + } } // Sort and make the unique list of diagnostics diff --git a/src/services/services.ts b/src/services/services.ts index 6e49e8427e5..bd222cb8240 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3881,7 +3881,8 @@ module ts { filename = TypeScript.switchToForwardSlashes(filename); var compilerOptions = program.getCompilerOptions(); var targetSourceFile = program.getSourceFile(filename); // Current selected file to be output - var emitToSingleFile = ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions); + // If --out flag is not specified, shouldEmitToOwnFile is true. Otherwise shouldEmitToOwnFile is false. + var shouldEmitToOwnFile = ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions); var emitDeclaration = compilerOptions.declaration; var emitOutput: EmitOutput = { outputFiles: [], @@ -3902,7 +3903,7 @@ module ts { var syntacticDiagnostics: Diagnostic[] = []; var containSyntacticErrors = false; - if (emitToSingleFile) { + if (shouldEmitToOwnFile) { // Check only the file we want to emit containSyntacticErrors = containErrors(program.getDiagnostics(targetSourceFile)); } else { @@ -3929,7 +3930,7 @@ module ts { // Perform semantic and force a type check before emit to ensure that all symbols are updated // EmitFiles will report if there is an error from TypeChecker and Emitter // Depend whether we will have to emit into a single file or not either emit only selected file in the project, emit all files into a single file - var emitFilesResult = emitToSingleFile ? getFullTypeCheckChecker().emitFiles(targetSourceFile) : getFullTypeCheckChecker().emitFiles(); + var emitFilesResult = getFullTypeCheckChecker().emitFiles(targetSourceFile);; emitOutput.emitOutputStatus = emitFilesResult.emitResultStatus; // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput From 747ae1b1f50fb966e4d4c24706fc4304516d5b94 Mon Sep 17 00:00:00 2001 From: Yui T Date: Mon, 6 Oct 2014 18:37:01 -0700 Subject: [PATCH 4/9] Add fourslash tests to cover external module case --- .../getEmitOutputExternalModule.baseline | 9 +++++++ .../getEmitOutputExternalModule2.baseline | 15 +++++++++++ .../getEmitOutputSingleFile2.baseline | 24 ----------------- .../fourslash/getEmitOutputExternalModule.ts | 19 ++++++++++++++ .../fourslash/getEmitOutputExternalModule2.ts | 26 +++++++++++++++++++ 5 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 tests/baselines/reference/getEmitOutputExternalModule.baseline create mode 100644 tests/baselines/reference/getEmitOutputExternalModule2.baseline create mode 100644 tests/cases/fourslash/getEmitOutputExternalModule.ts create mode 100644 tests/cases/fourslash/getEmitOutputExternalModule2.ts diff --git a/tests/baselines/reference/getEmitOutputExternalModule.baseline b/tests/baselines/reference/getEmitOutputExternalModule.baseline new file mode 100644 index 00000000000..b5e670c5fd7 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputExternalModule.baseline @@ -0,0 +1,9 @@ +EmitOutputStatus : Succeeded +Filename : declSingleFile.js +var x = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); + diff --git a/tests/baselines/reference/getEmitOutputExternalModule2.baseline b/tests/baselines/reference/getEmitOutputExternalModule2.baseline new file mode 100644 index 00000000000..5c03a092257 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputExternalModule2.baseline @@ -0,0 +1,15 @@ +EmitOutputStatus : JSGeneratedWithSemanticErrors +Filename : declSingleFile.js +var x = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); +var x = "world"; +var Bar2 = (function () { + function Bar2() { + } + return Bar2; +})(); + diff --git a/tests/baselines/reference/getEmitOutputSingleFile2.baseline b/tests/baselines/reference/getEmitOutputSingleFile2.baseline index 77fa6b9acdd..2f5dbe3daf8 100644 --- a/tests/baselines/reference/getEmitOutputSingleFile2.baseline +++ b/tests/baselines/reference/getEmitOutputSingleFile2.baseline @@ -5,28 +5,4 @@ exports.bar = "hello world"; Filename : tests/cases/fourslash/inputFile3.d.ts export declare var foo: number; export declare var bar: string; -Filename : declSingleFile.js -var x = 5; -var Bar = (function () { - function Bar() { - } - return Bar; -})(); -var x1 = "hello world"; -var Foo = (function () { - function Foo() { - } - return Foo; -})(); -Filename : declSingleFile.d.ts -declare var x: number; -declare class Bar { - x: string; - y: number; -} -declare var x1: string; -declare class Foo { - x: string; - y: number; -} diff --git a/tests/cases/fourslash/getEmitOutputExternalModule.ts b/tests/cases/fourslash/getEmitOutputExternalModule.ts new file mode 100644 index 00000000000..ef9fb348c57 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputExternalModule.ts @@ -0,0 +1,19 @@ +/// + +// @BaselineFile: getEmitOutputExternalModule.baseline +// @out: declSingleFile.js + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// var x: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +//// export module M { +//// class C {c} +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputExternalModule2.ts b/tests/cases/fourslash/getEmitOutputExternalModule2.ts new file mode 100644 index 00000000000..abecc219698 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputExternalModule2.ts @@ -0,0 +1,26 @@ +/// + +// @BaselineFile: getEmitOutputExternalModule2.baseline +// @out: declSingleFile.js + +// @Filename: inputFile1.ts +//// var x: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var x: string = "world"; +//// class Bar2 { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile3.ts +//// export module M { +//// class C {c} +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file From d345d228a7fb153d4f1bab3ae75bfa05b308560f Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 7 Oct 2014 10:17:29 -0700 Subject: [PATCH 5/9] Fix spelling --- src/compiler/emitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 74520b3fc6c..f7c9fa300a9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3242,7 +3242,7 @@ module ts { } else { // targetSourceFile is specified (i.e. calling emitter from language service) if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { - // If shouldEmitToOwnFile is true or targetSouceFile is an external module file, then emit targetSourceFile in its own output file + // If shouldEmitToOwnFile is true or targetSourceFile is an external module file, then emit targetSourceFile in its own output file var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js"); emitFile(jsFilePath, targetSourceFile); } else { From 7d725037b38fc4bd05a9639a84b6245198462989 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 7 Oct 2014 13:20:06 -0700 Subject: [PATCH 6/9] Address code review --- src/compiler/emitter.ts | 4 ++-- src/services/services.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f7c9fa300a9..37442772078 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3228,7 +3228,7 @@ module ts { } if (targetSourceFile === undefined) { - // No targetSourceFile is specified (i.e. calling emitter from batch compiler) + // No targetSourceFile is specified (e.g. calling emitter from batch compiler) forEach(program.getSourceFiles(), sourceFile => { if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js"); @@ -3240,7 +3240,7 @@ module ts { emitFile(compilerOptions.out); } } else { - // targetSourceFile is specified (i.e. calling emitter from language service) + // targetSourceFile is specified (e.g calling emitter from language service) if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { // If shouldEmitToOwnFile is true or targetSourceFile is an external module file, then emit targetSourceFile in its own output file var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js"); diff --git a/src/services/services.ts b/src/services/services.ts index bd222cb8240..b00c2b703e8 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3930,7 +3930,7 @@ module ts { // Perform semantic and force a type check before emit to ensure that all symbols are updated // EmitFiles will report if there is an error from TypeChecker and Emitter // Depend whether we will have to emit into a single file or not either emit only selected file in the project, emit all files into a single file - var emitFilesResult = getFullTypeCheckChecker().emitFiles(targetSourceFile);; + var emitFilesResult = getFullTypeCheckChecker().emitFiles(targetSourceFile); emitOutput.emitOutputStatus = emitFilesResult.emitResultStatus; // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput From 0b7453b9d6475ffefa3f1dbd83e57d65a1416757 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 7 Oct 2014 13:31:21 -0700 Subject: [PATCH 7/9] Properly marshall diagnostic codes to the managed layer --- src/services/shims.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index 40ce6c7b8df..c7d293794ca 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -502,7 +502,8 @@ module ts { start: diagnostic.start, length: diagnostic.length, /// TODO: no need for the tolowerCase call - category: DiagnosticCategory[diagnostic.category].toLowerCase() + category: DiagnosticCategory[diagnostic.category].toLowerCase(), + code: diagnostic.code }; } From 9e4fe5b1e8aadde9b16eac50023f4e0ade7982ae Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 7 Oct 2014 14:24:24 -0700 Subject: [PATCH 8/9] Don't merge nav bar items that are at different indent levels --- src/services/navigationBar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index ef2b5e9334a..9f16fa57741 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -148,7 +148,7 @@ module ts.NavigationBar { var item = createItem(child); if (item !== undefined) { if (item.text.length > 0) { - var key = item.text + "-" + item.kind; + var key = item.text + "-" + item.kind + "-" + item.indent; var itemWithSameName = keyToItem[key]; if (itemWithSameName) { From 01533905355a41edb585aaaa0e788a8ffffef00a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 7 Oct 2014 15:07:49 -0700 Subject: [PATCH 9/9] Outlining spans for a standalone block shouldn't have the span of their parent. --- Jakefile | 3 +- src/services/outliningElementsCollector.ts | 34 ++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Jakefile b/Jakefile index 4f2808dcbd1..74f950be9e0 100644 --- a/Jakefile +++ b/Jakefile @@ -58,7 +58,8 @@ var servicesSources = [ "shims.ts", "signatureHelp.ts", "utilities.ts", - "navigationBar.ts" + "navigationBar.ts", + "outliningElementsCollector.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index c9a513ee2aa..aaaedb735ea 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -33,13 +33,14 @@ module ts { export module OutliningElementsCollector { export function collectElements(sourceFile: SourceFile): OutliningSpan[] { var elements: OutliningSpan[] = []; + var collapseText = "..."; function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) { if (hintSpanNode && startElement && endElement) { var span: OutliningSpan = { textSpan: TypeScript.TextSpan.fromBounds(startElement.pos, endElement.end), hintSpan: TypeScript.TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end), - bannerText: "...", + bannerText: collapseText, autoCollapse: autoCollapse }; elements.push(span); @@ -66,10 +67,39 @@ module ts { } switch (n.kind) { case SyntaxKind.Block: + var parent = n.parent; + var openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + var closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + + // Check if the block is standalone, or 'attached' to some parent statement. + // If the latter, we want to collaps the block, but consider its hint span + // to be the entire span of the parent. + if (parent.kind === SyntaxKind.DoStatement || + parent.kind === SyntaxKind.ForInStatement || + parent.kind === SyntaxKind.ForStatement || + parent.kind === SyntaxKind.IfStatement || + parent.kind === SyntaxKind.WhileStatement || + parent.kind === SyntaxKind.WithStatement) { + + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + } + else { + // Block was a standalone block. In this case we want to only collapse + // the span of the block, independent of any parent span. + var span = TypeScript.TextSpan.fromBounds(n.getStart(), n.end); + elements.push({ + textSpan: span, + hintSpan: span, + bannerText: collapseText, + autoCollapse: autoCollapse(n) + }); + } + break; + + case SyntaxKind.FunctionBlock: case SyntaxKind.ModuleBlock: case SyntaxKind.TryBlock: - case SyntaxKind.TryBlock: case SyntaxKind.CatchBlock: case SyntaxKind.FinallyBlock: var openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);