File: Handler\InlineCompletions\XmlSnippetParser.ParsedXmlSnippet.cs
Web Access
Project: src\src\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj (Microsoft.CodeAnalysis.LanguageServer.Protocol)
// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions;
 
internal partial class XmlSnippetParser
{
    internal class ParsedXmlSnippet
    {
        public ImmutableArray<SnippetPart> Parts { get; }
        public string DefaultText { get; }
 
        public ParsedXmlSnippet(ImmutableArray<SnippetPart> parts)
        {
            Parts = parts;
 
            using var _ = PooledStringBuilder.GetInstance(out var defaultSnippetBuilder);
            foreach (var part in parts)
            {
                var textToAdd = part.DefaultText;
                defaultSnippetBuilder.Append(textToAdd);
            }
 
            DefaultText = defaultSnippetBuilder.ToString();
        }
    }
 
    internal abstract record SnippetPart(string DefaultText);
 
    internal record SnippetFieldPart(string FieldName, string DefaultText, int? EditIndex) : SnippetPart(DefaultText);
 
    internal record SnippetFunctionPart(string FieldName, string DefaultText, int? EditIndex, string FunctionName, string? FunctionParam)
        : SnippetFieldPart(FieldName, DefaultText, EditIndex)
    {
        public async Task<SnippetFunctionPart> WithSnippetFunctionResultAsync(Document documentWithSnippet, TextSpan fieldSpan, SimplifierOptions simplifierOptions, CancellationToken cancellationToken)
        {
            var snippetFunctionService = documentWithSnippet.Project.GetRequiredLanguageService<SnippetFunctionService>();
            switch (FunctionName)
            {
                case "SimpleTypeName":
                    if (FunctionParam == null)
                    {
                        return this;
                    }
 
                    var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(documentWithSnippet, fieldSpan, FunctionParam, simplifierOptions, cancellationToken).ConfigureAwait(false);
                    if (simplifiedTypeName == null)
                    {
                        return this;
                    }
 
                    return this with { DefaultText = simplifiedTypeName };
                case "ClassName":
                    var className = await snippetFunctionService.GetContainingClassNameAsync(documentWithSnippet, fieldSpan.Start, cancellationToken).ConfigureAwait(false);
                    if (className == null)
                    {
                        return this;
                    }
 
                    return this with { DefaultText = className };
                case "GenerateSwitchCases":
                    // Generate switch cases requires a multi-step snippet interaction, where the snippet is inserted first then the
                    // client calls back to on commit so that we can generate the cases for the specified switch value.
                    // This is not yet supported via LSP.
                    return this;
                default:
                    return this;
            }
        }
    }
 
    /// <summary>
    /// To indicate cursor location we put in a multi-line comment so that we can
    /// find it after formatting.
    /// </summary>
    internal record SnippetCursorPart() : SnippetPart("/*$0*/");
 
    internal record SnippetStringPart(string Text) : SnippetPart(Text);
}