Skip to content

Correct outlining spans for object and array literals in array #17709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions src/services/outliningElementsCollector.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
/* @internal */
namespace ts.OutliningElementsCollector {
const collapseText = "...";
const maxDepth = 20;

export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] {
const elements: OutliningSpan[] = [];
const collapseText = "...";
let depth = 0;

function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
walk(sourceFile);
return elements;

/** If useFullStart is true, then the collapsing span includes leading whitespace, including linebreaks. */
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean, useFullStart: boolean) {
if (hintSpanNode && startElement && endElement) {
const span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
textSpan: createTextSpanFromBounds(useFullStart ? startElement.getFullStart() : startElement.getStart(), endElement.getEnd()),
hintSpan: createTextSpanFromNode(hintSpanNode, sourceFile),
bannerText: collapseText,
autoCollapse,
Expand Down Expand Up @@ -82,8 +89,6 @@ namespace ts.OutliningElementsCollector {
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
}

let depth = 0;
const maxDepth = 20;
function walk(n: Node): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider renaming n to node.

cancellationToken.throwIfCancellationRequested();
if (depth > maxDepth) {
Expand Down Expand Up @@ -113,21 +118,21 @@ namespace ts.OutliningElementsCollector {
parent.kind === SyntaxKind.WithStatement ||
parent.kind === SyntaxKind.CatchClause) {

addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true);
break;
}

if (parent.kind === SyntaxKind.TryStatement) {
// Could be the try-block, or the finally-block.
const tryStatement = <TryStatement>parent;
if (tryStatement.tryBlock === n) {
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true);
break;
}
else if (tryStatement.finallyBlock === n) {
const finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
if (finallyKeyword) {
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true);
break;
}
}
Expand All @@ -151,31 +156,35 @@ namespace ts.OutliningElementsCollector {
case SyntaxKind.ModuleBlock: {
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true);
break;
}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.CaseBlock: {
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true);
break;
}
// If the block has no leading keywords and is inside an array literal,
// we only want to collapse the span of the block.
// Otherwise, the collapsed section will include the end of the previous line.
case SyntaxKind.ObjectLiteralExpression:
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ !isArrayLiteralExpression(n.parent));
break;
case SyntaxKind.ArrayLiteralExpression:
const openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile);
const closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n));
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n), /*useFullStart*/ !isArrayLiteralExpression(n.parent));
break;
}
depth++;
forEachChild(n, walk);
depth--;
}

walk(sourceFile);
return elements;
}
}
56 changes: 56 additions & 0 deletions tests/cases/fourslash/getOutliningForObjectsInArray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// <reference path="fourslash.ts"/>

// objects in x should generate outlining spans that do not render in VS
//// const x =[| [
//// [|{ a: 0 }|],
//// [|{ b: 1 }|],
//// [|{ c: 2 }|]
//// ]|];
////
// objects in y should generate outlining spans that render as expected
//// const y =[| [
//// [|{
//// a: 0
//// }|],
//// [|{
//// b: 1
//// }|],
//// [|{
//// c: 2
//// }|]
//// ]|];
////
// same behavior for nested arrays
//// const w =[| [
//// [|[ 0 ]|],
//// [|[ 1 ]|],
//// [|[ 2 ]|]
//// ]|];
////
//// const z =[| [
//// [|[
//// 0
//// ]|],
//// [|[
//// 1
//// ]|],
//// [|[
//// 2
//// ]|]
//// ]|];
////
// multiple levels of nesting work as expected
//// const z =[| [
//// [|[
//// [|{ hello: 0 }|]
//// ]|],
//// [|[
//// [|{ hello: 3 }|]
//// ]|],
//// [|[
//// [|{ hello: 5 }|],
//// [|{ hello: 7 }|]
//// ]|]
//// ]|];

verify.outliningSpansInCurrentFile(test.ranges());