vscode to cursor, disable vs

This commit is contained in:
whitetac
2024-03-13 10:19:04 +09:00
committed by YoungwoongLee
parent b28f5a3cbf
commit beaecf45f5
7 changed files with 14 additions and 617 deletions

View File

@@ -13,14 +13,6 @@ namespace Microsoft.Unity.VisualStudio.Editor
{
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
{
#if UNITY_EDITOR_WIN
foreach (var installation in VisualStudioForWindowsInstallation.GetVisualStudioInstallations())
yield return installation;
#elif UNITY_EDITOR_OSX
foreach (var installation in VisualStudioForMacInstallation.GetVisualStudioInstallations())
yield return installation;
#endif
foreach (var installation in VisualStudioCodeInstallation.GetVisualStudioInstallations())
yield return installation;
}
@@ -29,13 +21,6 @@ namespace Microsoft.Unity.VisualStudio.Editor
{
try
{
#if UNITY_EDITOR_WIN
if (VisualStudioForWindowsInstallation.TryDiscoverInstallation(editorPath, out installation))
return true;
#elif UNITY_EDITOR_OSX
if (VisualStudioForMacInstallation.TryDiscoverInstallation(editorPath, out installation))
return true;
#endif
if (VisualStudioCodeInstallation.TryDiscoverInstallation(editorPath, out installation))
return true;
}
@@ -49,11 +34,6 @@ namespace Microsoft.Unity.VisualStudio.Editor
public static void Initialize()
{
#if UNITY_EDITOR_WIN
VisualStudioForWindowsInstallation.Initialize();
#elif UNITY_EDITOR_OSX
VisualStudioForMacInstallation.Initialize();
#endif
VisualStudioCodeInstallation.Initialize();
}
}

View File

@@ -54,7 +54,8 @@ namespace Microsoft.Unity.VisualStudio.Editor
if (string.IsNullOrEmpty(vstuPath))
return Array.Empty<string>();
return GetAnalyzers(vstuPath); }
return GetAnalyzers(vstuPath);
}
public override IGenerator ProjectGenerator
{
@@ -132,7 +133,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
installation = new VisualStudioCodeInstallation()
{
IsPrerelease = isPrerelease,
Name = "Visual Studio Code" + (isPrerelease ? " - Insider" : string.Empty) + (version != null ? $" [{version.ToString(3)}]" : string.Empty),
Name = "Cursor" + (isPrerelease ? " - Insider" : string.Empty) + (version != null ? $" [{version.ToString(3)}]" : string.Empty),
Path = editorPath,
Version = version ?? new Version()
};
@@ -150,17 +151,16 @@ namespace Microsoft.Unity.VisualStudio.Editor
foreach (var basePath in new[] {localAppPath, programFiles})
{
candidates.Add(IOPath.Combine(basePath, "Microsoft VS Code", "Code.exe"));
candidates.Add(IOPath.Combine(basePath, "Microsoft VS Code Insiders", "Code - Insiders.exe"));
}
#elif UNITY_EDITOR_OSX
var appPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles));
candidates.AddRange(Directory.EnumerateDirectories(appPath, "Visual Studio Code*.app"));
candidates.AddRange(Directory.EnumerateDirectories(appPath, "Cursor*.app"));
#elif UNITY_EDITOR_LINUX
// Well known locations
candidates.Add("/usr/bin/code");
candidates.Add("/bin/code");
candidates.Add("/usr/local/bin/code");
candidates.Add("/usr/bin/cursor");
candidates.Add("/bin/cursor");
candidates.Add("/usr/local/bin/cursor");
// Preference ordered base directories relative to which desktop files should be searched
candidates.AddRange(GetXdgCandidates());
@@ -243,7 +243,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
}
catch (IOException)
{
}
}
}
private const string DefaultLaunchFileContent = @"{
@@ -440,7 +440,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
private const string MicrosoftUnityExtensionId = "visualstudiotoolsforunity.vstuc";
private const string DefaultRecommendedExtensionsContent = @"{
""recommendations"": [
"""+ MicrosoftUnityExtensionId + @"""
""" + MicrosoftUnityExtensionId + @"""
]
}
";
@@ -506,7 +506,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
var directory = IOPath.GetDirectoryName(solution);
var application = Path;
ProcessRunner.Start(string.IsNullOrEmpty(path) ?
ProcessRunner.Start(string.IsNullOrEmpty(path) ?
ProcessStartInfoFor(application, $"\"{directory}\"") :
ProcessStartInfoFor(application, $"\"{directory}\" -g \"{path}\":{line}:{column}"));

View File

@@ -1,181 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
#if UNITY_EDITOR_OSX
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Unity.CodeEditor;
using IOPath = System.IO.Path;
namespace Microsoft.Unity.VisualStudio.Editor
{
internal class VisualStudioForMacInstallation : VisualStudioInstallation
{
// C# language version support for Visual Studio for Mac
private static readonly VersionPair[] OSXVersionTable =
{
// VisualStudio for Mac 2022
new VersionPair(17,4, /* => */ 11,0),
new VersionPair(17,0, /* => */ 10,0),
// VisualStudio for Mac 8.x
new VersionPair(8,8, /* => */ 9,0),
new VersionPair(8,3, /* => */ 8,0),
new VersionPair(8,0, /* => */ 7,3),
};
private static readonly IGenerator _generator = new LegacyStyleProjectGeneration();
public override bool SupportsAnalyzers
{
get
{
return Version >= new Version(8, 3);
}
}
public override Version LatestLanguageVersionSupported
{
get
{
return GetLatestLanguageVersionSupported(OSXVersionTable);
}
}
private string GetExtensionPath()
{
const string addinName = "MonoDevelop.Unity";
const string addinAssembly = addinName + ".dll";
// user addins repository
var localAddins = IOPath.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
$"Library/Application Support/VisualStudio/${Version.Major}.0" + "/LocalInstall/Addins");
// In the user addins repository, the addins are suffixed by their versions, like `MonoDevelop.Unity.1.0`
// When installing another local user addin, MD will remove files inside the folder
// So we browse all VSTUM addins, and return the one with an addin assembly
if (Directory.Exists(localAddins))
{
foreach (var folder in Directory.GetDirectories(localAddins, addinName + "*", SearchOption.TopDirectoryOnly))
{
if (File.Exists(IOPath.Combine(folder, addinAssembly)))
return folder;
}
}
// Check in Visual Studio.app/
// In that case the name of the addin is used
var addinPath = IOPath.Combine(Path, $"Contents/Resources/lib/monodevelop/AddIns/{addinName}");
if (File.Exists(IOPath.Combine(addinPath, addinAssembly)))
return addinPath;
addinPath = IOPath.Combine(Path, $"Contents/MonoBundle/Addins/{addinName}");
if (File.Exists(IOPath.Combine(addinPath, addinAssembly)))
return addinPath;
return null;
}
public override string[] GetAnalyzers()
{
var vstuPath = GetExtensionPath();
if (string.IsNullOrEmpty(vstuPath))
return Array.Empty<string>();
return GetAnalyzers(vstuPath);
}
public override IGenerator ProjectGenerator
{
get
{
return _generator;
}
}
private static bool IsCandidateForDiscovery(string path)
{
return Directory.Exists(path) && Regex.IsMatch(path, "Visual\\s?Studio(?!.*Code.*).*.app$", RegexOptions.IgnoreCase);
}
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation)
{
installation = null;
if (string.IsNullOrEmpty(editorPath))
return false;
if (!IsCandidateForDiscovery(editorPath))
return false;
// On Mac we use the .app folder, so we need to access to main assembly
var fvi = IOPath.Combine(editorPath, "Contents/Resources/lib/monodevelop/bin/VisualStudio.exe");
if (!File.Exists(fvi))
fvi = IOPath.Combine(editorPath, "Contents/MonoBundle/VisualStudio.exe");
if (!File.Exists(fvi))
fvi = IOPath.Combine(editorPath, "Contents/MonoBundle/VisualStudio.dll");
if (!File.Exists(fvi))
return false;
// VS preview are not using the isPrerelease flag so far
// On Windows FileDescription contains "Preview", but not on Mac
var vi = FileVersionInfo.GetVersionInfo(fvi);
var version = new Version(vi.ProductVersion);
var isPrerelease = vi.IsPreRelease || string.Concat(editorPath, "/" + vi.FileDescription).ToLower().Contains("preview");
installation = new VisualStudioForMacInstallation()
{
IsPrerelease = isPrerelease,
Name = $"{vi.FileDescription}{(isPrerelease ? " Preview" : string.Empty)} [{version.ToString(3)}]",
Path = editorPath,
Version = version
};
return true;
}
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
{
var candidates = Directory.EnumerateDirectories("/Applications", "*.app");
foreach (var candidate in candidates)
{
if (TryDiscoverInstallation(candidate, out var installation))
yield return installation;
}
}
[DllImport("AppleEventIntegration")]
private static extern bool OpenVisualStudio(string appPath, string solutionPath, string filePath, int line);
public override void CreateExtraFiles(string projectDirectory)
{
}
public override bool Open(string path, int line, int column, string solution)
{
string absolutePath = "";
if (!string.IsNullOrWhiteSpace(path))
{
absolutePath = IOPath.GetFullPath(path);
}
return OpenVisualStudio(CodeEditor.CurrentEditorInstallation, solution, absolutePath, line);
}
public static void Initialize()
{
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2c64241ee5e302b478d7f2522bbaa4e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,380 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
#if UNITY_EDITOR_WIN
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using Unity.CodeEditor;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;
using IOPath = System.IO.Path;
namespace Microsoft.Unity.VisualStudio.Editor
{
internal class VisualStudioForWindowsInstallation : VisualStudioInstallation
{
// C# language version support for Visual Studio
private static readonly VersionPair[] WindowsVersionTable =
{
// VisualStudio 2022
new VersionPair(17,4, /* => */ 11,0),
new VersionPair(17,0, /* => */ 10,0),
// VisualStudio 2019
new VersionPair(16,8, /* => */ 9,0),
new VersionPair(16,0, /* => */ 8,0),
// VisualStudio 2017
new VersionPair(15,7, /* => */ 7,3),
new VersionPair(15,5, /* => */ 7,2),
new VersionPair(15,3, /* => */ 7,1),
new VersionPair(15,0, /* => */ 7,0),
};
private static string _vsWherePath = null;
private static readonly IGenerator _generator = new LegacyStyleProjectGeneration();
public override bool SupportsAnalyzers
{
get
{
return Version >= new Version(16, 3);
}
}
public override Version LatestLanguageVersionSupported
{
get
{
return GetLatestLanguageVersionSupported(WindowsVersionTable);
}
}
private static string ReadRegistry(RegistryKey hive, string keyName, string valueName)
{
try
{
var unitykey = hive.OpenSubKey(keyName);
var result = (string)unitykey?.GetValue(valueName);
return result;
}
catch (Exception)
{
return null;
}
}
private string GetWindowsBridgeFromRegistry()
{
var keyName = $"Software\\Microsoft\\Microsoft Visual Studio {Version.Major}.0 Tools for Unity";
const string valueName = "UnityExtensionPath";
var bridge = ReadRegistry(Registry.CurrentUser, keyName, valueName);
if (string.IsNullOrEmpty(bridge))
bridge = ReadRegistry(Registry.LocalMachine, keyName, valueName);
return bridge;
}
private string GetExtensionPath()
{
const string extensionName = "Visual Studio Tools for Unity";
const string extensionAssembly = "SyntaxTree.VisualStudio.Unity.dll";
var vsDirectory = IOPath.GetDirectoryName(Path);
var vstuDirectory = IOPath.Combine(vsDirectory, "Extensions", "Microsoft", extensionName);
if (File.Exists(IOPath.Combine(vstuDirectory, extensionAssembly)))
return vstuDirectory;
return null;
}
public override string[] GetAnalyzers()
{
var vstuPath = GetExtensionPath();
if (string.IsNullOrEmpty(vstuPath))
return Array.Empty<string>();
var analyzers = GetAnalyzers(vstuPath);
if (analyzers?.Length > 0)
return analyzers;
var bridge = GetWindowsBridgeFromRegistry();
if (File.Exists(bridge))
return GetAnalyzers(IOPath.Combine(IOPath.GetDirectoryName(bridge), ".."));
return Array.Empty<string>();
}
public override IGenerator ProjectGenerator
{
get
{
return _generator;
}
}
private static bool IsCandidateForDiscovery(string path)
{
return File.Exists(path) && Regex.IsMatch(path, "devenv.exe$", RegexOptions.IgnoreCase);
}
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation)
{
installation = null;
if (string.IsNullOrEmpty(editorPath))
return false;
if (!IsCandidateForDiscovery(editorPath))
return false;
// On windows we use the executable directly, so we can query extra information
if (!File.Exists(editorPath))
return false;
// VS preview are not using the isPrerelease flag so far
// On Windows FileDescription contains "Preview", but not on Mac
var vi = FileVersionInfo.GetVersionInfo(editorPath);
var version = new Version(vi.ProductVersion);
var isPrerelease = vi.IsPreRelease || string.Concat(editorPath, "/" + vi.FileDescription).ToLower().Contains("preview");
installation = new VisualStudioForWindowsInstallation()
{
IsPrerelease = isPrerelease,
Name = $"{FormatProductName(vi.FileDescription)} [{version.ToString(3)}]",
Path = editorPath,
Version = version
};
return true;
}
public static string FormatProductName(string productName)
{
if (string.IsNullOrEmpty(productName))
return string.Empty;
return productName.Replace("Microsoft ", string.Empty);
}
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
{
foreach (var installation in QueryVsWhere())
yield return installation;
}
#region VsWhere Json Schema
#pragma warning disable CS0649
[Serializable]
internal class VsWhereResult
{
public VsWhereEntry[] entries;
public static VsWhereResult FromJson(string json)
{
return JsonUtility.FromJson<VsWhereResult>("{ \"" + nameof(VsWhereResult.entries) + "\": " + json + " }");
}
public IEnumerable<VisualStudioInstallation> ToVisualStudioInstallations()
{
foreach (var entry in entries)
{
yield return new VisualStudioForWindowsInstallation
{
Name = $"{FormatProductName(entry.displayName)} [{entry.catalog.productDisplayVersion}]",
Path = entry.productPath,
IsPrerelease = entry.isPrerelease,
Version = Version.Parse(entry.catalog.buildVersion)
};
}
}
}
[Serializable]
internal class VsWhereEntry
{
public string displayName;
public bool isPrerelease;
public string productPath;
public VsWhereCatalog catalog;
}
[Serializable]
internal class VsWhereCatalog
{
public string productDisplayVersion; // non parseable like "16.3.0 Preview 3.0"
public string buildVersion;
}
#pragma warning restore CS3021
#endregion
private static IEnumerable<VisualStudioInstallation> QueryVsWhere()
{
var progpath = _vsWherePath;
if (string.IsNullOrWhiteSpace(progpath))
return Enumerable.Empty<VisualStudioInstallation>();
const string arguments = "-prerelease -format json";
// We've seen issues with json parsing in utf8 mode and with specific non-UTF code pages like 949 (Korea)
// So try with utf8 first, then fallback to non utf8 in case of an issue
// See https://github.com/microsoft/vswhere/issues/264
try
{
return QueryVsWhere(progpath, $"{arguments} -utf8");
}
catch
{
return QueryVsWhere(progpath, $"{arguments}");
}
}
private static IEnumerable<VisualStudioInstallation> QueryVsWhere(string progpath, string arguments)
{
var result = ProcessRunner.StartAndWaitForExit(progpath, arguments);
if (!result.Success)
throw new Exception($"Failure while running vswhere: {result.Error}");
// Do not catch any JsonException here, this will be handled by the caller
return VsWhereResult
.FromJson(result.Output)
.ToVisualStudioInstallations();
}
private enum COMIntegrationState
{
Running,
DisplayProgressBar,
ClearProgressBar,
Exited
}
public override void CreateExtraFiles(string projectDirectory)
{
// See https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/
// We create a .vsconfig file to make sure our ManagedGame workload is installed
try
{
var vsConfigFile = IOPath.Combine(projectDirectory.NormalizePathSeparators(), ".vsconfig");
if (File.Exists(vsConfigFile))
return;
const string content = @"{
""version"": ""1.0"",
""components"": [
""Microsoft.VisualStudio.Workload.ManagedGame""
]
}
";
File.WriteAllText(vsConfigFile, content);
}
catch (IOException)
{
}
}
public override bool Open(string path, int line, int column, string solution)
{
var progpath = FileUtility.GetPackageAssetFullPath("Editor", "COMIntegration", "Release", "COMIntegration.exe");
if (string.IsNullOrWhiteSpace(progpath))
return false;
string absolutePath = "";
if (!string.IsNullOrWhiteSpace(path))
{
absolutePath = IOPath.GetFullPath(path);
}
// We remove all invalid chars from the solution filename, but we cannot prevent the user from using a specific path for the Unity project
// So process the fullpath to make it compatible with VS
if (!string.IsNullOrWhiteSpace(solution))
{
solution = $"\"{solution}\"";
solution = solution.Replace("^", "^^");
}
var psi = ProcessRunner.ProcessStartInfoFor(progpath, $"\"{CodeEditor.CurrentEditorInstallation}\" {solution} \"{absolutePath}\" {line}");
psi.StandardOutputEncoding = System.Text.Encoding.Unicode;
psi.StandardErrorEncoding = System.Text.Encoding.Unicode;
// inter thread communication
var messages = new BlockingCollection<COMIntegrationState>();
var asyncStart = AsyncOperation<ProcessRunnerResult>.Run(
() => ProcessRunner.StartAndWaitForExit(psi, onOutputReceived: data => OnOutputReceived(data, messages)),
e => new ProcessRunnerResult {Success = false, Error = e.Message, Output = string.Empty},
() => messages.Add(COMIntegrationState.Exited)
);
MonitorCOMIntegration(messages);
var result = asyncStart.Result;
if (!result.Success && !string.IsNullOrWhiteSpace(result.Error))
Debug.LogError($"Error while starting Visual Studio: {result.Error}");
return result.Success;
}
private static void MonitorCOMIntegration(BlockingCollection<COMIntegrationState> messages)
{
var displayingProgress = false;
COMIntegrationState state;
do
{
state = messages.Take();
switch (state)
{
case COMIntegrationState.ClearProgressBar:
EditorUtility.ClearProgressBar();
displayingProgress = false;
break;
case COMIntegrationState.DisplayProgressBar:
EditorUtility.DisplayProgressBar("Opening Visual Studio", "Starting up Visual Studio, this might take some time.", .5f);
displayingProgress = true;
break;
}
} while (state != COMIntegrationState.Exited);
// Make sure the progress bar is properly cleared in case of COMIntegration failure
if (displayingProgress)
EditorUtility.ClearProgressBar();
}
private static readonly COMIntegrationState[] ProgressBarCommands = {COMIntegrationState.DisplayProgressBar, COMIntegrationState.ClearProgressBar};
private static void OnOutputReceived(string data, BlockingCollection<COMIntegrationState> messages)
{
if (data == null)
return;
foreach (var cmd in ProgressBarCommands)
{
if (data.IndexOf(cmd.ToString(), StringComparison.OrdinalIgnoreCase) >= 0)
messages.Add(cmd);
}
}
public static void Initialize()
{
_vsWherePath = FileUtility.GetPackageAssetFullPath("Editor", "VSWhere", "vswhere.exe");
}
}
}
#endif

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: be7ef402265a7a549b2e43c11d1a22c5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: