Skip to content

Commit

Permalink
Merge pull request #75515 from Cosifne/dev/shech/FixCollapseToDefinition
Browse files Browse the repository at this point in the history
Also compare other properties when remove block spans
  • Loading branch information
Cosifne authored Oct 16, 2024
2 parents c23b0d5 + 7ba96f3 commit d2e011d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
33 changes: 33 additions & 0 deletions src/EditorFeatures/Test/Structure/StructureTaggerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,39 @@ End Sub
});
}

[WpfFact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2112145")]
public async Task LambdaShouldBeCollapsed()
{
var code = """
public class MyClass
{
public void MyMethod() => System.Linq.Enumerable.Range(10, 100).Any(x =>
{
return x == 10;
});
}
""";

using var workspace = EditorTestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf);
var tags = await GetTagsFromWorkspaceAsync(workspace);

Assert.Collection(tags, programTag =>
{
Assert.Equal("public class MyClass", GetHeaderText(programTag));
Assert.Equal(7, GetCollapsedHintLineCount(programTag));
},
mainTag =>
{
Assert.Equal("public void MyMethod()", GetHeaderText(mainTag));
Assert.Equal(4, GetCollapsedHintLineCount(mainTag));
},
IfTag =>
{
Assert.Equal("x =>", GetHeaderText(IfTag));
Assert.Equal(4, GetCollapsedHintLineCount(IfTag));
});
}

#pragma warning disable CS0618 // Type or member is obsolete
private static async Task<List<IContainerStructureTag>> GetTagsFromWorkspaceAsync(EditorTestWorkspace workspace)
{
Expand Down
26 changes: 26 additions & 0 deletions src/Features/Core/Portable/Structure/BlockSpan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,30 @@ internal BlockSpan With(
return new BlockSpan(
newType, newIsCollapsible, newTextSpan, newHintSpan, newPrimarySpans, newBannerText, newAutoCollapse, newIsDefaultCollapsed);
}

internal bool IsOverlappingBlockSpan(TextLineCollection lines, BlockSpan? other)
{
// Compare collapse region related properties to decide should two block span be consider as one.
// We only want one block span (inner block) for case like:
// M1(M2(
// ))
if (other is null)
return false;

if (this.AutoCollapse != other.Value.AutoCollapse
|| this.IsCollapsible != other.Value.IsCollapsible
|| this.IsDefaultCollapsed != other.Value.IsDefaultCollapsed)
{
return false;
}

var startLine = lines.GetLinePosition(this.TextSpan.Start).Line;
var otherStartLine = lines.GetLinePosition(other.Value.TextSpan.Start).Line;
if (startLine != otherStartLine)
return false;

var endLine = lines.GetLinePosition(this.TextSpan.End).Line;
var otherEndLine = lines.GetLinePosition(other.Value.TextSpan.End).Line;
return endLine == otherEndLine;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,19 @@ public override void ProvideBlockStructure(in BlockStructureContext context)
//
// We only collapse the "inner" span which has larger start.
context.Spans.Sort(initialContextCount, s_blockSpanComparer);

var lastAddedLineStart = -1;
var lastAddedLineEnd = -1;
var text = context.SyntaxTree.GetText(context.CancellationToken);
BlockSpan? lastSpan = null;

context.Spans.RemoveWhere((span, index, _) =>
{
// do not remove items before the first item that we added
if (index < initialContextCount)
return false;

var lineStart = text.Lines.GetLinePosition(span.TextSpan.Start).Line;
var lineEnd = text.Lines.GetLinePosition(span.TextSpan.End).Line;
if (lineStart == lastAddedLineStart && lastAddedLineEnd == lineEnd)
if (span.IsOverlappingBlockSpan(text.Lines, lastSpan))
return true;

lastAddedLineStart = lineStart;
lastAddedLineEnd = lineEnd;

lastSpan = span;
return false;
},
arg: default(VoidResult));
Expand Down

0 comments on commit d2e011d

Please sign in to comment.