diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassificationContext.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassificationContext.cs
index 802a51bc8805c..2f8e3550b60a6 100644
--- a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassificationContext.cs
+++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassificationContext.cs
@@ -12,9 +12,12 @@ internal readonly struct AspNetCoreEmbeddedLanguageClassificationContext
{
private readonly EmbeddedLanguageClassificationContext _context;
- public AspNetCoreEmbeddedLanguageClassificationContext(EmbeddedLanguageClassificationContext context)
+ internal AspNetCoreEmbeddedLanguageClassificationContext(
+ EmbeddedLanguageClassificationContext context,
+ AspNetCoreVirtualCharSequence virtualCharSequence)
{
_context = context;
+ VirtualCharSequence = virtualCharSequence;
}
///
@@ -23,6 +26,9 @@ public AspNetCoreEmbeddedLanguageClassificationContext(EmbeddedLanguageClassific
///
public SemanticModel SemanticModel => _context.SemanticModel;
+ ///
+ public AspNetCoreVirtualCharSequence VirtualCharSequence { get; }
+
///
public CancellationToken CancellationToken => _context.CancellationToken;
diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs
new file mode 100644
index 0000000000000..e54d787afd63a
--- /dev/null
+++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualChar.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text;
+using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages
+{
+ internal readonly struct AspNetCoreVirtualChar
+ {
+ private readonly VirtualChar _virtualChar;
+
+ internal AspNetCoreVirtualChar(VirtualChar virtualChar)
+ {
+ _virtualChar = virtualChar;
+ }
+
+ ///
+ public Rune Rune => _virtualChar.Rune;
+
+ ///
+ public char SurrogateChar => _virtualChar.SurrogateChar;
+
+ ///
+ public TextSpan Span => _virtualChar.Span;
+
+ ///
+ public int Value => _virtualChar.Value;
+ }
+}
diff --git a/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs
new file mode 100644
index 0000000000000..12fc5525412d9
--- /dev/null
+++ b/src/Tools/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreVirtualCharSequence.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages
+{
+ ///
+ internal readonly struct AspNetCoreVirtualCharSequence
+ {
+ private readonly VirtualCharSequence _virtualCharSequence;
+
+ internal AspNetCoreVirtualCharSequence(VirtualCharSequence virtualCharSequence)
+ {
+ _virtualCharSequence = virtualCharSequence;
+ }
+
+ ///
+ public int Length => _virtualCharSequence.Length;
+
+ ///
+ public AspNetCoreVirtualChar this[int index] => new(_virtualCharSequence[index]);
+ }
+}
diff --git a/src/Tools/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassifier.cs b/src/Tools/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassifier.cs
index 32f254ede03df..51df99756cf30 100644
--- a/src/Tools/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassifier.cs
+++ b/src/Tools/ExternalAccess/AspNetCore/Internal/EmbeddedLanguages/AspNetCoreEmbeddedLanguageClassifier.cs
@@ -28,7 +28,15 @@ public void RegisterClassifications(EmbeddedLanguageClassificationContext contex
return;
var classifiers = AspNetCoreClassifierExtensionProvider.GetExtensions(context.Project);
- var aspContext = new AspNetCoreEmbeddedLanguageClassificationContext(context);
+ if (classifiers.Length == 0)
+ return;
+
+ var virtualChars = context.VirtualCharService.TryConvertToVirtualChars(context.SyntaxToken);
+ if (virtualChars.IsDefaultOrEmpty)
+ return;
+
+ var aspContext = new AspNetCoreEmbeddedLanguageClassificationContext(
+ context, new AspNetCoreVirtualCharSequence(virtualChars));
foreach (var classifier in classifiers)
classifier.RegisterClassifications(aspContext);
}
diff --git a/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/AbstractEmbeddedLanguageClassificationService.cs b/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/AbstractEmbeddedLanguageClassificationService.cs
index 24f4902bc16a9..91ea5b504cf6f 100644
--- a/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/AbstractEmbeddedLanguageClassificationService.cs
+++ b/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/AbstractEmbeddedLanguageClassificationService.cs
@@ -42,6 +42,11 @@ internal abstract class AbstractEmbeddedLanguageClassificationService : IEmbedde
///
private readonly Dictionary>> _identifierToClassifiers = new(StringComparer.OrdinalIgnoreCase);
+ ///
+ /// Information about the embedded language.
+ ///
+ private readonly EmbeddedLanguageInfo _info;
+
///
/// Helper to look at string literals and determine what language they are annotated to take.
///
@@ -71,6 +76,7 @@ protected AbstractEmbeddedLanguageClassificationService(
foreach (var (_, classifiers) in _identifierToClassifiers)
classifiers.RemoveDuplicates();
+ _info = info;
_detector = new EmbeddedLanguageDetector(info, _identifierToClassifiers.Keys.ToImmutableArray());
_syntaxTokenKinds.Add(syntaxKinds.CharacterLiteralToken);
@@ -165,7 +171,7 @@ private void ClassifyToken(SyntaxToken token)
_classifierBuffer.Clear();
var context = new EmbeddedLanguageClassificationContext(
- _project, _semanticModel, token, _options, _result, _cancellationToken);
+ _project, _semanticModel, token, _options, _service._info.VirtualCharService, _result, _cancellationToken);
// First, see if this is a string annotated with either a comment or [StringSyntax] attribute. If
// so, delegate to the first classifier we have registered for whatever language ID we find.
diff --git a/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/EmbeddedLanguageClassifierContext.cs b/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/EmbeddedLanguageClassifierContext.cs
index 866d202fc068b..978224cee5bc0 100644
--- a/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/EmbeddedLanguageClassifierContext.cs
+++ b/src/Workspaces/Core/Portable/Classification/EmbeddedLanguages/EmbeddedLanguageClassifierContext.cs
@@ -4,6 +4,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.Classification;
+using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
@@ -11,7 +12,6 @@ namespace Microsoft.CodeAnalysis.Classification
{
internal struct EmbeddedLanguageClassificationContext
{
- internal readonly ClassificationOptions Options;
private readonly ArrayBuilder _result;
public Project? Project { get; }
@@ -28,11 +28,15 @@ internal struct EmbeddedLanguageClassificationContext
public CancellationToken CancellationToken { get; }
+ internal readonly ClassificationOptions Options;
+ internal readonly IVirtualCharService VirtualCharService;
+
internal EmbeddedLanguageClassificationContext(
Project? project,
SemanticModel semanticModel,
SyntaxToken syntaxToken,
ClassificationOptions options,
+ IVirtualCharService virtualCharService,
ArrayBuilder result,
CancellationToken cancellationToken)
{
@@ -40,6 +44,7 @@ internal EmbeddedLanguageClassificationContext(
SemanticModel = semanticModel;
SyntaxToken = syntaxToken;
Options = options;
+ VirtualCharService = virtualCharService;
_result = result;
CancellationToken = cancellationToken;
}
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.cs
index 7d2a33b62242e..6a5ed7c255606 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.cs
@@ -63,7 +63,14 @@ private VirtualCharSequence(Chunk sequence, TextSpan span)
_span = span;
}
+ ///
+ /// Gets the number of elements contained in the .
+ ///
public int Length => _span.Length;
+
+ ///
+ /// Gets the at the specified index.
+ ///
public VirtualChar this[int index] => _leafCharacters[_span.Start + index];
public bool IsDefault => _leafCharacters == null;