File: Snippets\XmlSnippetParser.CodeSnippet.cs
Web Access
Project: src\src\Razor\src\Razor\src\Microsoft.VisualStudio.LanguageServices.Razor\Microsoft.VisualStudio.LanguageServices.Razor.csproj (Microsoft.VisualStudio.LanguageServices.Razor)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
using Roslyn.Utilities;
 
namespace Microsoft.VisualStudio.Razor.Snippets;
 
internal partial class XmlSnippetParser
{
    /// <summary>
    /// Shamelessly copied from the editor
    /// https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform?path=/src/Editor/VisualStudio/Impl/Snippet/CodeSnippet.cs
    /// </summary>
    internal class CodeSnippet
    {
        private const string ExpansionSnippetType = "Expansion";
 
        private readonly string[]? _snippetTypes;
 
        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="codeSnippetElement">XElement representing the CodeSnippet node.</param>
        public CodeSnippet(XElement codeSnippetElement)
        {
            var header = GetElementWithoutNamespace(codeSnippetElement, "Header");
            if (header == null)
            {
                throw new InvalidOperationException("snippet element is missing header.");
            }
 
            CodeSnippetElement = codeSnippetElement;
 
            Title = GetElementInnerText(header, "Title");
            Shortcut = GetElementInnerText(header, "Shortcut");
            var snippetTypes = GetElementsWithoutNamespace(header, "SnippetTypes");
            if (snippetTypes != null)
            {
                _snippetTypes = snippetTypes.Elements().Select(e => e.Value.Trim()).ToArray();
            }
        }
 
        public string Title { get; }
 
        public string Shortcut { get; }
 
        public XElement CodeSnippetElement { get; }
 
        public bool IsExpansionSnippet()
        {
            return _snippetTypes?.Contains(ExpansionSnippetType, StringComparer.OrdinalIgnoreCase) == true;
        }
 
        public static CodeSnippet ReadSnippetFromFile(string filePath, string snippetTitle)
        {
            var document = XDocument.Load(filePath);
            var snippets = ReadSnippets(document);
 
            var matchingSnippet = snippets.Single(s => string.Equals(s.Title, snippetTitle, StringComparison.OrdinalIgnoreCase));
            return matchingSnippet;
        }
 
        private static ImmutableArray<XElement> ReadCodeSnippetElements(XDocument document)
        {
            var codeSnippetsElement = document.Root;
            if (codeSnippetsElement is null)
                return ImmutableArray<XElement>.Empty;
 
            if (codeSnippetsElement.Name.LocalName.Equals("CodeSnippets", StringComparison.OrdinalIgnoreCase))
            {
                return codeSnippetsElement.Elements().Where(e => e.Name.LocalName.Equals("CodeSnippet", StringComparison.OrdinalIgnoreCase)).ToImmutableArray();
            }
            else if (codeSnippetsElement.Name.LocalName.Equals("CodeSnippet", StringComparison.OrdinalIgnoreCase))
            {
                return ImmutableArray.Create(codeSnippetsElement);
            }
 
            return ImmutableArray<XElement>.Empty;
        }
 
        public static IEnumerable<XElement> GetElementsWithoutNamespace(XElement element, string localName)
        {
            return element.Elements().Where(e => e.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase));
        }
 
        public static XElement? GetElementWithoutNamespace(XElement? element, string localName)
        {
            return element?.Elements().FirstOrDefault(e => e.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase));
        }
 
        public static string GetElementInnerText(XElement element, string subElementName)
        {
            var subElement = GetElementWithoutNamespace(element, subElementName);
            return subElement == null ? string.Empty : subElement.Value.Trim();
        }
 
        public static ImmutableArray<CodeSnippet> ReadSnippets(XDocument document)
        {
            return ReadCodeSnippetElements(document).SelectAsArray(element => new CodeSnippet(element));
        }
    }
}