File: AutoInsert\CloseTextTagOnAutoInsertProvider.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 System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.AspNetCore.Razor.Language.Syntax;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.Razor.AutoInsert;
 
internal class CloseTextTagOnAutoInsertProvider : IOnAutoInsertProvider
{
    public string TriggerCharacter => ">";
 
    public bool TryResolveInsertion(
        Position position,
        RazorCodeDocument codeDocument,
        bool enableAutoClosingTags,
        [NotNullWhen(true)] out VSInternalDocumentOnAutoInsertResponseItem? autoInsertEdit)
    {
        if (!enableAutoClosingTags || !IsAtTextTag(codeDocument, position))
        {
            autoInsertEdit = null;
            return false;
        }
 
        // This is a text tag.
        var format = InsertTextFormat.Snippet;
        var edit = LspFactory.CreateTextEdit(position, $"$0</{SyntaxConstants.TextTagName}>");
 
        autoInsertEdit = new()
        {
            TextEdit = edit,
            TextEditFormat = format
        };
 
        return true;
    }
 
    private static bool IsAtTextTag(RazorCodeDocument codeDocument, Position position)
    {
        if (!codeDocument.Source.Text.TryGetAbsoluteIndex(position, out var absoluteIndex))
        {
            return false;
        }
 
        var syntaxRoot = codeDocument.GetRequiredSyntaxRoot();
        var token = syntaxRoot.FindToken(absoluteIndex - 1);
 
        // Make sure the end </text> tag doesn't already exist
        if (token.Parent is MarkupStartTagSyntax
            {
                IsMarkupTransition: true,
                Parent: MarkupElementSyntax { EndTag: null }
            } startTag)
        {
            Debug.Assert(startTag.Name.Content == SyntaxConstants.TextTagName, "MarkupTransition that is not a <text> tag.");
 
            return true;
        }
 
        return false;
    }
}