diff --git a/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentExcerptService.cs b/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentExcerptService.cs index 93f836221f..bb3ba757cc 100644 --- a/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentExcerptService.cs +++ b/src/Microsoft.CodeAnalysis.Razor.Workspaces/RazorDocumentExcerptService.cs @@ -176,6 +176,10 @@ namespace Microsoft.CodeAnalysis.Razor secondaryDocument, secondarySpan, cancellationToken); + + // NOTE: The Classifier will only returns spans for things that it understands. That means + // that whitespace is not classified. The preview expects us to provide contiguous spans, + // so we are going to have to fill in the gaps. // Now we have to translate back to the primary document's coordinates. var offset = primarySpan.Start - secondarySpan.Start; @@ -185,11 +189,29 @@ namespace Microsoft.CodeAnalysis.Razor var updated = new TextSpan(classifiedSecondarySpan.TextSpan.Start + offset, classifiedSecondarySpan.TextSpan.Length); Debug.Assert(primarySpan.Contains(updated)); + + // Make sure that we're not introducing a gap. Remember, we need to fill in the whitespace. + if (remainingSpan.Start < updated.Start) + { + builder.Add(new ClassifiedSpan( + ClassificationTypeNames.Text, + new TextSpan(remainingSpan.Start, updated.Start - remainingSpan.Start))); + remainingSpan = new TextSpan(updated.Start, remainingSpan.Length - (updated.Start - remainingSpan.Start)); + } builder.Add(new ClassifiedSpan(classifiedSecondarySpan.ClassificationType, updated)); + remainingSpan = new TextSpan(updated.End, remainingSpan.Length - (updated.End - remainingSpan.Start)); + } + + // Make sure that we're not introducing a gap. Remember, we need to fill in the whitespace. + if (remainingSpan.Start < primarySpan.End) + { + builder.Add(new ClassifiedSpan( + ClassificationTypeNames.Text, + new TextSpan(remainingSpan.Start, primarySpan.End - remainingSpan.Start))); + remainingSpan = new TextSpan(primarySpan.End, remainingSpan.Length - (primarySpan.End - remainingSpan.Start)); } - remainingSpan = new TextSpan(primarySpan.End, remainingSpan.Length - primarySpan.Length); } // Deal with residue diff --git a/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/RazorExcerptServiceTest.cs b/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/RazorExcerptServiceTest.cs index 92cced1968..7466c4f09f 100644 --- a/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/RazorExcerptServiceTest.cs +++ b/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/RazorExcerptServiceTest.cs @@ -70,22 +70,42 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal(@" var foo = ""Hello, World!"";", result.Value.Content.ToString(), ignoreLineEndingDifferences: true); Assert.Collection( result.Value.ClassifiedSpans, + c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, c => { Assert.Equal(ClassificationTypeNames.Keyword, c.ClassificationType); Assert.Equal("var", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); Assert.Equal("foo", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); Assert.Equal("=", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.StringLiteral, c.ClassificationType); Assert.Equal("\"Hello, World!\"", result.Value.Content.GetSubText(c.TextSpan).ToString()); @@ -199,11 +219,21 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal("3", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); Assert.Equal("+", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.NumericLiteral, c.ClassificationType); Assert.Equal("4", result.Value.Content.GetSubText(c.TextSpan).ToString()); @@ -219,11 +249,21 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal("foo", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); Assert.Equal("+", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); Assert.Equal("foo", result.Value.Content.GetSubText(c.TextSpan).ToString()); @@ -292,21 +332,41 @@ namespace Microsoft.CodeAnalysis.Razor ignoreLineEndingDifferences: true); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal("\r\n ", result.Value.Content.GetSubText(c.TextSpan).ToString(), ignoreLineEndingDifferences: true); + }, + c => { Assert.Equal(ClassificationTypeNames.Keyword, c.ClassificationType); Assert.Equal("var", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); Assert.Equal("foo", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); Assert.Equal("=", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.StringLiteral, c.ClassificationType); Assert.Equal("\"Hello, World!\"", result.Value.Content.GetSubText(c.TextSpan).ToString()); @@ -317,6 +377,11 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal(";", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal("\r\n", result.Value.Content.GetSubText(c.TextSpan).ToString(), ignoreLineEndingDifferences: true); + }, + c => { Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); Assert.Equal( @@ -365,21 +430,41 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal("@{", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Keyword, c.ClassificationType); Assert.Equal("var", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.LocalName, c.ClassificationType); Assert.Equal("foo", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Operator, c.ClassificationType); Assert.Equal("=", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.StringLiteral, c.ClassificationType); Assert.Equal("\"Hello, World!\"", result.Value.Content.GetSubText(c.TextSpan).ToString()); @@ -390,6 +475,11 @@ namespace Microsoft.CodeAnalysis.Razor Assert.Equal(";", result.Value.Content.GetSubText(c.TextSpan).ToString()); }, c => + { + Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); + Assert.Equal(" ", result.Value.Content.GetSubText(c.TextSpan).ToString()); + }, + c => { Assert.Equal(ClassificationTypeNames.Text, c.ClassificationType); Assert.Equal("}", result.Value.Content.GetSubText(c.TextSpan).ToString());