File size: 6,386 Bytes
18a519f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /*---------------------------------------------------------------------------------------------
* 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.IO;
using Microsoft.Win32;
using Unity.CodeEditor;
using IOPath = System.IO.Path;
namespace Microsoft.Unity.VisualStudio.Editor
{
internal interface IVisualStudioInstallation
{
string Path { get; }
bool SupportsAnalyzers { get; }
Version LatestLanguageVersionSupported { get; }
string[] GetAnalyzers();
CodeEditor.Installation ToCodeEditorInstallation();
}
internal class VisualStudioInstallation : IVisualStudioInstallation
{
public string Name { get; set; }
public string Path { get; set; }
public Version Version { get; set; }
public bool IsPrerelease { get; set; }
public bool SupportsAnalyzers
{
get
{
if (VisualStudioEditor.IsWindows)
return Version >= new Version(16, 3);
if (VisualStudioEditor.IsOSX)
return Version >= new Version(8, 3);
return false;
}
}
// C# language version support for Visual Studio
private static 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),
};
// C# language version support for Visual Studio for Mac
private static 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),
};
public Version LatestLanguageVersionSupported
{
get
{
VersionPair[] versions = null;
if (VisualStudioEditor.IsWindows)
versions = WindowsVersionTable;
if (VisualStudioEditor.IsOSX)
versions = OSXVersionTable;
if (versions != null)
{
foreach (var entry in versions)
{
if (Version >= entry.IdeVersion)
return entry.LanguageVersion;
}
}
// default to 7.0 given we support at least VS 2017
return new Version(7, 0);
}
}
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;
}
// We only use this to find analyzers, we do not need to load this assembly anymore
private string GetExtensionPath()
{
if (VisualStudioEditor.IsWindows)
{
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;
}
if (VisualStudioEditor.IsOSX)
{
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;
}
private static string[] GetAnalyzers(string path)
{
var analyzersDirectory = IOPath.GetFullPath(IOPath.Combine(path, "Analyzers"));
if (Directory.Exists(analyzersDirectory))
return Directory.GetFiles(analyzersDirectory, "*Analyzers.dll", SearchOption.AllDirectories);
return Array.Empty<string>();
}
public string[] GetAnalyzers()
{
var vstuPath = GetExtensionPath();
if (string.IsNullOrEmpty(vstuPath))
return Array.Empty<string>();
if (VisualStudioEditor.IsOSX)
return GetAnalyzers(vstuPath);
if (VisualStudioEditor.IsWindows)
{
var analyzers = GetAnalyzers(vstuPath);
if (analyzers?.Length > 0)
return analyzers;
var bridge = GetWindowsBridgeFromRegistry();
if (File.Exists(bridge))
return GetAnalyzers(IOPath.Combine(IOPath.GetDirectoryName(bridge), ".."));
}
// Local assets
// return FileUtility.FindPackageAssetFullPath("Analyzers a:packages", ".Analyzers.dll");
return Array.Empty<string>();
}
public CodeEditor.Installation ToCodeEditorInstallation()
{
return new CodeEditor.Installation() { Name = Name, Path = Path };
}
}
}
|