-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Correct outlining spans for object and array literals in array #17709
Conversation
@uniqueiniquity, |
@@ -0,0 +1,23 @@ | |||
/// <reference path="fourslash.ts"/> | |||
|
|||
////// objects in x should generate outlining spans that do not render in VS |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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)?
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), |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, modulo comments
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { | |||
} | |||
} | |||
|
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved.
@aozgaa I added some comments characterizing the cases for which the change is needed, as well as explaining the new flag in addOutliningComments. |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved.
There was a problem hiding this 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use !isArrayLiteralExpression(n.parent)
.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto for isArrayLiteralExpression()
There was a problem hiding this comment.
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 = "..."; |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
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." |
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.