Skip to content
This repository was archived by the owner on Dec 19, 2018. It is now read-only.

Commit a3d0c8f

Browse files
committed
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.
1 parent 5229e65 commit a3d0c8f

File tree

2 files changed

+123
-25
lines changed

2 files changed

+123
-25
lines changed

src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentExcerptService.cs

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ public RazorDocumentExcerptService(DocumentSnapshot document, ISpanMappingServic
3737
ExcerptMode mode,
3838
CancellationToken cancellationToken)
3939
{
40+
var result = await TryGetExcerptInternalAsync(document, span, (ExcerptModeInternal)mode, cancellationToken).ConfigureAwait(false);
41+
return result?.ToExcerptResult();
42+
}
43+
44+
public async Task<ExcerptResultInternal?> TryGetExcerptInternalAsync(
45+
Document document,
46+
TextSpan span,
47+
ExcerptModeInternal mode,
48+
CancellationToken cancellationToken)
49+
{
4050
if (_document == null)
4151
{
4252
return null;
@@ -78,7 +88,8 @@ public RazorDocumentExcerptService(DocumentSnapshot document, ISpanMappingServic
7888
// Now translate everything to be relative to the excerpt
7989
var offset = 0 - excerptSpan.Start;
8090
var excerptText = primaryText.GetSubText(excerptSpan);
81-
excerptSpan = new TextSpan(excerptSpan.Start + offset, excerptSpan.Length);
91+
excerptSpan = new TextSpan(0, excerptSpan.Length);
92+
primarySpan = new TextSpan(primarySpan.Start + offset, primarySpan.Length);
8293

8394
for (var i = 0; i < classifiedSpans.Count; i++)
8495
{
@@ -89,24 +100,26 @@ public RazorDocumentExcerptService(DocumentSnapshot document, ISpanMappingServic
89100
classifiedSpans[i] = new ClassifiedSpan(classifiedSpan.ClassificationType, updated);
90101
}
91102

92-
return new ExcerptResult(excerptText, excerptSpan, classifiedSpans.ToImmutable(), document, span);
103+
return new ExcerptResultInternal(excerptText, primarySpan, classifiedSpans.ToImmutable(), document, span);
93104
}
94-
95-
private TextSpan ChooseExcerptSpan(SourceText primaryText, TextSpan primarySpan, ExcerptMode mode)
105+
106+
private TextSpan ChooseExcerptSpan(SourceText primaryText, TextSpan primarySpan, ExcerptModeInternal mode)
96107
{
97108
var startLine = primaryText.Lines.GetLineFromPosition(primarySpan.Start);
98109
var endLine = primaryText.Lines.GetLineFromPosition(primarySpan.End);
99110

100-
// If we're showing a single line then this will do. Otherwise expand the range by 1 in
111+
// If we're showing a single line then this will do. Otherwise expand the range by 3 in
101112
// each direction (if possible).
102-
if (mode == ExcerptMode.Tooltip && startLine.LineNumber > 0)
113+
if (mode == ExcerptModeInternal.Tooltip)
103114
{
104-
startLine = primaryText.Lines[startLine.LineNumber - 1];
115+
var index = Math.Max(startLine.LineNumber - 3, 0);
116+
startLine = primaryText.Lines[index];
105117
}
106118

107-
if (mode == ExcerptMode.Tooltip && endLine.LineNumber < primaryText.Lines.Count - 1)
119+
if (mode == ExcerptModeInternal.Tooltip)
108120
{
109-
endLine = primaryText.Lines[endLine.LineNumber + 1];
121+
var index = Math.Min(endLine.LineNumber + 3, primaryText.Lines.Count - 1);
122+
endLine = primaryText.Lines[index];
110123
}
111124

112125
return new TextSpan(startLine.Start, endLine.End - startLine.Start);
@@ -188,5 +201,45 @@ private TextSpan ChooseExcerptSpan(SourceText primaryText, TextSpan primarySpan,
188201

189202
return builder;
190203
}
204+
205+
// We have IVT access to the Roslyn APIs for product code, but not for testing.
206+
public enum ExcerptModeInternal
207+
{
208+
SingleLine = ExcerptMode.SingleLine,
209+
Tooltip = ExcerptMode.Tooltip,
210+
}
211+
212+
// We have IVT access to the Roslyn APIs for product code, but not for testing.
213+
public readonly struct ExcerptResultInternal
214+
{
215+
public readonly SourceText Content;
216+
217+
public readonly TextSpan MappedSpan;
218+
219+
public readonly ImmutableArray<ClassifiedSpan> ClassifiedSpans;
220+
221+
public readonly Document Document;
222+
223+
public readonly TextSpan Span;
224+
225+
public ExcerptResultInternal(
226+
SourceText content,
227+
TextSpan mappedSpan,
228+
ImmutableArray<ClassifiedSpan> classifiedSpans,
229+
Document document,
230+
TextSpan span)
231+
{
232+
Content = content;
233+
MappedSpan = mappedSpan;
234+
ClassifiedSpans = classifiedSpans;
235+
Document = document;
236+
Span = span;
237+
}
238+
239+
public ExcerptResult ToExcerptResult()
240+
{
241+
return new ExcerptResult(Content, MappedSpan, ClassifiedSpans, Document, Span);
242+
}
243+
}
191244
}
192245
}

test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/RazorExcerptServiceTest.cs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
1414
using Microsoft.CodeAnalysis.Text;
1515
using Xunit;
16+
using static Microsoft.CodeAnalysis.Razor.RazorDocumentExcerptService;
1617

1718
namespace Microsoft.CodeAnalysis.Razor
1819
{
@@ -33,7 +34,7 @@ protected override void ConfigureLanguageServices(List<ILanguageService> service
3334
}
3435

3536
[Fact]
36-
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp()
37+
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp()
3738
{
3839
// Arrange
3940
var (sourceText, primarySpan) = CreateText(
@@ -53,13 +54,19 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp()
5354
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
5455

5556
// Act
56-
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
57+
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
5758

5859
// Assert
5960
Assert.NotNull(result);
6061
Assert.Equal(secondarySpan, result.Value.Span);
6162
Assert.Same(secondary, result.Value.Document);
6263

64+
// Verifies that the right part of the primary document will be highlighted.
65+
Assert.Equal(
66+
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
67+
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
68+
ignoreLineEndingDifferences: true);
69+
6370
Assert.Equal(@" var foo = ""Hello, World!"";", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
6471
Assert.Collection(
6572
result.Value.ClassifiedSpans,
@@ -91,7 +98,7 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp()
9198
}
9299

93100
[Fact]
94-
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ImplicitExpression()
101+
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_ImplicitExpression()
95102
{
96103
// Arrange
97104
var (sourceText, primarySpan) = CreateText(
@@ -111,13 +118,19 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ImplicitExpressio
111118
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
112119

113120
// Act
114-
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
121+
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
115122

116123
// Assert
117124
Assert.NotNull(result);
118125
Assert.Equal(secondarySpan, result.Value.Span);
119126
Assert.Same(secondary, result.Value.Document);
120127

128+
// Verifies that the right part of the primary document will be highlighted.
129+
Assert.Equal(
130+
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
131+
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
132+
ignoreLineEndingDifferences: true);
133+
121134
Assert.Equal(@" <body>@foo</body>", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
122135
Assert.Collection(
123136
result.Value.ClassifiedSpans,
@@ -139,7 +152,7 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ImplicitExpressio
139152
}
140153

141154
[Fact]
142-
public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ComplexLine()
155+
public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_ComplexLine()
143156
{
144157
// Arrange
145158
var (sourceText, primarySpan) = CreateText(
@@ -159,13 +172,19 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ComplexLine()
159172
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
160173

161174
// Act
162-
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.SingleLine, CancellationToken.None);
175+
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.SingleLine, CancellationToken.None);
163176

164177
// Assert
165178
Assert.NotNull(result);
166179
Assert.Equal(secondarySpan, result.Value.Span);
167180
Assert.Same(secondary, result.Value.Document);
168181

182+
// Verifies that the right part of the primary document will be highlighted.
183+
Assert.Equal(
184+
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
185+
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
186+
ignoreLineEndingDifferences: true);
187+
169188
Assert.Equal(@" <div>@(3 + 4)</div><div>@(foo + foo)</div>", result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
170189
Assert.Collection(
171190
result.Value.ClassifiedSpans,
@@ -217,7 +236,7 @@ public async Task TryExcerptAsync_SingleLine_CanClassifyCSharp_ComplexLine()
217236
}
218237

219238
[Fact]
220-
public async Task TryExcerptAsync_MultiLine_CanClassifyCSharp()
239+
public async Task TryGetExcerptInternalAsync_MultiLine_CanClassifyCSharp()
221240
{
222241
// Arrange
223242
var (sourceText, primarySpan) = CreateText(
@@ -226,8 +245,8 @@ public async Task TryExcerptAsync_MultiLine_CanClassifyCSharp()
226245
@{
227246
var |foo| = ""Hello, World!"";
228247
}
229-
<body>@foo</body>
230-
<div>@(3 + 4)</div><div>@(foo + foo)</div>
248+
<body></body>
249+
<div></div>
231250
</html>
232251
");
233252

@@ -237,25 +256,40 @@ public async Task TryExcerptAsync_MultiLine_CanClassifyCSharp()
237256
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
238257

239258
// Act
240-
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.Tooltip, CancellationToken.None);
259+
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.Tooltip, CancellationToken.None);
241260

242261
// Assert
243262
Assert.NotNull(result);
244263
Assert.Equal(secondarySpan, result.Value.Span);
245264
Assert.Same(secondary, result.Value.Document);
246265

266+
// Verifies that the right part of the primary document will be highlighted.
247267
Assert.Equal(
248-
@"@{
268+
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
269+
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
270+
ignoreLineEndingDifferences: true);
271+
272+
Assert.Equal(
273+
@"
274+
<html>
275+
@{
249276
var foo = ""Hello, World!"";
250-
}",
277+
}
278+
<body></body>
279+
<div></div>",
251280
result.Value.Content.ToString(), ignoreLineEndingDifferences: true);
252281

253282
Assert.Collection(
254283
result.Value.ClassifiedSpans,
255284
c =>
256285
{
257286
Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType);
258-
Assert.Equal("@{", result.Value.Content.GetSubText(c.TextSpan).ToString());
287+
Assert.Equal(
288+
@"
289+
<html>
290+
@{",
291+
result.Value.Content.GetSubText(c.TextSpan).ToString(),
292+
ignoreLineEndingDifferences: true);
259293
},
260294
c =>
261295
{
@@ -285,12 +319,17 @@ public async Task TryExcerptAsync_MultiLine_CanClassifyCSharp()
285319
c =>
286320
{
287321
Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType);
288-
Assert.Equal("}", result.Value.Content.GetSubText(c.TextSpan).ToString());
322+
Assert.Equal(
323+
@"}
324+
<body></body>
325+
<div></div>",
326+
result.Value.Content.GetSubText(c.TextSpan).ToString(),
327+
ignoreLineEndingDifferences: true);
289328
});
290329
}
291330

292331
[Fact]
293-
public async Task TryExcerptAsync_MultiLine_Boundaries_CanClassifyCSharp()
332+
public async Task TryGetExcerptInternalAsync_MultiLine_Boundaries_CanClassifyCSharp()
294333
{
295334
// Arrange
296335
var (sourceText, primarySpan) = CreateText(@"@{ var |foo| = ""Hello, World!""; }");
@@ -301,13 +340,19 @@ public async Task TryExcerptAsync_MultiLine_Boundaries_CanClassifyCSharp()
301340
var secondarySpan = await GetSecondarySpanAsync(primary, primarySpan, secondary);
302341

303342
// Act
304-
var result = await service.TryExcerptAsync(secondary, secondarySpan, ExcerptMode.Tooltip, CancellationToken.None);
343+
var result = await service.TryGetExcerptInternalAsync(secondary, secondarySpan, ExcerptModeInternal.Tooltip, CancellationToken.None);
305344

306345
// Assert
307346
Assert.NotNull(result);
308347
Assert.Equal(secondarySpan, result.Value.Span);
309348
Assert.Same(secondary, result.Value.Document);
310349

350+
// Verifies that the right part of the primary document will be highlighted.
351+
Assert.Equal(
352+
(await secondary.GetTextAsync()).GetSubText(secondarySpan).ToString(),
353+
result.Value.Content.GetSubText(result.Value.MappedSpan).ToString(),
354+
ignoreLineEndingDifferences: true);
355+
311356
Assert.Equal(
312357
@"@{ var foo = ""Hello, World!""; }",
313358
result.Value.Content.ToString(), ignoreLineEndingDifferences: true);

0 commit comments

Comments
 (0)