You've already forked com.unity.ide.cursor
mirror of
https://github.com/boxqkrtm/com.unity.ide.cursor.git
synced 2026-05-14 14:20:09 +00:00
com.unity.ide.visualstudio@2.0.9
## [2.0.9] - 2021-05-04 Project generation: Added support for CLI. Integration: Improved performance when discovering Visual Studio installations. Warn when legacy assemblies are present in the project. Warn when the package version is not up-to-date.
This commit is contained in:
76
Editor/AsyncOperation.cs
Normal file
76
Editor/AsyncOperation.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Unity Technologies.
|
||||
* 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;
|
||||
|
||||
namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
internal class AsyncOperation<T>
|
||||
{
|
||||
private readonly Func<T> _producer;
|
||||
private readonly ManualResetEventSlim _resetEvent;
|
||||
|
||||
private T _result;
|
||||
private Exception _exception;
|
||||
|
||||
private AsyncOperation(Func<T> producer)
|
||||
{
|
||||
_producer = producer;
|
||||
_resetEvent = new ManualResetEventSlim(initialState: false);
|
||||
}
|
||||
|
||||
public static AsyncOperation<T> Run(Func<T> producer)
|
||||
{
|
||||
var task = new AsyncOperation<T>(producer);
|
||||
task.Run();
|
||||
return task;
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_result = _producer();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_exception = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_resetEvent.Set();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void CheckCompletion()
|
||||
{
|
||||
if (!_resetEvent.IsSet)
|
||||
_resetEvent.Wait();
|
||||
}
|
||||
|
||||
|
||||
public T Result
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckCompletion();
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
public Exception Exception
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckCompletion();
|
||||
return _exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Editor/AsyncOperation.cs.meta
Normal file
11
Editor/AsyncOperation.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6c8b2f6152bd1348ae35f9f95719f75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
88
Editor/Cli.cs
Normal file
88
Editor/Cli.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 Unity.CodeEditor;
|
||||
|
||||
namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
internal static class Cli
|
||||
{
|
||||
internal static void Log(string message)
|
||||
{
|
||||
// Use writeline here, instead of UnityEngine.Debug.Log to not include the stacktrace in the editor.log
|
||||
Console.WriteLine($"[VisualStudio.Editor.{nameof(Cli)}] {message}");
|
||||
}
|
||||
|
||||
internal static string GetInstallationDetails(IVisualStudioInstallation installation)
|
||||
{
|
||||
return $"{installation.ToCodeEditorInstallation().Name} Path:{installation.Path}, LanguageVersionSupport:{installation.LatestLanguageVersionSupported} AnalyzersSupport:{installation.SupportsAnalyzers}";
|
||||
}
|
||||
|
||||
internal static void GenerateSolutionWith(VisualStudioEditor vse, string installationPath)
|
||||
{
|
||||
if (vse != null && vse.TryGetVisualStudioInstallationForPath(installationPath, searchInstallations: true, out var vsi))
|
||||
{
|
||||
Log($"Using {GetInstallationDetails(vsi)}");
|
||||
vse.SyncAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"No Visual Studio installation found in ${installationPath}!");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void GenerateSolution()
|
||||
{
|
||||
if (CodeEditor.CurrentEditor is VisualStudioEditor vse)
|
||||
{
|
||||
Log($"Using default editor settings for Visual Studio installation");
|
||||
GenerateSolutionWith(vse, CodeEditor.CurrentEditorInstallation);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Visual Studio is not set as your default editor, looking for installations");
|
||||
try
|
||||
{
|
||||
var installations = Discovery
|
||||
.GetVisualStudioInstallations()
|
||||
.Cast<VisualStudioInstallation>()
|
||||
.OrderByDescending(vsi => !vsi.IsPrerelease)
|
||||
.ThenBy(vsi => vsi.Version)
|
||||
.ToArray();
|
||||
|
||||
foreach(var vsi in installations)
|
||||
{
|
||||
Log($"Detected {GetInstallationDetails(vsi)}");
|
||||
}
|
||||
|
||||
var installation = installations
|
||||
.FirstOrDefault();
|
||||
|
||||
if (installation != null)
|
||||
{
|
||||
var current = CodeEditor.CurrentEditorInstallation;
|
||||
try
|
||||
{
|
||||
CodeEditor.SetExternalScriptEditor(installation.Path);
|
||||
GenerateSolutionWith(CodeEditor.CurrentEditor as VisualStudioEditor, installation.Path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CodeEditor.SetExternalScriptEditor(current);
|
||||
}
|
||||
} else
|
||||
{
|
||||
Log($"No Visual Studio installation found!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Error detecting Visual Studio installations: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Editor/Cli.cs.meta
Normal file
11
Editor/Cli.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7b5530092b3a7646bdc7865f1f6ee94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,10 +6,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
@@ -17,6 +17,14 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
internal const string ManagedWorkload = "Microsoft.VisualStudio.Workload.ManagedGame";
|
||||
|
||||
internal static string _vsWherePath;
|
||||
|
||||
public static void FindVSWhere()
|
||||
{
|
||||
_vsWherePath = FileUtility
|
||||
.FindPackageAssetFullPath("VSWhere a:packages", "vswhere.exe")
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
|
||||
{
|
||||
@@ -37,7 +45,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCandidateToDiscovery(string path)
|
||||
private static bool IsCandidateForDiscovery(string path)
|
||||
{
|
||||
if (File.Exists(path) && VisualStudioEditor.IsWindows && Regex.IsMatch(path, "devenv.exe$", RegexOptions.IgnoreCase))
|
||||
return true;
|
||||
@@ -55,7 +63,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
if (string.IsNullOrEmpty(editorPath))
|
||||
return false;
|
||||
|
||||
if (!IsCandidateToDiscovery(editorPath))
|
||||
if (!IsCandidateForDiscovery(editorPath))
|
||||
return false;
|
||||
|
||||
// On windows we use the executable directly, so we can query extra information
|
||||
@@ -131,9 +139,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
|
||||
private static IEnumerable<VisualStudioInstallation> QueryVsWhere()
|
||||
{
|
||||
var progpath = FileUtility
|
||||
.FindPackageAssetFullPath("VSWhere a:packages", "vswhere.exe")
|
||||
.FirstOrDefault();
|
||||
var progpath = _vsWherePath;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(progpath))
|
||||
return Enumerable.Empty<VisualStudioInstallation>();
|
||||
|
||||
14
Editor/KnownAssemblies.cs
Normal file
14
Editor/KnownAssemblies.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
internal static class KnownAssemblies
|
||||
{
|
||||
public const string Bridge = "SyntaxTree.VisualStudio.Unity.Bridge";
|
||||
public const string Messaging = "SyntaxTree.VisualStudio.Unity.Messaging";
|
||||
public const string UnityVS = "UnityVS.VersionSpecific";
|
||||
}
|
||||
}
|
||||
11
Editor/KnownAssemblies.cs.meta
Normal file
11
Editor/KnownAssemblies.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbccb6292dce08a489e6e742243154e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>19H2</string>
|
||||
<string>19H1030</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
@@ -27,19 +27,19 @@
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>12A7300</string>
|
||||
<string>12D4e</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>macosx</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>10.15.6</string>
|
||||
<string>11.1</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>19G68</string>
|
||||
<string>20C63</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx10.15</string>
|
||||
<string>macosx11.1</string>
|
||||
<key>DTXcode</key>
|
||||
<string>1201</string>
|
||||
<string>1240</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>12A7300</string>
|
||||
<string>12D4e</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
Binary file not shown.
@@ -148,7 +148,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
private void RefreshCurrentInstallation()
|
||||
{
|
||||
var editor = CodeEditor.CurrentEditor as VisualStudioEditor;
|
||||
editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, out m_CurrentInstallation);
|
||||
editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, searchInstallations: true, out m_CurrentInstallation);
|
||||
}
|
||||
|
||||
public void Sync()
|
||||
@@ -370,7 +370,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
return TypeCache
|
||||
.GetTypesDerivedFrom<AssetPostprocessor>()
|
||||
.Where(t => t.Assembly.GetName().Name != "SyntaxTree.VisualStudio.Unity.Bridge") // never call into the bridge if loaded with the package
|
||||
.Where(t => t.Assembly.GetName().Name != KnownAssemblies.Bridge) // never call into the bridge if loaded with the package
|
||||
.Select(t => t.GetMethod(name, SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static))
|
||||
.Where(m => m != null);
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Unity.CodeEditor;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.VisualStudio.EditorTests")]
|
||||
[assembly: InternalsVisibleTo("Unity.VisualStudio.Standalone.EditorTests")]
|
||||
@@ -22,42 +22,44 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
[InitializeOnLoad]
|
||||
public class VisualStudioEditor : IExternalCodeEditor
|
||||
{
|
||||
private static readonly IVisualStudioInstallation[] _installations;
|
||||
|
||||
internal static bool IsOSX => Application.platform == RuntimePlatform.OSXEditor;
|
||||
internal static bool IsWindows => !IsOSX && Path.DirectorySeparatorChar == FileUtility.WinSeparator && Environment.NewLine == "\r\n";
|
||||
|
||||
CodeEditor.Installation[] IExternalCodeEditor.Installations => _installations
|
||||
CodeEditor.Installation[] IExternalCodeEditor.Installations => _discoverInstallations.Result
|
||||
.Select(i => i.ToCodeEditorInstallation())
|
||||
.ToArray();
|
||||
|
||||
private static readonly AsyncOperation<IVisualStudioInstallation[]> _discoverInstallations;
|
||||
|
||||
private readonly IGenerator _generator = new ProjectGeneration();
|
||||
|
||||
static VisualStudioEditor()
|
||||
{
|
||||
if (IsWindows)
|
||||
Discovery.FindVSWhere();
|
||||
|
||||
CodeEditor.Register(new VisualStudioEditor());
|
||||
|
||||
_discoverInstallations = AsyncOperation<IVisualStudioInstallation[]>.Run(DiscoverInstallations);
|
||||
}
|
||||
|
||||
private static IVisualStudioInstallation[] DiscoverInstallations()
|
||||
{
|
||||
try
|
||||
{
|
||||
_installations = Discovery
|
||||
return Discovery
|
||||
.GetVisualStudioInstallations()
|
||||
.ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"Error detecting Visual Studio installations: {ex}");
|
||||
_installations = Array.Empty<VisualStudioInstallation>();
|
||||
}
|
||||
|
||||
CodeEditor.Register(new VisualStudioEditor());
|
||||
}
|
||||
|
||||
internal static bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return CodeEditor.CurrentEditor is VisualStudioEditor;
|
||||
return Array.Empty<VisualStudioInstallation>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsEnabled => CodeEditor.CurrentEditor is VisualStudioEditor;
|
||||
|
||||
public void CreateIfDoesntExist()
|
||||
{
|
||||
if (!_generator.HasSolutionBeenGenerated())
|
||||
@@ -68,16 +70,19 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
{
|
||||
}
|
||||
|
||||
internal virtual bool TryGetVisualStudioInstallationForPath(string editorPath, out IVisualStudioInstallation installation)
|
||||
internal virtual bool TryGetVisualStudioInstallationForPath(string editorPath, bool searchInstallations, out IVisualStudioInstallation installation)
|
||||
{
|
||||
// lookup for well known installations
|
||||
foreach (var candidate in _installations)
|
||||
if (searchInstallations)
|
||||
{
|
||||
if (!string.Equals(Path.GetFullPath(editorPath), Path.GetFullPath(candidate.Path), StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
// lookup for well known installations
|
||||
foreach (var candidate in _discoverInstallations.Result)
|
||||
{
|
||||
if (!string.Equals(Path.GetFullPath(editorPath), Path.GetFullPath(candidate.Path), StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
installation = candidate;
|
||||
return true;
|
||||
installation = candidate;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Discovery.TryDiscoverInstallation(editorPath, out installation);
|
||||
@@ -85,7 +90,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
|
||||
public virtual bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation)
|
||||
{
|
||||
var result = TryGetVisualStudioInstallationForPath(editorPath, out var vsi);
|
||||
var result = TryGetVisualStudioInstallationForPath(editorPath, searchInstallations: false, out var vsi);
|
||||
installation = vsi == null ? default : vsi.ToCodeEditorInstallation();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ using System.Net.Sockets;
|
||||
using Microsoft.Unity.VisualStudio.Editor.Messaging;
|
||||
using Microsoft.Unity.VisualStudio.Editor.Testing;
|
||||
using UnityEditor;
|
||||
using UnityEditor.PackageManager;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
using UnityEngine;
|
||||
using MessageType = Microsoft.Unity.VisualStudio.Editor.Messaging.MessageType;
|
||||
|
||||
@@ -32,11 +34,15 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
private static readonly object _incomingLock = new object();
|
||||
private static readonly object _clientsLock = new object();
|
||||
|
||||
private static ListRequest _listRequest;
|
||||
|
||||
static VisualStudioIntegration()
|
||||
{
|
||||
if (!VisualStudioEditor.IsEnabled)
|
||||
return;
|
||||
|
||||
_listRequest = UnityEditor.PackageManager.Client.List();
|
||||
|
||||
RunOnceOnUpdate(() =>
|
||||
{
|
||||
// Despite using ReuseAddress|!ExclusiveAddressUse, we can fail here:
|
||||
@@ -59,6 +65,35 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
});
|
||||
|
||||
EditorApplication.update += OnUpdate;
|
||||
|
||||
CheckLegacyAssemblies();
|
||||
}
|
||||
|
||||
private static void CheckLegacyAssemblies()
|
||||
{
|
||||
var checkList = new HashSet<string>(new[] { KnownAssemblies.UnityVS, KnownAssemblies.Messaging, KnownAssemblies.Bridge });
|
||||
|
||||
try
|
||||
{
|
||||
var assemblies = AppDomain
|
||||
.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.Where(a => checkList.Contains(a.GetName().Name));
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
// for now we only want to warn against local assemblies, do not check externals.
|
||||
var relativePath = FileUtility.MakeRelativeToProjectPath(assembly.Location);
|
||||
if (relativePath == null)
|
||||
continue;
|
||||
|
||||
Debug.LogWarning($"Project contains legacy assembly that could interfere with the Visual Studio Package. You should delete {relativePath}");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// abandon legacy check
|
||||
}
|
||||
}
|
||||
|
||||
private static void RunOnceOnUpdate(Action action)
|
||||
@@ -98,8 +133,33 @@ namespace Microsoft.Unity.VisualStudio.Editor
|
||||
OnMessage(args.Message);
|
||||
}
|
||||
|
||||
private static void HandleListRequestCompletion()
|
||||
{
|
||||
const string packageName = "com.unity.ide.visualstudio";
|
||||
|
||||
if (_listRequest.Status == StatusCode.Success)
|
||||
{
|
||||
var package = _listRequest.Result.FirstOrDefault(p => p.name == packageName);
|
||||
|
||||
if (package != null
|
||||
&& Version.TryParse(package.version, out var packageVersion)
|
||||
&& Version.TryParse(package.versions.latest, out var latestVersion)
|
||||
&& packageVersion < latestVersion)
|
||||
{
|
||||
Debug.LogWarning($"Visual Studio Editor Package version {package.versions.latest} is available, we strongly encourage you to update from the Unity Package Manager for a better Visual Studio integration");
|
||||
}
|
||||
}
|
||||
|
||||
_listRequest = null;
|
||||
}
|
||||
|
||||
private static void OnUpdate()
|
||||
{
|
||||
if (_listRequest != null && _listRequest.IsCompleted)
|
||||
{
|
||||
HandleListRequestCompletion();
|
||||
}
|
||||
|
||||
lock (_incomingLock)
|
||||
{
|
||||
while (_incoming.Count > 0)
|
||||
|
||||
Reference in New Issue
Block a user