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

Conversation

uniqueiniquity
Copy link
Contributor

@uniqueiniquity uniqueiniquity commented Aug 9, 2017

This change causes outlining regions for object and array literals in an array to no longer extend to the previous member of the array. This has the effect of no longer permitting single-line object or array literals to be folded.

@msftclas
Copy link

msftclas commented Aug 9, 2017

@uniqueiniquity,
Thanks for your contribution as a Microsoft full-time employee or intern. You do not need to sign a CLA.
Thanks,
Microsoft Pull Request Bot

@uniqueiniquity uniqueiniquity changed the title Objects in array Correct outlining spans for object literals in array Aug 9, 2017
@@ -0,0 +1,23 @@
/// <reference path="fourslash.ts"/>

////// objects in x should generate outlining spans that do not render in VS
Copy link
Member

Choose a reason for hiding this comment

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

Is this validated somehow? Also did this test fail before your change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The particular point about the spans not rendering in VS is not validated, but the placement of the spans is. This test would have failed before my change.

function addOutliningForObjectLiteralsInArray(startElement: Node, endElement: Node, autoCollapse: boolean) {
if (startElement && endElement) {
const span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.getStart(), endElement.end),
Copy link
Member

Choose a reason for hiding this comment

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

Extract a local for this repeated expression?

@@ -161,6 +173,10 @@ namespace ts.OutliningElementsCollector {
case SyntaxKind.CaseBlock: {
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
if (n.kind === SyntaxKind.ObjectLiteralExpression && n.parent.kind === SyntaxKind.ArrayLiteralExpression) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm afraid I don't understand why this case is special. It looks like the main things we're doing differently are calling getStart instead of pos and computing our own hintSpan. Why not make those changes to the general case? If this case is indeed different from the general case, why aren't there related cases (nested arrays, for example)?

@uniqueiniquity uniqueiniquity changed the title Correct outlining spans for object literals in array Correct outlining spans for object and array literals in array Aug 10, 2017
if (startElement && endElement) {
const span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.getStart(), endElement.end),
textSpan: createTextSpanFromBounds(fullStart ? startElement.pos : startElement.getStart(), endElement.end),
hintSpan: createTextSpanFromBounds(startElement.getStart(), endElement.end),
Copy link
Member

Choose a reason for hiding this comment

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

Should fullStart (which I might call "useFullStart) apply to the hint span as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it should apply to the hint span, since it has always used the actual start (as opposed to the full start, which the textSpan previously always used).

@@ -19,5 +19,24 @@
//// c: 2
//// }|]
//// ]|];
////
////// same behavior for nested arrays
Copy link
Member

Choose a reason for hiding this comment

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

Would it be interesting to test an object in an array in an array?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

Copy link
Member

@amcasey amcasey left a comment

Choose a reason for hiding this comment

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

LGTM, modulo comments

Copy link
Contributor

@aozgaa aozgaa left a comment

Choose a reason for hiding this comment

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

Same questions as Andrew. In particular, could you come up with a succinct description for which parent-child matchings (eg: array literal containing object literal entry) the "next-line" phenomenon occurs?

@@ -0,0 +1,23 @@
/// <reference path="fourslash.ts"/>

////// objects in x should generate outlining spans that do not render in VS
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless you want the comment to be part of the sourcefile, you can just use two slashes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -16,6 +16,18 @@ namespace ts.OutliningElementsCollector {
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you move the body of collectElements above to precede local functions? It's not strictly-speaking necessary for this change, but makes reading collectElements easier and is consistent with defining local functions last elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved.

@uniqueiniquity
Copy link
Contributor Author

@aozgaa I added some comments characterizing the cases for which the change is needed, as well as explaining the new flag in addOutliningComments.

Copy link
Member

@billti billti left a comment

Choose a reason for hiding this comment

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

Thanks!

@@ -3,12 +3,18 @@ namespace ts.OutliningElementsCollector {
export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] {
const elements: OutliningSpan[] = [];
const collapseText = "...";
let depth = 0;
const maxDepth = 20;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: you could move this outside the function body (don't export).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved.

Copy link
Contributor

@aozgaa aozgaa left a comment

Choose a reason for hiding this comment

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

Use some internal helpers, but otherwise just grammatical and stylistic nit's. LGTM, thanks!


function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
// If useFullStart is true, then the collapsing span includes leading whitespace, including linebreaks.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: make a JsDoc comment so the description shows up as part of quickinfo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
hintSpan: createTextSpanFromNode(hintSpanNode, sourceFile),
textSpan: createTextSpanFromBounds(useFullStart ? startElement.pos : startElement.getStart(), endElement.end),
hintSpan: createTextSpanFromBounds(startElement.getStart(), endElement.end),
Copy link
Contributor

Choose a reason for hiding this comment

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

use createTextSpanFromNode(...).

if (hintSpanNode && startElement && endElement) {
const span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
hintSpan: createTextSpanFromNode(hintSpanNode, sourceFile),
textSpan: createTextSpanFromBounds(useFullStart ? startElement.pos : startElement.getStart(), endElement.end),
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider also calling createTextSpanFromNode and adding a boolean parameter to use full start that defaults to false.

Regardless of whether you do it inline here or by modifying the helper, use startElement.getFullStart(...) to get the full start.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can't use createTextSpanFromNode everywhere because in most places, the start node and end node are different.
I'll change it back in the one relevant place though.

Also changing all .pos to .getFullStart (and similar for .end).

break;
}
// If the block has no leading keywords and is a member of an array literal,
// we again want to only collapse the span of the block.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Perhaps we again want to only should be we only want to

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

break;
}
// If the block has no leading keywords and is a member of an array literal,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: and is a member of could be and is inside.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

@@ -82,8 +88,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.

case SyntaxKind.ObjectLiteralExpression:
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n), /* fullStart */ n.parent.kind !== SyntaxKind.ArrayLiteralExpression);
Copy link
Contributor

Choose a reason for hiding this comment

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

use !isArrayLiteralExpression(n.parent).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

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), /* fullStart */ n.parent.kind !== SyntaxKind.ArrayLiteralExpression);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto for isArrayLiteralExpression()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -3,12 +3,18 @@ namespace ts.OutliningElementsCollector {
export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] {
const elements: OutliningSpan[] = [];
const collapseText = "...";
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this could also be moved outside the function body (don't export).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved.

@@ -113,21 +117,21 @@ namespace ts.OutliningElementsCollector {
parent.kind === SyntaxKind.WithStatement ||
parent.kind === SyntaxKind.CatchClause) {

addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n), /* fullStart */ true);
Copy link
Contributor

Choose a reason for hiding this comment

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

s/fullStart/getFullStart? Also, consider removing the spaces on either end of the comment to make it more compact. This should be the convention throughout the codebase -- it appears to be followed in the cases I saw within a cursory glance. Maybe a tslint rule could help here... @Andy-MS ?

To avoid this in the future, we could make renaming smarter, but deciding how to handle comments in general is not obvious (c.f. csharp).

Copy link

Choose a reason for hiding this comment

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

Tried this out at #17893

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@uniqueiniquity
Copy link
Contributor Author

As from #16385,

"All PR's from the last day appear to be failing Travis with node 4 due to a gulp-typescript dependency. See ivogabe/gulp-typescript#536 for the fix.

Going to ignore this and go ahead and merge."

@uniqueiniquity uniqueiniquity merged commit 45c62ac into microsoft:master Aug 18, 2017
@uniqueiniquity uniqueiniquity deleted the objectsInArray branch August 18, 2017 23:25
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants