diff options
author | Aaron Bockover <abock@microsoft.com> | 2019-07-17 21:34:08 +0300 |
---|---|---|
committer | Aaron Bockover <abock@microsoft.com> | 2019-07-17 21:34:08 +0300 |
commit | 199f195723d8d43352ca5842e0d45d16786bd6f6 (patch) | |
tree | a81efe421bdfadfea08b4200a1d3219712199d6d | |
parent | 0b92a4dc241aa16bc33659e188f5b4325fc903cd (diff) |
Sync with vs-editor-core@0b543734
27 files changed, 940 insertions, 7 deletions
diff --git a/Directory.Build.props b/Directory.Build.props index 5f55836..c7c4cbb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -19,7 +19,7 @@ </PropertyGroup> <PropertyGroup> - <NuGetVersionRoslyn>3.2.0-beta4-19324-01</NuGetVersionRoslyn> + <NuGetVersionRoslyn>3.2.0-beta4-19359-03</NuGetVersionRoslyn> <NuGetVersionVSEditor Condition="$(NuGetVersionVSEditor) == ''">16.0.379-g4a55b0e4f2</NuGetVersionVSEditor> </PropertyGroup> diff --git a/src/Editor/Imaging/Def/Catalogs/LightBulbImageCatalog.cs b/src/Editor/Imaging/Def/Catalogs/LightBulbImageCatalog.cs new file mode 100644 index 0000000..09b0f47 --- /dev/null +++ b/src/Editor/Imaging/Def/Catalogs/LightBulbImageCatalog.cs @@ -0,0 +1,26 @@ +// +// 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 Microsoft.VisualStudio.Core.Imaging; + +namespace Microsoft.VisualStudio.Language.Intellisense +{ + public static class LightBulbImageCatalog + { + public static readonly Guid CatalogId = new Guid("f09c8ce2-d515-4226-a430-dec104c81f05"); + + public static object GetImage(this IImageService imageService, LightBulbImageId imageId, ImageTags imageTags = default) + => imageService.GetImage(new ImageDescription(new ImageId(CatalogId, (int)imageId), 16, imageTags)); + } + + public enum LightBulbImageId + { + OnlyActions = 1, + Fixes, + ErrorFixes, + } +} diff --git a/src/Editor/Imaging/Def/Catalogs/OverviewMarginCatalog.cs b/src/Editor/Imaging/Def/Catalogs/OverviewMarginCatalog.cs new file mode 100644 index 0000000..c177e17 --- /dev/null +++ b/src/Editor/Imaging/Def/Catalogs/OverviewMarginCatalog.cs @@ -0,0 +1,29 @@ +// +// 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 Microsoft.VisualStudio.Core.Imaging; + +namespace Microsoft.VisualStudio.Text.OverviewMargin +{ + public static class OverviewMarginCatalog + { + public static readonly Guid CatalogId = new Guid("47efec21-fd36-445d-99a4-238f66ab764c"); + + public static object GetImage(this IImageService imageService, OverviewMarginImageId imageId, ImageTags imageTags = default) + => imageService.GetImage(new ImageDescription(new ImageId(CatalogId, (int)imageId), 16, imageTags)); + } + + public enum OverviewMarginImageId + { + Busy = 1, + Ok, + Warning, + Error, + Suggestion, + Hide + } +} diff --git a/src/Editor/Imaging/Def/Catalogs/SignatureHelpImageCatalog.cs b/src/Editor/Imaging/Def/Catalogs/SignatureHelpImageCatalog.cs new file mode 100644 index 0000000..857b0fd --- /dev/null +++ b/src/Editor/Imaging/Def/Catalogs/SignatureHelpImageCatalog.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 Microsoft.VisualStudio.Core.Imaging; + +namespace Microsoft.VisualStudio.Language.Intellisense +{ + public static class SignatureHelpImageCatalog + { + public static readonly Guid CatalogId = new Guid("95fdedcb-dc13-48a8-8165-ed1fff877d9a"); + + public static object GetImage(this IImageService imageService, SignatureHelpImageId imageId) + => imageService.GetImage(new ImageDescription(new ImageId(CatalogId, (int)imageId), 16, ImageTags.Template)) as object; + } + + public enum SignatureHelpImageId + { + PreviousSignatureButton = 1, + NextSignatureButton + } +} diff --git a/src/Editor/Core/Def/IImageService.cs b/src/Editor/Imaging/Def/IImageService.cs index 9ae87a0..cecb445 100644 --- a/src/Editor/Core/Def/IImageService.cs +++ b/src/Editor/Imaging/Def/IImageService.cs @@ -2,6 +2,7 @@ // 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.Core.Imaging { public interface IImageService @@ -24,4 +25,4 @@ namespace Microsoft.VisualStudio.Core.Imaging ImageTags tags = ImageTags.None) => imageService.GetImage(new ImageDescription(id, size, tags)); } -}
\ No newline at end of file +} diff --git a/src/Editor/Core/Def/ImageDescription.cs b/src/Editor/Imaging/Def/ImageDescription.cs index 1ec4c7e..33f89b3 100644 --- a/src/Editor/Core/Def/ImageDescription.cs +++ b/src/Editor/Imaging/Def/ImageDescription.cs @@ -1,4 +1,9 @@ -using System; +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + +using System; namespace Microsoft.VisualStudio.Core.Imaging { @@ -66,4 +71,4 @@ namespace Microsoft.VisualStudio.Core.Imaging public static bool operator !=(ImageDescription left, ImageDescription right) => !(left == right); } -}
\ No newline at end of file +} diff --git a/src/Editor/Core/Def/ImageTags.cs b/src/Editor/Imaging/Def/ImageTags.cs index 814d7c1..6e2163d 100644 --- a/src/Editor/Core/Def/ImageTags.cs +++ b/src/Editor/Imaging/Def/ImageTags.cs @@ -1,3 +1,8 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// + using System; namespace Microsoft.VisualStudio.Core.Imaging @@ -14,4 +19,4 @@ namespace Microsoft.VisualStudio.Core.Imaging Selected = 1 << 5, Template = 1 << 6 } -}
\ No newline at end of file +} diff --git a/src/Editor/Imaging/Def/Imaging.csproj b/src/Editor/Imaging/Def/Imaging.csproj new file mode 100644 index 0000000..06606e4 --- /dev/null +++ b/src/Editor/Imaging/Def/Imaging.csproj @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <AssemblyName>Microsoft.VisualStudio.Editor.Imaging</AssemblyName> + <RootNamespace>Microsoft.VisualStudio.Imaging</RootNamespace> + <PushToPublicFeed>true</PushToPublicFeed> + <NoWarn>649;436;$(NoWarn)</NoWarn> + <AssemblyAttributeClsCompliant>true</AssemblyAttributeClsCompliant> + <LocalizationEnabled>false</LocalizationEnabled> + <InsertNuget>true</InsertNuget> + <IncludeInOptProf>true</IncludeInOptProf> + <TargetFramework>$(TargetFramework)</TargetFramework> + </PropertyGroup> + <ItemGroup> + <ProjectReference Include="..\..\Core\Def\CoreUtility.csproj" /> + </ItemGroup> +</Project> 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; } + } +} diff --git a/src/Editor/Language/Def/Language/AssemblyInfo.cs b/src/Editor/Language/Def/Language/AssemblyInfo.cs index cb9fc3b..b9002d7 100644 --- a/src/Editor/Language/Def/Language/AssemblyInfo.cs +++ b/src/Editor/Language/Def/Language/AssemblyInfo.cs @@ -18,6 +18,7 @@ using System.Security.Permissions; [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Implementation, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.CodeLens.Service, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] // InternalsVisibleTo for VS for Mac implementation assembly: [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.Implementation, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e57febc1f220077550a65e338d3d15d7cbd189cf4f62f7c3829dcb2f8441a6c40631d172e3deb4dc0bb7237b44ec9daeb9bd7d72c3d64c4f52b968795443cb58bc341583c29440345b8c35f72f6a31aecb2903376136f8fc35779bb422eb643f8668fa6605c697bff927e3bb10745328ff878bd1b7e42bbcb839f04baa8460bd")] diff --git a/src/Editor/Language/Util/LanguageUtil/AssemblyInfo.cs b/src/Editor/Language/Util/LanguageUtil/AssemblyInfo.cs index 2f4ea70..3821eb8 100644 --- a/src/Editor/Language/Util/LanguageUtil/AssemblyInfo.cs +++ b/src/Editor/Language/Util/LanguageUtil/AssemblyInfo.cs @@ -11,6 +11,7 @@ using System.Runtime.ConstrainedExecution; [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Language.Intellisense.UnitTestHelper, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Language.Intellisense.UnitTests, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information diff --git a/src/Editor/Text/Def/TextUI/AssemblyInfo.cs b/src/Editor/Text/Def/TextUI/AssemblyInfo.cs index f26bbe9..e404e66 100644 --- a/src/Editor/Text/Def/TextUI/AssemblyInfo.cs +++ b/src/Editor/Text/Def/TextUI/AssemblyInfo.cs @@ -15,13 +15,14 @@ using System.Security.Permissions; [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Commanding.Implementation, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Commanding.Implementation.UnitTests, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.UI.Utilities, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] // InternalsVisibleTo for VS for Mac implementation assembly: [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.Implementation, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e57febc1f220077550a65e338d3d15d7cbd189cf4f62f7c3829dcb2f8441a6c40631d172e3deb4dc0bb7237b44ec9daeb9bd7d72c3d64c4f52b968795443cb58bc341583c29440345b8c35f72f6a31aecb2903376136f8fc35779bb422eb643f8668fa6605c697bff927e3bb10745328ff878bd1b7e42bbcb839f04baa8460bd")] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] // -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. // diff --git a/src/Editor/Text/Def/TextUICocoa/AssemblyInfo.cs b/src/Editor/Text/Def/TextUICocoa/AssemblyInfo.cs index e65861e..15fc302 100644 --- a/src/Editor/Text/Def/TextUICocoa/AssemblyInfo.cs +++ b/src/Editor/Text/Def/TextUICocoa/AssemblyInfo.cs @@ -7,4 +7,5 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)]
\ No newline at end of file +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] diff --git a/src/Editor/Text/Def/TextUICocoa/Classification/ClassificationExtensions.cs b/src/Editor/Text/Def/TextUICocoa/Classification/ClassificationExtensions.cs new file mode 100644 index 0000000..78ce7a2 --- /dev/null +++ b/src/Editor/Text/Def/TextUICocoa/Classification/ClassificationExtensions.cs @@ -0,0 +1,99 @@ +// +// 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.Windows; + +using AppKit; + +namespace Microsoft.VisualStudio.Text.Classification +{ + using static ClassificationFormatDefinition; + + public static class ClassificationExtensions + { + internal const string FontRenderingScaleId = "FontRenderingScale"; + + public static void UpdateFont( + this ResourceDictionary resourceDictionary, + NSFont font) + { + if (font == null) + throw new ArgumentNullException(nameof(font)); + + resourceDictionary[TypefaceId] = font.FontDescriptor.FontDescriptorWithSize(0); + resourceDictionary[FontRenderingSizeId] = (double)font.PointSize; + } + + public static NSFont GetFont( + this ResourceDictionary resourceDictionary, + bool respectScale = true) + { + NSFontDescriptor fontDescriptor = null; + nfloat fontSize = 0; + + switch (resourceDictionary[TypefaceId]) + { + case NSFontDescriptor fd: + fontDescriptor = fd; + break; + case NSFont rdFont: + fontDescriptor = rdFont.FontDescriptor; + fontSize = rdFont.PointSize; + break; + case string fontName: + fontDescriptor = NSFontWorkarounds + .FromFontName(fontName, 0) + .FontDescriptor; + break; + } + + switch (resourceDictionary[FontRenderingSizeId]) + { + case double d: + fontSize = (nfloat)d; + break; + case float f: + fontSize = f; + break; + case nfloat nf: + fontSize = nf; + break; + case int i: + fontSize = i; + break; + } + + if (fontSize <= 0) + fontSize = NSFont.SystemFontSize; + + if (respectScale && resourceDictionary[FontRenderingScaleId] is double scale) + fontSize *= (nfloat)scale; + + var font = fontDescriptor == null + ? NSFontWorkarounds.UserFixedPitchFontOfSize(fontSize) + : NSFontWorkarounds.FromDescriptor(fontDescriptor, fontSize); + + NSFontTraitMask convertFontTraits = 0; + + if (resourceDictionary.Contains(IsBoldId) && + resourceDictionary[IsBoldId] is bool isBold && + isBold) + convertFontTraits |= NSFontTraitMask.Bold; + + if (resourceDictionary.Contains(IsItalicId) && + resourceDictionary[IsItalicId] is bool isItalic && + isItalic) + convertFontTraits |= NSFontTraitMask.Italic; + + if (convertFontTraits != 0) + font = NSFontManager.SharedFontManager.ConvertFontWorkaround( + font, + convertFontTraits); + + return font; + } + } +}
\ No newline at end of file diff --git a/src/Editor/Text/Def/TextUICocoa/Editor/ICocoaTextViewExtensions.cs b/src/Editor/Text/Def/TextUICocoa/Editor/ICocoaTextViewExtensions.cs new file mode 100644 index 0000000..3f0d46c --- /dev/null +++ b/src/Editor/Text/Def/TextUICocoa/Editor/ICocoaTextViewExtensions.cs @@ -0,0 +1,64 @@ +// +// 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.Linq; + +using AppKit; +using CoreGraphics; + +using Microsoft.VisualStudio.Text.Formatting; + +namespace Microsoft.VisualStudio.Text.Editor +{ + public static class ICocoaTextViewExtensions + { + public static CGPoint GetViewRelativeMousePosition(this ICocoaTextView textView, NSEvent theEvent) + => textView.VisualElement.ConvertPointFromView(theEvent.LocationInWindow, null); + + public static void MoveCaretToPosition(this ICocoaTextView textView, NSEvent theEvent) + { + var mousePosition = GetViewRelativeMousePosition(textView, theEvent); + + mousePosition.X += (nfloat)textView.ViewportLeft; + mousePosition.Y += (nfloat)textView.ViewportTop; + + // Set the caret at the closest mouse location (if there is no selection surrounding the clicked location) + ITextViewLine textViewLine = textView.TextViewLines.GetTextViewLineContainingYCoordinate(mousePosition.Y); + if (textViewLine != null) + { + VirtualSnapshotPoint clickedBufferPosition = textViewLine.GetInsertionBufferPositionFromXCoordinate(mousePosition.X); + + // What we're trying to determine is: if the caret were to be placed by this + // click, would it still be inside the current selection? + + bool insideSelection; + + // If neither virtual space is enabled nor the selection mode is box, check the non-virtual buffer point + if (!(textView.Options.GetOptionValue(DefaultTextViewOptions.UseVirtualSpaceId) || (textView.Selection.Mode == TextSelectionMode.Box))) + { + SnapshotPoint nonVirtualPoint = clickedBufferPosition.Position; + insideSelection = textView.Selection.SelectedSpans.Any(selectionSpan => selectionSpan.Contains(nonVirtualPoint)); + } + else + { + insideSelection = textView.Selection.VirtualSelectedSpans.Any(selectionSpan => selectionSpan.Contains(clickedBufferPosition)); + } + + // If this is outside of the selection, move the caret. + if (!insideSelection) + { + textView.Caret.MoveTo(textViewLine, mousePosition.X); + textView.Selection.Clear(); + textView.Caret.EnsureVisible(); + } + } + else + { + textView.Caret.MoveTo(new SnapshotPoint(textView.TextSnapshot, textView.TextSnapshot.Length)); + } + } + } +} diff --git a/src/Editor/Text/Def/TextUICocoa/NSFontExtensions.cs b/src/Editor/Text/Def/TextUICocoa/NSFontExtensions.cs new file mode 100644 index 0000000..98489e9 --- /dev/null +++ b/src/Editor/Text/Def/TextUICocoa/NSFontExtensions.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Runtime.InteropServices; + +using Foundation; +using ObjCRuntime; + +namespace AppKit +{ + public static class NSFontWorkarounds + { + [DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + static extern IntPtr IntPtr_objc_msgSend_IntPtr_nfloat(IntPtr receiver, IntPtr selector, IntPtr arg1, nfloat arg2); + + [DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + static extern IntPtr IntPtr_objc_msgSend_IntPtr_nuint_nint_nfloat(IntPtr receiver, IntPtr selector, IntPtr arg1, nuint arg2, nint arg3, nfloat arg4); + + [DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + static extern IntPtr IntPtr_objc_msgSend_nfloat(IntPtr receiver, IntPtr selector, nfloat arg1); + + [DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + static extern IntPtr IntPtr_objc_msgSend_IntPtr_nuint(IntPtr receiver, IntPtr selector, IntPtr arg1, nuint arg2); + + [DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + static extern bool bool_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1); + + static readonly IntPtr sel_respondsToSelector_ = Selector.GetHandle("respondsToSelector:"); + + static bool RespondsToSelector(IntPtr receiver, IntPtr selector) + => bool_objc_msgSend_IntPtr(receiver, sel_respondsToSelector_, selector); + + static readonly IntPtr classPtrNSFont = Class.GetHandle("NSFont"); + + static readonly IntPtr selFontWithName_Size = Selector.GetHandle("fontWithName:size:"); + + /// <summary> + /// Workaround for https://github.com/xamarin/xamarin-macios/pull/5423 + /// </summary> + public static NSFont FromFontName(string fontName, nfloat fontSize) + { + var fontNamePtr = NSString.CreateNative(fontName); + + try + { + return WrappedNSFont.Wrap(IntPtr_objc_msgSend_IntPtr_nfloat( + classPtrNSFont, + selFontWithName_Size, + fontNamePtr, + fontSize)); + } + finally + { + NSString.ReleaseNative(fontNamePtr); + } + } + + static readonly IntPtr selUserFixedPitchFontOfSize = Selector.GetHandle("userFixedPitchFontOfSize:"); + + public static NSFont UserFixedPitchFontOfSize(nfloat fontSize) + => WrappedNSFont.Wrap(IntPtr_objc_msgSend_nfloat( + classPtrNSFont, + selUserFixedPitchFontOfSize, + fontSize)); + + static readonly IntPtr selUserFontOfSize = Selector.GetHandle("userFontOfSize:"); + + public static NSFont UserFontOfSize(nfloat fontSize) + => WrappedNSFont.Wrap(IntPtr_objc_msgSend_nfloat( + classPtrNSFont, + selUserFontOfSize, + fontSize)); + + static readonly IntPtr sel_systemFontOfSize_ = Selector.GetHandle("systemFontOfSize:"); + + public static NSFont SystemFontOfSize(nfloat fontSize) + => WrappedNSFont.Wrap(IntPtr_objc_msgSend_nfloat( + classPtrNSFont, + sel_systemFontOfSize_, + fontSize)); + + static readonly IntPtr sel__lightSystemFontOfSize_ = Selector.GetHandle("_lightSystemFontOfSize:"); + static readonly IntPtr sel_lightSystemFontOfSize_ = Selector.GetHandle("lightSystemFontOfSize:"); + + public static NSFont LightSystemFontOfSize(nfloat fontSize) + { + IntPtr selectorHandle; + + if (RespondsToSelector(classPtrNSFont, sel__lightSystemFontOfSize_)) + // _lightSystemFontOfSize: is AppKit internal as of 10.14 but is used by Spotlight and Xcode + selectorHandle = sel__lightSystemFontOfSize_; + else if (RespondsToSelector(classPtrNSFont, sel_lightSystemFontOfSize_)) + // lightSystemFontOfSize: does not exist, but may in a future macOS... try it next + selectorHandle = sel_lightSystemFontOfSize_; + else + // systemFontOfSize: has always existed, fall back to it + selectorHandle = sel_systemFontOfSize_; + + return WrappedNSFont.Wrap(IntPtr_objc_msgSend_nfloat( + classPtrNSFont, + selectorHandle, + fontSize)); + } + + static readonly IntPtr selToolTipsFontOfSize = Selector.GetHandle("toolTipsFontOfSize:"); + + public static NSFont ToolTipsFontOfSize(nfloat fontSize) + => WrappedNSFont.Wrap(IntPtr_objc_msgSend_nfloat( + classPtrNSFont, + selToolTipsFontOfSize, + fontSize)); + + static readonly IntPtr selFontWithDescriptor_Size = Selector.GetHandle("fontWithDescriptor:size:"); + + public static NSFont FromDescriptor(NSFontDescriptor fontDescriptor, nfloat fontSize) + => WrappedNSFont.Wrap(IntPtr_objc_msgSend_IntPtr_nfloat( + classPtrNSFont, + selFontWithDescriptor_Size, + (fontDescriptor ?? throw new ArgumentNullException(nameof(fontDescriptor))).Handle, + fontSize)); + + static readonly IntPtr selFontWithFamily_traits_weight_size_ = Selector.GetHandle("fontWithFamily:traits:weight:size:"); + + public static NSFont FontWithFamilyWorkaround( + this NSFontManager fontManager, + string family, + NSFontTraitMask traits, + nint weight, + nfloat size) + { + if (family == null) + throw new ArgumentNullException(nameof(family)); + + var familyPtr = NSString.CreateNative(family); + try + { + return WrappedNSFont.Wrap(IntPtr_objc_msgSend_IntPtr_nuint_nint_nfloat( + fontManager.Handle, + selFontWithFamily_traits_weight_size_, + familyPtr, + (nuint)(ulong)traits, + weight, + size)); + } finally + { + NSString.ReleaseNative(familyPtr); + } + } + + static readonly IntPtr selConvertFont_toHaveTrait_ = Selector.GetHandle("convertFont:toHaveTrait:"); + + public static NSFont ConvertFontWorkaround( + this NSFontManager fontManager, + NSFont font, + NSFontTraitMask trait) + { + if (font == null) + throw new ArgumentNullException(nameof(font)); + + return WrappedNSFont.Wrap( + IntPtr_objc_msgSend_IntPtr_nuint( + fontManager.Handle, + selConvertFont_toHaveTrait_, + font.Handle, + (nuint)(ulong)trait)); + } + + sealed class WrappedNSFont : NSFont + { + public static NSFont Wrap(IntPtr handle) + => handle == IntPtr.Zero ? null : new WrappedNSFont(handle); + + WrappedNSFont(IntPtr handle) : base(handle) + { + } + } + } +}
\ No newline at end of file diff --git a/src/Editor/Text/Def/TextUICocoa/TextUICocoa.csproj b/src/Editor/Text/Def/TextUICocoa/TextUICocoa.csproj index a93e997..920cc6b 100644 --- a/src/Editor/Text/Def/TextUICocoa/TextUICocoa.csproj +++ b/src/Editor/Text/Def/TextUICocoa/TextUICocoa.csproj @@ -4,8 +4,12 @@ <TargetFramework>$(TargetFramework)</TargetFramework> </PropertyGroup> <ItemGroup> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include="..\TextData\TextData.csproj" /> <ProjectReference Include="..\TextUI\TextUI.csproj" /> + <ProjectReference Include="..\TextUIWpf\TextUIWpf.csproj" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.VisualStudio.Composition" /> diff --git a/src/Editor/Text/Util/TextDataUtil/AssemblyInfo.cs b/src/Editor/Text/Util/TextDataUtil/AssemblyInfo.cs index ea93b49..ccc6bf1 100644 --- a/src/Editor/Text/Util/TextDataUtil/AssemblyInfo.cs +++ b/src/Editor/Text/Util/TextDataUtil/AssemblyInfo.cs @@ -72,6 +72,7 @@ using System.Runtime.ConstrainedExecution; [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Commanding.Implementation.UnitTests, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.MultiSelection.Implementation.UI.UnitTests, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] // // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information diff --git a/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs b/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs index 4567dde..c5cbe95 100644 --- a/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs +++ b/src/Editor/Text/Util/TextUIUtil/AssemblyInfo.cs @@ -30,6 +30,7 @@ using System.Security.Permissions; [assembly: InternalsVisibleTo("Microsoft.VisualStudio.Text.Editor.PrintingService.Implementation, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("EditorTestApp, PublicKey=" + ThisAssembly.PublicKey)] [assembly: InternalsVisibleTo("Microsoft.VisualStudio.UI.Text.Cocoa.View.Implementation, PublicKey=" + ThisAssembly.PublicKey)] +[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Platform.VSEditor, PublicKey=" + ThisAssembly.PublicKey)] // // General Information about an assembly is controlled through the following |