Fixes for excerpt service
We had a bug where were not returning the correct span for highlighting. Fixed this. Also we have a problem here, we're using types in our tests that are coming from Roslyn - however we're not getting IVT for our test assemblies. So some additional pain is required.
This commit is contained in:
parent
5229e65962
commit
a3d0c8f634
|
|
@ -37,6 +37,16 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
ExcerptMode mode,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await TryGetExcerptInternalAsync(document, span, (ExcerptModeInternal)mode, cancellationToken).ConfigureAwait(false);
|
||||
return result?.ToExcerptResult();
|
||||
}
|
||||
|
||||
public async Task<ExcerptResultInternal?> TryGetExcerptInternalAsync(
|
||||
Document document,
|
||||
TextSpan span,
|
||||
ExcerptModeInternal mode,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (_document == null)
|
||||
{
|
||||
return null;
|
||||
|
|
@ -78,7 +88,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
// Now translate everything to be relative to the excerpt
|
||||
var offset = 0 - excerptSpan.Start;
|
||||
var excerptText = primaryText.GetSubText(excerptSpan);
|
||||
excerptSpan = new TextSpan(excerptSpan.Start + offset, excerptSpan.Length);
|
||||
excerptSpan = new TextSpan(0, excerptSpan.Length);
|
||||
primarySpan = new TextSpan(primarySpan.Start + offset, primarySpan.Length);
|
||||
|
||||
for (var i = 0; i < classifiedSpans.Count; i++)
|
||||
{
|
||||
|
|
@ -89,24 +100,26 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
classifiedSpans[i] = new ClassifiedSpan(classifiedSpan.ClassificationType, updated);
|
||||
}
|
||||
|
||||
return new ExcerptResult(excerptText, excerptSpan, classifiedSpans.ToImmutable(), document, span);
|
||||
return new ExcerptResultInternal(excerptText, primarySpan, classifiedSpans.ToImmutable(), document, span);
|
||||
}
|
||||
|
||||
private TextSpan ChooseExcerptSpan(SourceText primaryText, TextSpan primarySpan, ExcerptMode mode)
|
||||
|
||||
private TextSpan ChooseExcerptSpan(SourceText primaryText, TextSpan primarySpan, ExcerptModeInternal mode)
|
||||
{
|
||||
var startLine = primaryText.Lines.GetLineFromPosition(primarySpan.Start);
|
||||
var endLine = primaryText.Lines.GetLineFromPosition(primarySpan.End);
|
||||
|
||||
// If we're showing a single line then this will do. Otherwise expand the range by 1 in
|
||||
// If we're showing a single line then this will do. Otherwise expand the range by 3 in
|
||||
// each direction (if possible).
|
||||
if (mode == ExcerptMode.Tooltip && startLine.LineNumber > 0)
|
||||
if (mode == ExcerptModeInternal.Tooltip)
|
||||
{
|
||||
startLine = primaryText.Lines[startLine.LineNumber - 1];
|
||||
var index = Math.Max(startLine.LineNumber - 3, 0);
|
||||
startLine = primaryText.Lines[index];
|
||||
}
|
||||
|
||||
if (mode == ExcerptMode.Tooltip && endLine.LineNumber < primaryText.Lines.Count - 1)
|
||||
if (mode == ExcerptModeInternal.Tooltip)
|
||||
{
|
||||
endLine = primaryText.Lines[endLine.LineNumber + 1];
|
||||
var index = Math.Min(endLine.LineNumber + 3, primaryText.Lines.Count - 1);
|
||||
endLine = primaryText.Lines[index];
|
||||
}
|
||||
|
||||
return new TextSpan(startLine.Start, endLine.End - startLine.Start);
|
||||
|
|
@ -188,5 +201,45 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
|
||||
return builder;
|
||||
}
|
||||
|
||||
// We have IVT access to the Roslyn APIs for product code, but not for testing.
|
||||
public enum ExcerptModeInternal
|
||||
{
|
||||
SingleLine = ExcerptMode.SingleLine,
|
||||
Tooltip = ExcerptMode.Tooltip,
|
||||
}
|
||||
|
||||
// We have IVT access to the Roslyn APIs for product code, but not for testing.
|
||||
public readonly struct ExcerptResultInternal
|
||||
{
|
||||
public readonly SourceText Content;
|
||||
|
||||
public readonly TextSpan MappedSpan;
|
||||
|
||||
public readonly ImmutableArray<ClassifiedSpan> ClassifiedSpans;
|
||||
|
||||
public readonly Document Document;
|
||||
|
||||
public readonly TextSpan Span;
|
||||
|
||||
public ExcerptResultInternal(
|
||||
SourceText content,
|
||||
TextSpan mappedSpan,
|
||||
ImmutableArray<ClassifiedSpan> classifiedSpans,
|
||||
Document document,
|
||||
TextSpan span)
|
||||
{
|
||||
Content = content;
|
||||
MappedSpan = mappedSpan;
|
||||
ClassifiedSpans = classifiedSpans;
|
||||
Document = document;
|
||||
Span = span;
|
||||
}
|
||||
|
||||
public ExcerptResult ToExcerptResult()
|
||||
{
|
||||
return new ExcerptResult(Content, MappedSpan, ClassifiedSpans, Document, Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Host;
|
|||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Xunit;
|
||||
using static Microsoft.CodeAnalysis.Razor.RazorDocumentExcerptService;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Razor
|
||||
{
|
||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp()
|
||||
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp()
|
||||
{
|
||||
// Arrange
|
||||
var (sourceText, primarySpan) = CreateText(
|
||||
|
|
@ -53,13 +54,19 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
|
||||
|
||||
// Act
|
||||
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
|
||||
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(secondarySpan, result.Value.Span);
|
||||
Assert.Same(secondary, result.Value.Document);
|
||||
|
||||
// Verifies that the right part of the primary document will be highlighted.
|
||||
Assert.Equal(
|
||||
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
|
||||
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Equal(@" var foo = ""Hello, World!"";", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
|
||||
Assert.Collection(
|
||||
result.Value.ClassifiedSpans,
|
||||
|
|
@ -91,7 +98,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ImplicitExpression()
|
||||
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_ImplicitExpression()
|
||||
{
|
||||
// Arrange
|
||||
var (sourceText, primarySpan) = CreateText(
|
||||
|
|
@ -111,13 +118,19 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
|
||||
|
||||
// Act
|
||||
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
|
||||
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(secondarySpan, result.Value.Span);
|
||||
Assert.Same(secondary, result.Value.Document);
|
||||
|
||||
// Verifies that the right part of the primary document will be highlighted.
|
||||
Assert.Equal(
|
||||
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
|
||||
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Equal(@" <body>@foo</body>", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
|
||||
Assert.Collection(
|
||||
result.Value.ClassifiedSpans,
|
||||
|
|
@ -139,7 +152,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ComplexLine()
|
||||
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_ComplexLine()
|
||||
{
|
||||
// Arrange
|
||||
var (sourceText, primarySpan) = CreateText(
|
||||
|
|
@ -159,13 +172,19 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
|
||||
|
||||
// Act
|
||||
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
|
||||
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(secondarySpan, result.Value.Span);
|
||||
Assert.Same(secondary, result.Value.Document);
|
||||
|
||||
// Verifies that the right part of the primary document will be highlighted.
|
||||
Assert.Equal(
|
||||
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
|
||||
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Equal(@" <div>@(3 + 4)</div><div>@(foo + foo)</div>", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
|
||||
Assert.Collection(
|
||||
result.Value.ClassifiedSpans,
|
||||
|
|
@ -217,7 +236,7 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryExcerptAsync_MultiLine_CanClassifyCSharp()
|
||||
public async Task TryGetExcerptInternalAsync_MultiLine_CanClassifyCSharp()
|
||||
{
|
||||
// Arrange
|
||||
var (sourceText, primarySpan) = CreateText(
|
||||
|
|
@ -226,8 +245,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
@{
|
||||
var |foo| = ""Hello, World!"";
|
||||
}
|
||||
<body>@foo</body>
|
||||
<div>@(3 + 4)</div><div>@(foo + foo)</div>
|
||||
<body></body>
|
||||
<div></div>
|
||||
</html>
|
||||
");
|
||||
|
||||
|
|
@ -237,17 +256,27 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
|
||||
|
||||
// Act
|
||||
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.Tooltip, CancellationToken.None);
|
||||
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.Tooltip, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(secondarySpan, result.Value.Span);
|
||||
Assert.Same(secondary, result.Value.Document);
|
||||
|
||||
// Verifies that the right part of the primary document will be highlighted.
|
||||
Assert.Equal(
|
||||
@"@{
|
||||
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
|
||||
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Equal(
|
||||
@"
|
||||
<html>
|
||||
@{
|
||||
var foo = ""Hello, World!"";
|
||||
}",
|
||||
}
|
||||
<body></body>
|
||||
<div></div>",
|
||||
result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Collection(
|
||||
|
|
@ -255,7 +284,12 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
c =>
|
||||
{
|
||||
Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType);
|
||||
Assert.Equal("@{", result.Value.Content.GetSubText(c.TextSpan).ToString());
|
||||
Assert.Equal(
|
||||
@"
|
||||
<html>
|
||||
@{",
|
||||
result.Value.Content.GetSubText(c.TextSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
},
|
||||
c =>
|
||||
{
|
||||
|
|
@ -285,12 +319,17 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
c =>
|
||||
{
|
||||
Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType);
|
||||
Assert.Equal("}", result.Value.Content.GetSubText(c.TextSpan).ToString());
|
||||
Assert.Equal(
|
||||
@"}
|
||||
<body></body>
|
||||
<div></div>",
|
||||
result.Value.Content.GetSubText(c.TextSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryExcerptAsync_MultiLine_Boundaries_CanClassifyCSharp()
|
||||
public async Task TryGetExcerptInternalAsync_MultiLine_Boundaries_CanClassifyCSharp()
|
||||
{
|
||||
// Arrange
|
||||
var (sourceText, primarySpan) = CreateText(@"@{ var |foo| = ""Hello, World!""; }");
|
||||
|
|
@ -301,13 +340,19 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
|
||||
|
||||
// Act
|
||||
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.Tooltip, CancellationToken.None);
|
||||
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.Tooltip, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(secondarySpan, result.Value.Span);
|
||||
Assert.Same(secondary, result.Value.Document);
|
||||
|
||||
// Verifies that the right part of the primary document will be highlighted.
|
||||
Assert.Equal(
|
||||
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
|
||||
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
|
||||
ignoreLineEndingDifferences: true);
|
||||
|
||||
Assert.Equal(
|
||||
@"@{ var foo = ""Hello, World!""; }",
|
||||
result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue