File: DocumentMapping\PreferHtmlInAttributeValuesDocumentPositionStrategy.cs
Web Access
Project: src\src\Razor\src\Razor\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj (Microsoft.CodeAnalysis.Razor.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.CodeAnalysis.Razor.Protocol;
 
namespace Microsoft.CodeAnalysis.Razor.DocumentMapping;
 
// The main reason for this service is auto-insert of empty double quotes when a user types
// equals "=" after Blazor component attribute. We think this is C# (correctly I guess)
// and wouldn't forward auto-insert request to HTML in this case. By essentially overriding
// language info here we allow the request to be sent over to HTML where it will insert empty
// double-quotes as it would for any other attribute value
internal sealed class PreferHtmlInAttributeValuesDocumentPositionInfoStrategy : IDocumentPositionInfoStrategy
{
    public static IDocumentPositionInfoStrategy Instance { get; } = new PreferHtmlInAttributeValuesDocumentPositionInfoStrategy();
 
    private PreferHtmlInAttributeValuesDocumentPositionInfoStrategy()
    {
    }
 
    public DocumentPositionInfo GetPositionInfo(IDocumentMappingService mappingService, RazorCodeDocument codeDocument, int hostDocumentIndex)
    {
        var positionInfo = DefaultDocumentPositionInfoStrategy.Instance.GetPositionInfo(mappingService, codeDocument, hostDocumentIndex);
 
        var absolutePosition = positionInfo.HostDocumentIndex;
        if (positionInfo.LanguageKind != RazorLanguageKind.CSharp ||
            absolutePosition < 1)
        {
            return positionInfo;
        }
 
        // Get the node at previous position to see if we are after markup tag helper attribute,
        // and more specifically after the EqualsToken of it
        var previousPosition = absolutePosition - 1;
 
        var syntaxRoot = codeDocument.GetRequiredSyntaxRoot();
 
        var owner = syntaxRoot.FindInnermostNode(previousPosition);
 
        if (owner is MarkupTagHelperAttributeSyntax { EqualsToken: { IsMissing: false } equalsToken } &&
            equalsToken.EndPosition == positionInfo.HostDocumentIndex)
        {
            return new DocumentPositionInfo(RazorLanguageKind.Html, codeDocument.Source.Text.GetPosition(absolutePosition), absolutePosition);
        }
 
        return positionInfo;
    }
}