diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea5459..dbd294a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Code Editor Package for Visual Studio +## [2.0.2] - 2020-05-27 + +Added support for solution folders. +Only bind the messenger when the VS editor is selected. +Warn when unable to create the messenger. +Fixed an initialization issue triggering legacy code generation. +Allow package source in assembly to be generated when referenced from asmref. + + ## [2.0.1] - 2020-03-19 When Visual Studio installation is compatible with C# 8.0, setup the language version to not prompt the user with unsupported constructs. (So far Unity only supports C# 7.3). diff --git a/Editor/ProjectGeneration/ProjectGeneration.cs b/Editor/ProjectGeneration/ProjectGeneration.cs index 6fa0782..18a625e 100644 --- a/Editor/ProjectGeneration/ProjectGeneration.cs +++ b/Editor/ProjectGeneration/ProjectGeneration.cs @@ -44,9 +44,7 @@ namespace Microsoft.Unity.VisualStudio.Editor const string k_WindowsNewline = "\r\n"; - string m_SolutionProjectEntryTemplate = string.Join("\r\n", - @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""", - @"EndProject").Replace(" ", "\t"); + string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject"; string m_SolutionProjectConfigurationTemplate = string.Join("\r\n", @" {{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", @@ -87,6 +85,8 @@ namespace Microsoft.Unity.VisualStudio.Editor m_AssemblyNameProvider = assemblyNameProvider; m_FileIOProvider = fileIoProvider; m_GUIDGenerator = guidGenerator; + + SetupProjectSupportedExtensions(); } /// @@ -412,7 +412,7 @@ namespace Microsoft.Unity.VisualStudio.Editor projectBuilder.Append(@" ").Append(k_WindowsNewline); foreach (string file in assembly.sourceFiles) { - if (!ShouldFileBePartOfSolution(file)) + if (!IsSupportedFile(file)) continue; var extension = Path.GetExtension(file).ToLower(); @@ -725,7 +725,7 @@ namespace Microsoft.Unity.VisualStudio.Editor const string vsversion = "15"; var relevantAssemblies = RelevantAssembliesForMode(assemblies); - var generatedProjects = ToProjectEntries(relevantAssemblies); + var generatedProjects = ToProjectEntries(relevantAssemblies).ToList(); SolutionProperties[] properties = null; @@ -737,7 +737,7 @@ namespace Microsoft.Unity.VisualStudio.Editor { // Add all projects that were previously in the solution and that are not generated by Unity, nor generated in the project root directory var externalProjects = previousSolution.Projects - .Where(p => !FileUtility.IsFileInProjectDirectory(p.FileName)) + .Where(p => p.IsSolutionFolderProjectFactory() || !FileUtility.IsFileInProjectDirectory(p.FileName)) .Where(p => generatedProjects.All(gp => gp.FileName != p.FileName)); projects.AddRange(externalProjects); @@ -746,7 +746,11 @@ namespace Microsoft.Unity.VisualStudio.Editor string propertiesText = GetPropertiesText(properties); string projectEntriesText = GetProjectEntriesText(projects); - string projectConfigurationsText = string.Join(k_WindowsNewline, projects.Select(p => GetProjectActiveConfigurations(p.ProjectGuid)).ToArray()); + + // do not generate configurations for SolutionFolders + var configurableProjects = projects.Where(p => !p.IsSolutionFolderProjectFactory()); + string projectConfigurationsText = string.Join(k_WindowsNewline, configurableProjects.Select(p => GetProjectActiveConfigurations(p.ProjectGuid)).ToArray()); + return string.Format(GetSolutionText(), fileversion, vsversion, projectEntriesText, projectConfigurationsText, propertiesText); } @@ -800,7 +804,7 @@ namespace Microsoft.Unity.VisualStudio.Editor { var projectEntries = entries.Select(entry => string.Format( m_SolutionProjectEntryTemplate, - entry.ProjectFactoryGuid, entry.Name, entry.FileName, entry.ProjectGuid + entry.ProjectFactoryGuid, entry.Name, entry.FileName, entry.ProjectGuid, entry.Metadata )); return string.Join(k_WindowsNewline, projectEntries.ToArray()); @@ -814,7 +818,8 @@ namespace Microsoft.Unity.VisualStudio.Editor ProjectFactoryGuid = SolutionGuid(assembly), Name = assembly.name, FileName = Path.GetFileName(ProjectFile(assembly)), - ProjectGuid = ProjectGuid(assembly) + ProjectGuid = ProjectGuid(assembly), + Metadata = k_WindowsNewline }; } diff --git a/Editor/SolutionParser.cs b/Editor/SolutionParser.cs index 891df12..81f7ab2 100644 --- a/Editor/SolutionParser.cs +++ b/Editor/SolutionParser.cs @@ -11,8 +11,8 @@ namespace Microsoft.Unity.VisualStudio.Editor internal static class SolutionParser { // Compared to the bridge implementation, we are not returning "{" "}" from Guids - private static readonly Regex ProjectDeclaration = new Regex(@"Project\(\""{(?.*?)}\""\)\s+=\s+\""(?.*?)\"",\s+\""(?.*?)\"",\s+\""{(?.*?)}\""(?.*?)\bEndProject\b", RegexOptions.Singleline | RegexOptions.ExplicitCapture); - private static readonly Regex PropertiesDeclaration = new Regex(@"GlobalSection\((?[\w]+Properties)\)\s+=\s+(?(?:post|pre)Solution)(?.*?)EndGlobalSection", RegexOptions.Singleline | RegexOptions.ExplicitCapture); + private static readonly Regex ProjectDeclaration = new Regex(@"Project\(\""{(?.*?)}\""\)\s+=\s+\""(?.*?)\"",\s+\""(?.*?)\"",\s+\""{(?.*?)}\""(?.*?)\bEndProject\b", RegexOptions.Singleline | RegexOptions.ExplicitCapture); + private static readonly Regex PropertiesDeclaration = new Regex(@"GlobalSection\((?([\w]+Properties|NestedProjects))\)\s+=\s+(?(?:post|pre)Solution)(?.*?)EndGlobalSection", RegexOptions.Singleline | RegexOptions.ExplicitCapture); private static readonly Regex PropertiesEntryDeclaration = new Regex(@"^\s*(?.*?)=(?.*?)$", RegexOptions.Multiline | RegexOptions.ExplicitCapture); public static Solution ParseSolutionFile(string filename, IFileIO fileIO) @@ -42,6 +42,7 @@ namespace Microsoft.Unity.VisualStudio.Editor Name = match.Groups["name"].Value, FileName = match.Groups["fileName"].Value, ProjectGuid = match.Groups["projectGuid"].Value, + Metadata = match.Groups["metadata"].Value }); } diff --git a/Editor/SolutionProjectEntry.cs b/Editor/SolutionProjectEntry.cs index 4319b94..8c78a53 100644 --- a/Editor/SolutionProjectEntry.cs +++ b/Editor/SolutionProjectEntry.cs @@ -2,6 +2,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.Unity.VisualStudio.Editor { internal class SolutionProjectEntry @@ -10,5 +12,11 @@ namespace Microsoft.Unity.VisualStudio.Editor public string Name { get; set; } public string FileName { get; set; } public string ProjectGuid { get; set; } + public string Metadata { get; set; } + + public bool IsSolutionFolderProjectFactory() + { + return ProjectFactoryGuid != null && ProjectFactoryGuid.Equals("2150E333-8FDC-42A3-9474-1A3956D46DE8", StringComparison.OrdinalIgnoreCase); + } } } diff --git a/Editor/VisualStudioEditor.cs b/Editor/VisualStudioEditor.cs index 3962da1..0032120 100644 --- a/Editor/VisualStudioEditor.cs +++ b/Editor/VisualStudioEditor.cs @@ -46,6 +46,14 @@ namespace Microsoft.Unity.VisualStudio.Editor CodeEditor.Register(new VisualStudioEditor()); } + internal static bool IsEnabled + { + get + { + return CodeEditor.CurrentEditor is VisualStudioEditor; + } + } + public void CreateIfDoesntExist() { if (!_generator.HasSolutionBeenGenerated()) diff --git a/Editor/VisualStudioIntegration.cs b/Editor/VisualStudioIntegration.cs index e1c8873..3bd0cfa 100644 --- a/Editor/VisualStudioIntegration.cs +++ b/Editor/VisualStudioIntegration.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Sockets; using Microsoft.Unity.VisualStudio.Editor.Messaging; using UnityEditor; using UnityEngine; @@ -21,14 +22,27 @@ namespace Microsoft.Unity.VisualStudio.Editor private static readonly Queue Incoming = new Queue(); private static readonly object IncomingLock = new object(); - public static Application.LogCallback LogCallback = delegate { }; - static VisualStudioIntegration() { + if (!VisualStudioEditor.IsEnabled) + return; + RunOnceOnUpdate(() => { - _messager = Messager.BindTo(MessagingPort()); - _messager.ReceiveMessage += ReceiveMessage; + // Despite using ReuseAddress|!ExclusiveAddressUse, we can fail here: + // - if another application is using this port with exclusive access + // - or if the firewall is not properly configured + var messagingPort = MessagingPort(); + + try { + _messager = Messager.BindTo(messagingPort); + _messager.ReceiveMessage += ReceiveMessage; + } + catch (SocketException) + { + // We'll have a chance to try to rebind on next domain reload + Debug.LogWarning($"Unable to use UDP port {messagingPort} for VS/Unity messaging. You should check if another process is already bound to this port or if your firewall settings are compatible."); + } RunOnShutdown(Shutdown); }); diff --git a/package.json b/package.json index 8735581..1b05135 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,19 @@ "name": "com.unity.ide.visualstudio", "displayName": "Visual Studio Editor", "description": "Code editor integration for supporting Visual Studio as code editor for unity. Adds support for generating csproj files for intellisense purposes, auto discovery of installations, etc.", - "version": "2.0.1", + "version": "2.0.2", "unity": "2020.1", "unityRelease": "0a12", "dependencies": {}, "relatedPackages": { - "com.unity.ide.visualstudio.tests": "2.0.1" + "com.unity.ide.visualstudio.tests": "2.0.2" + }, + "upmCi": { + "footprint": "07f6b10869c0df5a69cfdcba85bf56c904b6d15d" }, "repository": { - "footprint": "29b3412db92c0d78a94e0fdcaf3aa46387f7b415", - "type": "git", "url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.visualstudio.git", - "revision": "f8cace3617b9248d18f3a982b22fa3fb527e7b9b" + "type": "git", + "revision": "fe4c910c44c62de4bf224f458e3116184d414906" } }