diff options
Diffstat (limited to 'src/Editor/Language/Def/Intellisense/Snippet')
9 files changed, 473 insertions, 0 deletions
diff --git a/src/Editor/Language/Def/Intellisense/Snippet/CodeSnippet.cs b/src/Editor/Language/Def/Intellisense/Snippet/CodeSnippet.cs new file mode 100644 index 0000000..e5f0fa1 --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/CodeSnippet.cs @@ -0,0 +1,123 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public class CodeSnippet + { + public string Title { get; set; } + public string Shortcut { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public List<string> SnippetTypes { get; set; } + public string Code { get; set; } + public List<ExpansionField> Fields { get; set; } + public string FilePath { get; set; } + public string Language { get; set; } + public XElement Snippet { get; set; } + + public CodeSnippet() + { + + } + + public CodeSnippet(XElement codeSnippetElement, string filePath) + { + this.FilePath = filePath; + this.Fields = new List<ExpansionField>(); + this.SnippetTypes = new List<string>(); + + var header = codeSnippetElement.Element(GetXName("Header")); + this.Title = GetElementInnerText(header, "Title"); + this.Shortcut = GetElementInnerText(header, "Shortcut") ?? ""; // https://github.com/dotnet/roslyn/pull/31738 + this.Description = GetElementInnerText(header, "Description"); + this.Author = GetElementInnerText(header, "Author"); + var snippetTypes = header.Element(GetXName("SnippetTypes")); + if (snippetTypes != null) + { + var snippetTypeElements = snippetTypes.Elements(); + foreach (var snippetType in snippetTypeElements) + { + SnippetTypes.Add(snippetType.Value); + } + } + + Snippet = codeSnippetElement.Element(GetXName("Snippet")); + var declarations = Snippet.Element(GetXName("Declarations")); + ReadDeclarations(declarations); + var code = Snippet.Element(GetXName("Code")); + this.Code = code.Value.Replace("\n", "\r\n"); + this.Language = code.Attribute("Language").Value; + } + + private void ReadDeclarations(XElement declarations) + { + if (declarations == null) + { + return; + } + + foreach (var declarationElement in declarations.Elements()) + { + var defaultAttribute = declarationElement.Attribute("Default"); + var editableAttribute = declarationElement.Attribute("Editable"); + this.Fields.Add(new ExpansionField + { + ID = GetElementInnerText(declarationElement, "ID"), + ToolTip = GetElementInnerText(declarationElement, "ToolTip"), + Default = GetElementInnerText(declarationElement, "Default") ?? " ", + Function = GetElementInnerText(declarationElement, "Function"), + IsDefault = defaultAttribute != null && defaultAttribute.Value == "true", + Editable = editableAttribute == null || editableAttribute.Value == "true" || editableAttribute.Value == "1" + }); + } + } + + private static string GetElementInnerText(XElement element, string subElementName) + { + var subElement = element.Element(GetXName(subElementName)); + if (subElement == null) + { + return null; + } + + return subElement.Value; + } + + public static IEnumerable<CodeSnippet> ReadSnippetsFromFile(string filePath) + { + try + { + XDocument document = XDocument.Load(filePath); + var codeSnippetsElement = document.Root; + IEnumerable<XElement> codeSnippetElements = null; + if (codeSnippetsElement.Name.LocalName == "CodeSnippets") + { + codeSnippetElements = codeSnippetsElement.Elements(GetXName("CodeSnippet")); + } + else + { + codeSnippetElements = new[] { codeSnippetsElement }; + } + + return codeSnippetElements.Select(element => new CodeSnippet(element, filePath)); + } + catch (XmlException) + { + return Enumerable.Empty<CodeSnippet>(); + } + } + + private static XName GetXName(string localName) + { + return XName.Get(localName, "http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"); + } + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/ExpansionField.cs b/src/Editor/Language/Def/Intellisense/Snippet/ExpansionField.cs new file mode 100644 index 0000000..9bdef92 --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/ExpansionField.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public class ExpansionField + { + public string ID { get; set; } + public string ToolTip { get; set; } + public string Default { get; set; } + public string Function { get; set; } + + private List<int> offsets = new List<int>(); + + public int GetOffsetCount() + { + return offsets.Count; + } + + public void AddOffset(int offset) + { + offsets.Add(offset); + } + + public int GetOffset(int index) + { + return offsets[index]; + } + + public string GetDefault() + { + return Default; + } + + public int GetLength() + { + return Default.Length; + } + + public bool IsEditable() + { + return Editable; + } + + public XElement GetFunctionXML() + { + return new XElement(XName.Get("ExpansionField")) + { + Value = Function + }; + } + + public bool UsesFunction() + { + return Function != null; + } + + public bool IsDefault { get; set; } + public bool Editable { get; set; } + + public string GetName() + { + return ID; + } + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/ExpansionTemplate.cs b/src/Editor/Language/Def/Intellisense/Snippet/ExpansionTemplate.cs new file mode 100644 index 0000000..356d2bd --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/ExpansionTemplate.cs @@ -0,0 +1,148 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public class ExpansionTemplate + { + private string snippetFullText; + private readonly List<ExpansionField> tokens = new List<ExpansionField>(); + private int selectedOffset; + private int editOffset; + private string snippetFirst; + private string snippetLast; + + public CodeSnippet Snippet { get; set; } + + public ExpansionTemplate(string filePath) + :this(CodeSnippet.ReadSnippetsFromFile(filePath).First()) + { + + } + + public ExpansionTemplate(CodeSnippet snippet) + { + Snippet = snippet; + Parse(); + } + + private void Parse() + { + foreach (var field in Snippet.Fields) + { + tokens.Add(field); + } + + var matches = Regex.Matches(Snippet.Code, @"\$(\w+)\$"); + + var total = new StringBuilder(); + int index = 0; + int indexCorrection = 0; + foreach (Match match in matches) + { + string fieldName = match.Groups[1].Value; + string substitution = GetDefaultValue(fieldName) ?? ""; + if (match.Index > index) + { + total.Append(Snippet.Code.Substring(index, match.Index - index)); + } + + AddToken(total.Length, fieldName); + total.Append(substitution); + + index = match.Index + match.Length; + indexCorrection += substitution.Length; + } + + if (index <= Snippet.Code.Length - 1) + { + total.Append(Snippet.Code.Substring(index, Snippet.Code.Length - index)); + } + + this.snippetFullText = total.ToString(); + this.snippetFirst = snippetFullText.Substring(0, selectedOffset); + this.snippetLast = snippetFullText.Substring(selectedOffset, snippetFullText.Length - selectedOffset); + } + + private string GetDefaultValue(string fieldName) + { + ExpansionField field = FindField(fieldName); + if (field == null) + { + return null; + } + + return field.Default; + } + + private void AddToken(int position, string fieldName) + { + ExpansionField field = FindField(fieldName); + if (field != null) + { + field.AddOffset(position); + } + else if (fieldName == "selected") + { + this.selectedOffset = position; + } + else if (fieldName == "end") + { + this.editOffset = position; + } + } + + private ExpansionField FindField(string fieldName) + { + return tokens.FirstOrDefault(t => t.ID == fieldName); + } + + public string GetCodeSnippet() + { + return snippetFullText; + } + + public int GetSelectedOffset() + { + return selectedOffset; + } + + public int GetEditOffset() + { + return editOffset; + } + + public string GetCodeSnippet(bool all, bool first) + { + if (all) + { + return snippetFullText; + } + else if (first) + { + return snippetFirst; + } + else + { + return snippetLast; + } + } + + public IEnumerable<ExpansionField> Fields + { + get + { + return tokens; + } + } + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionClient.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionClient.cs new file mode 100644 index 0000000..f04d13c --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionClient.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Xml.Linq; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public interface IExpansionClient + { + IExpansionFunction GetExpansionFunction(XElement xmlFunctionNode, string fieldName); + void FormatSpan(SnapshotSpan span); + + void EndExpansion(); + + void OnBeforeInsertion(IExpansionSession session); + void OnAfterInsertion(IExpansionSession session); + + void PositionCaretForEditing(ITextView textView, SnapshotPoint point); + void OnItemChosen(string tittle, string path); + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionFunction.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionFunction.cs new file mode 100644 index 0000000..af945a5 --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionFunction.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public enum ExpansionFunctionType + { + List, + Value + }; + + public interface IExpansionFunction + { + void GetDefaultValue(out string value, out bool hasDefaultValue); + + void GetCurrentValue(out string value, out bool hasCurrentValue); + + bool FieldChanged(string fieldName); + + ExpansionFunctionType GetFunctionType(); + + int GetListCount(); + + string GetListText(int index); + + void ReleaseFunction(); + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionManager.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionManager.cs new file mode 100644 index 0000000..077b20b --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionManager.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public interface IExpansionManager + { + IEnumerable<ExpansionTemplate> EnumerateExpansions(IContentType contentType, bool shortcutOnly, string[] snippetTypes, bool includeNullType, bool includeDuplicates); + ExpansionTemplate GetTemplateByName(IExpansionClient expansionClient, IContentType contentType, string name, string filePath, ITextView textView, SnapshotSpan span, bool showDisambiguationUI); + ExpansionTemplate GetTemplateByShortcut(IExpansionClient expansionClient, string shortcut, IContentType contentType, ITextView textView, SnapshotSpan span, bool showDisambiguationUI); + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionService.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionService.cs new file mode 100644 index 0000000..193edf5 --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionService.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Threading; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public interface IExpansionService + { + IExpansionSession InsertExpansion(SnapshotSpan triggerSpan, IExpansionClient expansionClient, IContentType contentType, CancellationToken cancellationToken = default); + IExpansionSession InsertNamedExpansion(string title, string pszPath, SnapshotSpan triggerSpan, IExpansionClient expansionClient, IContentType contentType, bool showDisambiguationUI); + void InvokeInsertionUI(IExpansionClient expansionClient, IContentType contentType, string[] types, bool includeNullType, string[] kinds, bool includeNullKind, string prefixText, string completionChar); + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionServiceProvider.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionServiceProvider.cs new file mode 100644 index 0000000..cead20d --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionServiceProvider.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public interface IExpansionServiceProvider + { + IExpansionService GetExpansionService(ITextView textView); + } +} diff --git a/src/Editor/Language/Def/Intellisense/Snippet/IExpansionSession.cs b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionSession.cs new file mode 100644 index 0000000..9845f93 --- /dev/null +++ b/src/Editor/Language/Def/Intellisense/Snippet/IExpansionSession.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; +using System.Xml.Linq; + +namespace Microsoft.VisualStudio.Text.Editor.Expansion +{ + public interface IExpansionSession + { + void EndCurrentExpansion(bool leaveCaret); + bool GoToNextExpansionField(bool commitIfLast); + bool GoToPreviousExpansionField(); + string GetFieldValue(string fieldName); + void SetFieldDefault(string fieldName, string newValue); + SnapshotSpan GetFieldSpan(string fieldName); + XElement GetHeaderNode(); + XElement GetDeclarationNode(); + XElement GetSnippetNode(); + SnapshotSpan GetSnippetSpan(); + SnapshotSpan EndSpan { get; set; } + } +} |