com.unity.ide.visualstudio@2.0.17

## [2.0.17] - 2022-12-06

Integration:

- Fix rare deadlocks while discovering or launching Visual Studio on Windows.
- Improve launching Visual Studio on macOs.

Project generation:

- Include analyzers from response files.
- Update supported C# versions.
- Performance improvements.
This commit is contained in:
Unity Technologies
2022-12-06 00:00:00 +00:00
parent 7c58d4170b
commit 4893e3bfe7
16 changed files with 410 additions and 216 deletions

View File

@@ -1,5 +1,19 @@
# Code Editor Package for Visual Studio # Code Editor Package for Visual Studio
## [2.0.17] - 2022-12-06
Integration:
- Fix rare deadlocks while discovering or launching Visual Studio on Windows.
- Improve launching Visual Studio on macOs.
Project generation:
- Include analyzers from response files.
- Update supported C# versions.
- Performance improvements.
## [2.0.16] - 2022-06-08 ## [2.0.16] - 2022-06-08
Integration: Integration:
@@ -7,7 +21,6 @@ Integration:
- Prevent ADB Refresh while being in safe-mode with a URP project - Prevent ADB Refresh while being in safe-mode with a URP project
- Fixed an issue keeping the progress bar visible even after opening a script with Visual Studio. - Fixed an issue keeping the progress bar visible even after opening a script with Visual Studio.
## [2.0.15] - 2022-03-21 ## [2.0.15] - 2022-03-21
Integration: Integration:

View File

@@ -3,7 +3,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -11,7 +11,7 @@
#define keyFileSender 1179872868 #define keyFileSender 1179872868
// 16 bit aligned legacy struct - this should total 20 bytes // 16 bit aligned legacy struct - this should total 20 bytes
struct SelectionRange typedef struct _SelectionRange
{ {
int16_t unused1; // 0 (not used) int16_t unused1; // 0 (not used)
int16_t lineNum; // line to select (<0 to specify range) int16_t lineNum; // line to select (<0 to specify range)
@@ -19,7 +19,7 @@ struct SelectionRange
int32_t endRange; // end of selection range (if line < 0) int32_t endRange; // end of selection range (if line < 0)
int32_t unused2; // 0 (not used) int32_t unused2; // 0 (not used)
int32_t theDate; // modification date/time int32_t theDate; // modification date/time
} __attribute__((packed)); } __attribute__((packed)) SelectionRange;
static NSString* MakeNSString(const char* str) static NSString* MakeNSString(const char* str)
{ {
@@ -200,18 +200,13 @@ static NSRunningApplication* QueryRunningApplicationOpenedOnSolution(NSString* a
static NSRunningApplication* LaunchApplicationOnSolution(NSString* appPath, NSString* solutionPath) static NSRunningApplication* LaunchApplicationOnSolution(NSString* appPath, NSString* solutionPath)
{ {
NSURL* appUrl = [NSURL fileURLWithPath: appPath]; return [[NSWorkspace sharedWorkspace]
NSMutableDictionary* config = [[NSMutableDictionary alloc] init]; launchApplicationAtURL: [NSURL fileURLWithPath: appPath]
NSRunningApplication* runningApp = [[NSWorkspace sharedWorkspace]
launchApplicationAtURL: appUrl
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
configuration: config configuration: @{
NSWorkspaceLaunchConfigurationArguments: @[ solutionPath ],
}
error: nil]; error: nil];
OpenFileAtLineWithAppleEvent(runningApp, solutionPath, -1);
return runningApp;
} }
static NSRunningApplication* QueryOrLaunchApplication(NSString* appPath, NSString* solutionPath) static NSRunningApplication* QueryOrLaunchApplication(NSString* appPath, NSString* solutionPath)

View File

@@ -11,20 +11,24 @@ namespace Microsoft.Unity.VisualStudio.Editor
internal class AsyncOperation<T> internal class AsyncOperation<T>
{ {
private readonly Func<T> _producer; private readonly Func<T> _producer;
private readonly Func<Exception, T> _exceptionHandler;
private readonly Action _finalHandler;
private readonly ManualResetEventSlim _resetEvent; private readonly ManualResetEventSlim _resetEvent;
private T _result; private T _result;
private Exception _exception; private Exception _exception;
private AsyncOperation(Func<T> producer) private AsyncOperation(Func<T> producer, Func<Exception, T> exceptionHandler, Action finalHandler)
{ {
_producer = producer; _producer = producer;
_exceptionHandler = exceptionHandler;
_finalHandler = finalHandler;
_resetEvent = new ManualResetEventSlim(initialState: false); _resetEvent = new ManualResetEventSlim(initialState: false);
} }
public static AsyncOperation<T> Run(Func<T> producer) public static AsyncOperation<T> Run(Func<T> producer, Func<Exception, T> exceptionHandler = null, Action finalHandler = null)
{ {
var task = new AsyncOperation<T>(producer); var task = new AsyncOperation<T>(producer, exceptionHandler, finalHandler);
task.Run(); task.Run();
return task; return task;
} }
@@ -40,9 +44,15 @@ namespace Microsoft.Unity.VisualStudio.Editor
catch (Exception e) catch (Exception e)
{ {
_exception = e; _exception = e;
if (_exceptionHandler != null)
{
_result = _exceptionHandler(e);
}
} }
finally finally
{ {
_finalHandler?.Invoke();
_resetEvent.Set(); _resetEvent.Set();
} }
}); });

View File

@@ -205,6 +205,32 @@ static bool StartVisualStudioProcess(
return true; return true;
} }
static bool
MonikerIsVisualStudioProcess(const win::ComPtr<IMoniker> &moniker, const win::ComPtr<IBindCtx> &bindCtx, const DWORD dwProcessId = 0) {
LPOLESTR oleMonikerName;
if (FAILED(moniker->GetDisplayName(bindCtx, nullptr, &oleMonikerName)))
return false;
std::wstring monikerName(oleMonikerName);
// VisualStudio Moniker is "!VisualStudio.DTE.$Version:$PID"
// Example "!VisualStudio.DTE.14.0:1234"
if (monikerName.find(L"!VisualStudio.DTE") != 0)
return false;
if (dwProcessId == 0)
return true;
std::wstringstream suffixStream;
suffixStream << ":";
suffixStream << dwProcessId;
std::wstring suffix(suffixStream.str());
return monikerName.length() - suffix.length() == monikerName.find(suffix);
}
static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithSolution( static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithSolution(
const std::filesystem::path &visualStudioExecutablePath, const std::filesystem::path &visualStudioExecutablePath,
const std::filesystem::path &solutionPath) const std::filesystem::path &solutionPath)
@@ -232,6 +258,9 @@ static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithSolution(
win::ComPtr<IMoniker> moniker; win::ComPtr<IMoniker> moniker;
ULONG monikersFetched = 0; ULONG monikersFetched = 0;
while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) { while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) {
if (!MonikerIsVisualStudioProcess(moniker, bindCtx))
continue;
if (FAILED(ROT->GetObject(moniker, &punk))) if (FAILED(ROT->GetObject(moniker, &punk)))
continue; continue;
@@ -285,29 +314,6 @@ static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithSolution(
return nullptr; return nullptr;
} }
static bool
MonikerIsVisualStudioProcess(const win::ComPtr<IMoniker> &moniker, const win::ComPtr<IBindCtx> &bindCtx, const DWORD dwProcessId) {
LPOLESTR oleMonikerName;
if (FAILED(moniker->GetDisplayName(bindCtx, nullptr, &oleMonikerName)))
return false;
std::wstring monikerName(oleMonikerName);
// VisualStudio Moniker is "!VisualStudio.DTE.$Version:$PID"
// Example "!VisualStudio.DTE.14.0:1234"
if (monikerName.find(L"!VisualStudio.DTE") != 0)
return false;
std::wstringstream suffixStream;
suffixStream << ":";
suffixStream << dwProcessId;
std::wstring suffix(suffixStream.str());
return monikerName.length() - suffix.length() == monikerName.find(suffix);
}
static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithPID(const DWORD dwProcessId) { static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithPID(const DWORD dwProcessId) {
win::ComPtr<IUnknown> punk = nullptr; win::ComPtr<IUnknown> punk = nullptr;
win::ComPtr<EnvDTE::_DTE> dte = nullptr; win::ComPtr<EnvDTE::_DTE> dte = nullptr;
@@ -329,10 +335,10 @@ static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithPID(const DWORD dwPr
win::ComPtr<IMoniker> moniker; win::ComPtr<IMoniker> moniker;
ULONG monikersFetched = 0; ULONG monikersFetched = 0;
while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) { while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) {
if (FAILED(ROT->GetObject(moniker, &punk))) if (!MonikerIsVisualStudioProcess(moniker, bindCtx, dwProcessId))
continue; continue;
if (!MonikerIsVisualStudioProcess(moniker, bindCtx, dwProcessId)) if (FAILED(ROT->GetObject(moniker, &punk)))
continue; continue;
punk.As(&dte); punk.As(&dte);

View File

@@ -1,6 +1,9 @@
Direct style: Direct style:
cl /EHsc /std:c++17 COMIntegration.cpp /link Shlwapi.lib /out:"..\Release\COMIntegration.exe" cl /EHsc /std:c++17 COMIntegration.cpp /link Shlwapi.lib /out:"..\Release\COMIntegration.exe"
For a debug build with PDB:
cl /EHsc /std:c++17 /Z7 /DEBUG:FULL COMIntegration.cpp /link Shlwapi.lib /out:"..\Release\COMIntegration.exe"
CMake style: CMake style:
cmake ../COMIntegration~ -B ./build cmake ../COMIntegration~ -B ./build
cmake --build ./build --config=release -- /p:OutDir=.. cmake --build ./build --config=release -- /p:OutDir=..

View File

@@ -150,31 +150,15 @@ namespace Microsoft.Unity.VisualStudio.Editor
if (string.IsNullOrWhiteSpace(progpath)) if (string.IsNullOrWhiteSpace(progpath))
return Enumerable.Empty<VisualStudioInstallation>(); return Enumerable.Empty<VisualStudioInstallation>();
var process = new Process var result = ProcessRunner.StartAndWaitForExit(progpath, "-prerelease -format json -utf8");
{
StartInfo = new ProcessStartInfo
{
FileName = progpath,
Arguments = "-prerelease -format json -utf8",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
}
};
using (process) if (!result.Success)
{ throw new Exception($"Failure while running vswhere: {result.Error}");
var json = string.Empty;
process.OutputDataReceived += (o, e) => json += e.Data; // Do not catch any JsonException here, this will be handled by the caller
process.Start(); return VsWhereResult
process.BeginOutputReadLine(); .FromJson(result.Output)
process.WaitForExit(); .ToVisualStudioInstallations();
var result = VsWhereResult.FromJson(json);
return result.ToVisualStudioInstallations();
}
} }
} }
} }

96
Editor/ProcessRunner.cs Normal file
View File

@@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* 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.Diagnostics;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.Unity.VisualStudio.Editor
{
internal class ProcessRunnerResult
{
public bool Success { get; set; }
public string Output { get; set; }
public string Error { get; set; }
}
internal static class ProcessRunner
{
public const int DefaultTimeoutInMilliseconds = 300000;
public static ProcessStartInfo ProcessStartInfoFor(string filename, string arguments)
{
return new ProcessStartInfo
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = filename,
Arguments = arguments
};
}
public static ProcessRunnerResult StartAndWaitForExit(string filename, string arguments, int timeoutms = DefaultTimeoutInMilliseconds, Action<string> onOutputReceived = null)
{
return StartAndWaitForExit(ProcessStartInfoFor(filename, arguments), timeoutms, onOutputReceived);
}
public static ProcessRunnerResult StartAndWaitForExit(ProcessStartInfo processStartInfo, int timeoutms = DefaultTimeoutInMilliseconds, Action<string> onOutputReceived = null)
{
var process = new Process { StartInfo = processStartInfo };
using (process)
{
var sbOutput = new StringBuilder();
var sbError = new StringBuilder();
var outputSource = new TaskCompletionSource<bool>();
var errorSource = new TaskCompletionSource<bool>();
process.OutputDataReceived += (_, e) =>
{
Append(sbOutput, e.Data, outputSource);
if (onOutputReceived != null && e.Data != null)
onOutputReceived(e.Data);
};
process.ErrorDataReceived += (_, e) => Append(sbError, e.Data, errorSource);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
var run = Task.Run(() => process.WaitForExit(timeoutms));
var processTask = Task.WhenAll(run, outputSource.Task, errorSource.Task);
if (Task.WhenAny(Task.Delay(timeoutms), processTask).Result == processTask && run.Result)
return new ProcessRunnerResult {Success = true, Error = sbError.ToString(), Output = sbOutput.ToString()};
try
{
process.Kill();
}
catch
{
/* ignore */
}
return new ProcessRunnerResult {Success = false, Error = sbError.ToString(), Output = sbOutput.ToString()};
}
}
private static void Append(StringBuilder sb, string data, TaskCompletionSource<bool> taskSource)
{
if (data == null)
{
taskSource.SetResult(true);
return;
}
sb?.Append(data);
}
}
}

View File

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

View File

@@ -43,6 +43,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
public IAssemblyNameProvider AssemblyNameProvider => m_AssemblyNameProvider; public IAssemblyNameProvider AssemblyNameProvider => m_AssemblyNameProvider;
public string ProjectDirectory { get; } public string ProjectDirectory { get; }
// Use this to have the same newline ending on all platforms for consistency.
const string k_WindowsNewline = "\r\n"; const string k_WindowsNewline = "\r\n";
const string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject"; const string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject";
@@ -126,11 +127,11 @@ namespace Microsoft.Unity.VisualStudio.Editor
var affectedNames = affected var affectedNames = affected
.Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset)) .Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset))
.Where(name => !string.IsNullOrWhiteSpace(name)).Select(name => .Where(name => !string.IsNullOrWhiteSpace(name)).Select(name =>
name.Split(new[] {".dll"}, StringSplitOptions.RemoveEmptyEntries)[0]); name.Split(new[] { ".dll" }, StringSplitOptions.RemoveEmptyEntries)[0]);
var reimportedNames = reimported var reimportedNames = reimported
.Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset)) .Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset))
.Where(name => !string.IsNullOrWhiteSpace(name)).Select(name => .Where(name => !string.IsNullOrWhiteSpace(name)).Select(name =>
name.Split(new[] {".dll"}, StringSplitOptions.RemoveEmptyEntries)[0]); name.Split(new[] { ".dll" }, StringSplitOptions.RemoveEmptyEntries)[0]);
var affectedAndReimported = new HashSet<string>(affectedNames.Concat(reimportedNames)); var affectedAndReimported = new HashSet<string>(affectedNames.Concat(reimportedNames));
foreach (var assembly in allProjectAssemblies) foreach (var assembly in allProjectAssemblies)
@@ -381,19 +382,19 @@ namespace Microsoft.Unity.VisualStudio.Editor
{ {
var filename = EscapedRelativePathFor(asset, out var packageInfo); var filename = EscapedRelativePathFor(asset, out var packageInfo);
builder.Append($" <{tag} Include=\"").Append(filename); builder.Append(" <").Append(tag).Append(@" Include=""").Append(filename);
if (Path.IsPathRooted(filename) && packageInfo != null) if (Path.IsPathRooted(filename) && packageInfo != null)
{ {
// We are outside the Unity project and using a package context // We are outside the Unity project and using a package context
var linkPath = SkipPathPrefix(asset.NormalizePathSeparators(), packageInfo.assetPath.NormalizePathSeparators()); var linkPath = SkipPathPrefix(asset.NormalizePathSeparators(), packageInfo.assetPath.NormalizePathSeparators());
builder.Append("\">").Append(k_WindowsNewline); builder.Append(@""">").Append(k_WindowsNewline);
builder.Append(" <Link>").Append(linkPath).Append("</Link>").Append(k_WindowsNewline); builder.Append(" <Link>").Append(linkPath).Append("</Link>").Append(k_WindowsNewline);
builder.Append($" </{tag}>").Append(k_WindowsNewline); builder.Append($" </{tag}>").Append(k_WindowsNewline);
} }
else else
{ {
builder.Append("\" />").Append(k_WindowsNewline); builder.Append(@""" />").Append(k_WindowsNewline);
} }
} }
@@ -504,7 +505,8 @@ namespace Microsoft.Unity.VisualStudio.Editor
Dictionary<string, string> allAssetsProjectParts, Dictionary<string, string> allAssetsProjectParts,
ResponseFileData[] responseFilesData) ResponseFileData[] responseFilesData)
{ {
var projectBuilder = new StringBuilder(ProjectHeader(assembly, responseFilesData)); ProjectHeader(assembly, responseFilesData, out StringBuilder projectBuilder);
var references = new List<string>(); var references = new List<string>();
projectBuilder.Append(@" <ItemGroup>").Append(k_WindowsNewline); projectBuilder.Append(@" <ItemGroup>").Append(k_WindowsNewline);
@@ -563,7 +565,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
// If the current assembly is a Player project, we want to project-reference the corresponding Player project // If the current assembly is a Player project, we want to project-reference the corresponding Player project
var referenceName = m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, reference.name); var referenceName = m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, reference.name);
projectBuilder.Append(" <ProjectReference Include=\"").Append(referenceName).Append(GetProjectExtension()).Append("\">").Append(k_WindowsNewline); projectBuilder.Append(@" <ProjectReference Include=""").Append(referenceName).Append(GetProjectExtension()).Append(@""">").Append(k_WindowsNewline);
projectBuilder.Append(" <Project>{").Append(ProjectGuid(referenceName)).Append("}</Project>").Append(k_WindowsNewline); projectBuilder.Append(" <Project>{").Append(ProjectGuid(referenceName)).Append("}</Project>").Append(k_WindowsNewline);
projectBuilder.Append(" <Name>").Append(referenceName).Append("</Name>").Append(k_WindowsNewline); projectBuilder.Append(" <Name>").Append(referenceName).Append("</Name>").Append(k_WindowsNewline);
projectBuilder.Append(" </ProjectReference>").Append(k_WindowsNewline); projectBuilder.Append(" </ProjectReference>").Append(k_WindowsNewline);
@@ -595,7 +597,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
private void AppendReference(string fullReference, StringBuilder projectBuilder) private void AppendReference(string fullReference, StringBuilder projectBuilder)
{ {
var escapedFullPath = EscapedRelativePathFor(fullReference, out _); var escapedFullPath = EscapedRelativePathFor(fullReference, out _);
projectBuilder.Append(" <Reference Include=\"").Append(Path.GetFileNameWithoutExtension(escapedFullPath)).Append("\">").Append(k_WindowsNewline); projectBuilder.Append(@" <Reference Include=""").Append(Path.GetFileNameWithoutExtension(escapedFullPath)).Append(@""">").Append(k_WindowsNewline);
projectBuilder.Append(" <HintPath>").Append(escapedFullPath).Append("</HintPath>").Append(k_WindowsNewline); projectBuilder.Append(" <HintPath>").Append(escapedFullPath).Append("</HintPath>").Append(k_WindowsNewline);
projectBuilder.Append(" </Reference>").Append(k_WindowsNewline); projectBuilder.Append(" </Reference>").Append(k_WindowsNewline);
} }
@@ -632,25 +634,77 @@ namespace Microsoft.Unity.VisualStudio.Editor
return targetLanguageVersion; return targetLanguageVersion;
} }
private string ProjectHeader( private static IEnumerable<string> GetOtherArguments(ResponseFileData[] responseFilesData, HashSet<string> names)
{
var lines = responseFilesData
.SelectMany(x => x.OtherArguments)
.Where(l => !string.IsNullOrEmpty(l))
.Select(l => l.Trim())
.Where(l => l.StartsWith("/") || l.StartsWith("-"));
foreach (var argument in lines)
{
var index = argument.IndexOf(":", StringComparison.Ordinal);
if (index == -1)
continue;
var key = argument
.Substring(1, index - 1)
.Trim();
if (!names.Contains(key))
continue;
if (argument.Length <= index)
continue;
yield return argument
.Substring(index + 1)
.Trim();
}
}
private string[] GetAnalyzers(Assembly assembly, ResponseFileData[] responseFilesData, out string rulesetPath)
{
rulesetPath = null;
if (m_CurrentInstallation == null || !m_CurrentInstallation.SupportsAnalyzers)
return Array.Empty<string>();
// Analyzers provided by VisualStudio
List<string> analyzers = new List<string>(m_CurrentInstallation.GetAnalyzers());
#if UNITY_2020_2_OR_NEWER
// Analyzers + ruleset provided by Unity
analyzers.AddRange(assembly.compilerOptions.RoslynAnalyzerDllPaths);
rulesetPath = assembly
.compilerOptions
.RoslynAnalyzerRulesetPath
.MakeAbsolutePath()
.NormalizePathSeparators();
#endif
// Analyzers provided by csc.rsp
analyzers.AddRange(GetOtherArguments(responseFilesData, new HashSet<string>(new[] { "analyzer", "a" })));
return analyzers
.Where(a => !string.IsNullOrEmpty(a))
.Select(a => a.MakeAbsolutePath().NormalizePathSeparators())
.Distinct()
.ToArray();
}
private void ProjectHeader(
Assembly assembly, Assembly assembly,
ResponseFileData[] responseFilesData ResponseFileData[] responseFilesData,
out StringBuilder headerBuilder
) )
{ {
var projectType = ProjectTypeOf(assembly.name); var projectType = ProjectTypeOf(assembly.name);
string rulesetPath = null; var analyzers = GetAnalyzers(assembly, responseFilesData, out var rulesetPath);
var analyzers = Array.Empty<string>();
if (m_CurrentInstallation != null && m_CurrentInstallation.SupportsAnalyzers) var projectProperties = new ProjectProperties
{
analyzers = m_CurrentInstallation.GetAnalyzers();
#if UNITY_2020_2_OR_NEWER
analyzers = analyzers != null ? analyzers.Concat(assembly.compilerOptions.RoslynAnalyzerDllPaths).ToArray() : assembly.compilerOptions.RoslynAnalyzerDllPaths;
rulesetPath = assembly.compilerOptions.RoslynAnalyzerRulesetPath;
#endif
}
var projectProperties = new ProjectProperties()
{ {
ProjectGuid = ProjectGuid(assembly), ProjectGuid = ProjectGuid(assembly),
LangVersion = GetLangVersion(assembly), LangVersion = GetLangVersion(assembly),
@@ -658,9 +712,9 @@ namespace Microsoft.Unity.VisualStudio.Editor
RootNamespace = GetRootNamespace(assembly), RootNamespace = GetRootNamespace(assembly),
OutputPath = assembly.outputPath, OutputPath = assembly.outputPath,
// Analyzers // Analyzers
Analyzers = analyzers,
RulesetPath = rulesetPath, RulesetPath = rulesetPath,
// RSP alterable // RSP alterable
Analyzers = analyzers,
Defines = assembly.defines.Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray(), Defines = assembly.defines.Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray(),
Unsafe = assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe), Unsafe = assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe),
// VSTU Flavoring // VSTU Flavoring
@@ -670,7 +724,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
FlavoringPackageVersion = VisualStudioIntegration.PackageVersion(), FlavoringPackageVersion = VisualStudioIntegration.PackageVersion(),
}; };
return GetProjectHeader(projectProperties); GetProjectHeader(projectProperties, out headerBuilder);
} }
private enum ProjectType private enum ProjectType
@@ -696,102 +750,86 @@ namespace Microsoft.Unity.VisualStudio.Editor
return ProjectType.Game; return ProjectType.Game;
} }
private string GetProjectHeader(ProjectProperties properties) private void GetProjectHeader(ProjectProperties properties, out StringBuilder headerBuilder)
{ {
var header = new[] headerBuilder = new StringBuilder();
{
$@"<?xml version=""1.0"" encoding=""utf-8""?>",
$@"<Project ToolsVersion=""4.0"" DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">",
$@" <PropertyGroup>",
$@" <LangVersion>{properties.LangVersion}</LangVersion>",
$@" </PropertyGroup>",
$@" <PropertyGroup>",
$@" <Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>",
$@" <Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>",
$@" <ProductVersion>10.0.20506</ProductVersion>",
$@" <SchemaVersion>2.0</SchemaVersion>",
$@" <RootNamespace>{properties.RootNamespace}</RootNamespace>",
$@" <ProjectGuid>{{{properties.ProjectGuid}}}</ProjectGuid>",
$@" <OutputType>Library</OutputType>",
$@" <AppDesignerFolder>Properties</AppDesignerFolder>",
$@" <AssemblyName>{properties.AssemblyName}</AssemblyName>",
$@" <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>",
$@" <FileAlignment>512</FileAlignment>",
$@" <BaseDirectory>.</BaseDirectory>",
$@" </PropertyGroup>",
$@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">",
$@" <DebugSymbols>true</DebugSymbols>",
$@" <DebugType>full</DebugType>",
$@" <Optimize>false</Optimize>",
$@" <OutputPath>{properties.OutputPath}</OutputPath>",
$@" <DefineConstants>{string.Join(";", properties.Defines)}</DefineConstants>",
$@" <ErrorReport>prompt</ErrorReport>",
$@" <WarningLevel>4</WarningLevel>",
$@" <NoWarn>0169</NoWarn>",
$@" <AllowUnsafeBlocks>{properties.Unsafe}</AllowUnsafeBlocks>",
$@" </PropertyGroup>",
$@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "">",
$@" <DebugType>pdbonly</DebugType>",
$@" <Optimize>true</Optimize>",
$@" <OutputPath>Temp\bin\Release\</OutputPath>",
$@" <ErrorReport>prompt</ErrorReport>",
$@" <WarningLevel>4</WarningLevel>",
$@" <NoWarn>0169</NoWarn>",
$@" <AllowUnsafeBlocks>{properties.Unsafe}</AllowUnsafeBlocks>",
$@" </PropertyGroup>"
};
var forceExplicitReferences = new[] //Header
{ headerBuilder.Append(@"<?xml version=""1.0"" encoding=""utf-8""?>").Append(k_WindowsNewline);
$@" <PropertyGroup>", headerBuilder.Append(@"<Project ToolsVersion=""4.0"" DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">").Append(k_WindowsNewline);
$@" <NoConfig>true</NoConfig>", headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
$@" <NoStdLib>true</NoStdLib>", headerBuilder.Append(@" <LangVersion>").Append(properties.LangVersion).Append(@"</LangVersion>").Append(k_WindowsNewline);
$@" <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>", headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
$@" <ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>", headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
$@" <ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>", headerBuilder.Append(@" <Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>").Append(k_WindowsNewline);
$@" </PropertyGroup>" headerBuilder.Append(@" <Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>").Append(k_WindowsNewline);
}; headerBuilder.Append(@" <ProductVersion>10.0.20506</ProductVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <SchemaVersion>2.0</SchemaVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <RootNamespace>").Append(properties.RootNamespace).Append(@"</RootNamespace>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ProjectGuid>{").Append(properties.ProjectGuid).Append(@"}</ProjectGuid>").Append(k_WindowsNewline);
headerBuilder.Append(@" <OutputType>Library</OutputType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AppDesignerFolder>Properties</AppDesignerFolder>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AssemblyName>").Append(properties.AssemblyName).Append(@"</AssemblyName>").Append(k_WindowsNewline);
headerBuilder.Append(@" <TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>").Append(k_WindowsNewline);
headerBuilder.Append(@" <FileAlignment>512</FileAlignment>").Append(k_WindowsNewline);
headerBuilder.Append(@" <BaseDirectory>.</BaseDirectory>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">").Append(k_WindowsNewline);
headerBuilder.Append(@" <DebugSymbols>true</DebugSymbols>").Append(k_WindowsNewline);
headerBuilder.Append(@" <DebugType>full</DebugType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <Optimize>false</Optimize>").Append(k_WindowsNewline);
headerBuilder.Append(@" <OutputPath>").Append(properties.OutputPath).Append(@"</OutputPath>").Append(k_WindowsNewline);
headerBuilder.Append(@" <DefineConstants>").Append(string.Join(";", properties.Defines)).Append(@"</DefineConstants>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ErrorReport>prompt</ErrorReport>").Append(k_WindowsNewline);
headerBuilder.Append(@" <WarningLevel>4</WarningLevel>").Append(k_WindowsNewline);
headerBuilder.Append(@" <NoWarn>0169</NoWarn>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AllowUnsafeBlocks>").Append(properties.Unsafe).Append(@"</AllowUnsafeBlocks>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
headerBuilder.Append(@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "">").Append(k_WindowsNewline);
headerBuilder.Append(@" <DebugType>pdbonly</DebugType>").Append(k_WindowsNewline);
headerBuilder.Append(@" <Optimize>true</Optimize>").Append(k_WindowsNewline);
headerBuilder.Append(@" <OutputPath>Temp\bin\Release\</OutputPath>").Append(k_WindowsNewline);
headerBuilder.Append(@" <ErrorReport>prompt</ErrorReport>").Append(k_WindowsNewline);
headerBuilder.Append(@" <WarningLevel>4</WarningLevel>").Append(k_WindowsNewline);
headerBuilder.Append(@" <NoWarn>0169</NoWarn>").Append(k_WindowsNewline);
headerBuilder.Append(@" <AllowUnsafeBlocks>").Append(properties.Unsafe).Append(@"</AllowUnsafeBlocks>").Append(k_WindowsNewline);
headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
var flavoring = new[] // Explicit references
{ headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
$@" <PropertyGroup>", headerBuilder.Append(@" <NoConfig>true</NoConfig>").Append(k_WindowsNewline);
$@" <ProjectTypeGuids>{{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1}};{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}</ProjectTypeGuids>", headerBuilder.Append(@" <NoStdLib>true</NoStdLib>").Append(k_WindowsNewline);
$@" <UnityProjectGenerator>Package</UnityProjectGenerator>", headerBuilder.Append(@" <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>").Append(k_WindowsNewline);
$@" <UnityProjectGeneratorVersion>{properties.FlavoringPackageVersion}</UnityProjectGeneratorVersion>", headerBuilder.Append(@" <ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>").Append(k_WindowsNewline);
$@" <UnityProjectType>{properties.FlavoringProjectType}</UnityProjectType>", headerBuilder.Append(@" <ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>").Append(k_WindowsNewline);
$@" <UnityBuildTarget>{properties.FlavoringBuildTarget}</UnityBuildTarget>", headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
$@" <UnityVersion>{properties.FlavoringUnityVersion}</UnityVersion>",
$@" </PropertyGroup>"
};
var footer = new[] // Flavoring
{ headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
@"" headerBuilder.Append(@" <ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>").Append(k_WindowsNewline);
}; headerBuilder.Append(@" <UnityProjectGenerator>Package</UnityProjectGenerator>").Append(k_WindowsNewline);
headerBuilder.Append(@" <UnityProjectGeneratorVersion>").Append(properties.FlavoringPackageVersion).Append(@"</UnityProjectGeneratorVersion>").Append(k_WindowsNewline);
var lines = header headerBuilder.Append(@" <UnityProjectType>").Append(properties.FlavoringProjectType).Append(@"</UnityProjectType>").Append(k_WindowsNewline);
.Concat(forceExplicitReferences) headerBuilder.Append(@" <UnityBuildTarget>").Append(properties.FlavoringBuildTarget).Append(@"</UnityBuildTarget>").Append(k_WindowsNewline);
.Concat(flavoring) headerBuilder.Append(@" <UnityVersion>").Append(properties.FlavoringUnityVersion).Append(@"</UnityVersion>").Append(k_WindowsNewline);
.ToList(); headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
if (!string.IsNullOrEmpty(properties.RulesetPath)) if (!string.IsNullOrEmpty(properties.RulesetPath))
{ {
lines.Add(@" <PropertyGroup>"); headerBuilder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
lines.Add($" <CodeAnalysisRuleSet>{properties.RulesetPath.MakeAbsolutePath().NormalizePathSeparators()}</CodeAnalysisRuleSet>"); headerBuilder.Append(@" <CodeAnalysisRuleSet>").Append(properties.RulesetPath).Append(@"</CodeAnalysisRuleSet>").Append(k_WindowsNewline);
lines.Add(@" </PropertyGroup>"); headerBuilder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
} }
if (properties.Analyzers.Any()) if (properties.Analyzers.Any())
{ {
lines.Add(@" <ItemGroup>"); headerBuilder.Append(@" <ItemGroup>").Append(k_WindowsNewline);
foreach (var analyzer in properties.Analyzers.Distinct()) foreach (var analyzer in properties.Analyzers)
{ {
lines.Add($@" <Analyzer Include=""{analyzer.MakeAbsolutePath().NormalizePathSeparators()}"" />"); headerBuilder.Append(@" <Analyzer Include=""").Append(analyzer).Append(@""" />").Append(k_WindowsNewline);
} }
lines.Add(@" </ItemGroup>"); headerBuilder.Append(@" </ItemGroup>").Append(k_WindowsNewline);
} }
return string.Join(k_WindowsNewline, lines.Concat(footer));
} }
private static string GetProjectFooter() private static string GetProjectFooter()
@@ -885,7 +923,7 @@ namespace Microsoft.Unity.VisualStudio.Editor
if (array == null || array.Length == 0) if (array == null || array.Length == 0)
{ {
// HideSolution by default // HideSolution by default
array = new [] { array = new[] {
new SolutionProperties() { new SolutionProperties() {
Name = "SolutionProperties", Name = "SolutionProperties",
Type = "preSolution", Type = "preSolution",

View File

@@ -10,9 +10,9 @@ namespace Microsoft.Unity.VisualStudio.Editor
internal static class SolutionParser internal static class SolutionParser
{ {
// Compared to the bridge implementation, we are not returning "{" "}" from Guids // Compared to the bridge implementation, we are not returning "{" "}" from Guids
private static readonly Regex ProjectDeclaration = new Regex(@"Project\(\""{(?<projectFactoryGuid>.*?)}\""\)\s+=\s+\""(?<name>.*?)\"",\s+\""(?<fileName>.*?)\"",\s+\""{(?<projectGuid>.*?)}\""(?<metadata>.*?)\bEndProject\b", RegexOptions.Singleline | RegexOptions.ExplicitCapture); private static readonly Regex ProjectDeclaration = new Regex(@"Project\(\""{(?<projectFactoryGuid>.*?)}\""\)\s+=\s+\""(?<name>.*?)\"",\s+\""(?<fileName>.*?)\"",\s+\""{(?<projectGuid>.*?)}\""(?<metadata>.*?)\bEndProject\b", RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
private static readonly Regex PropertiesDeclaration = new Regex(@"GlobalSection\((?<name>([\w]+Properties|NestedProjects))\)\s+=\s+(?<type>(?:post|pre)Solution)(?<entries>.*?)EndGlobalSection", RegexOptions.Singleline | RegexOptions.ExplicitCapture); private static readonly Regex PropertiesDeclaration = new Regex(@"GlobalSection\((?<name>([\w]+Properties|NestedProjects))\)\s+=\s+(?<type>(?:post|pre)Solution)(?<entries>.*?)EndGlobalSection", RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
private static readonly Regex PropertiesEntryDeclaration = new Regex(@"^\s*(?<key>.*?)=(?<value>.*?)$", RegexOptions.Multiline | RegexOptions.ExplicitCapture); private static readonly Regex PropertiesEntryDeclaration = new Regex(@"^\s*(?<key>.*?)=(?<value>.*?)$", RegexOptions.Multiline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
public static Solution ParseSolutionFile(string filename, IFileIO fileIO) public static Solution ParseSolutionFile(string filename, IFileIO fileIO)
{ {

Binary file not shown.

View File

@@ -4,7 +4,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -12,6 +11,8 @@ using System.Runtime.CompilerServices;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using Unity.CodeEditor; using Unity.CodeEditor;
using System.Threading;
using System.Collections.Concurrent;
[assembly: InternalsVisibleTo("Unity.VisualStudio.EditorTests")] [assembly: InternalsVisibleTo("Unity.VisualStudio.EditorTests")]
[assembly: InternalsVisibleTo("Unity.VisualStudio.Standalone.EditorTests")] [assembly: InternalsVisibleTo("Unity.VisualStudio.Standalone.EditorTests")]
@@ -287,6 +288,14 @@ namespace Microsoft.Unity.VisualStudio.Editor
return false; return false;
} }
private enum COMIntegrationState
{
Running,
DisplayProgressBar,
ClearProgressBar,
Exited
}
private bool OpenWindowsApp(string path, int line) private bool OpenWindowsApp(string path, int line)
{ {
var progpath = FileUtility.GetPackageAssetFullPath("Editor", "COMIntegration", "Release", "COMIntegration.exe"); var progpath = FileUtility.GetPackageAssetFullPath("Editor", "COMIntegration", "Release", "COMIntegration.exe");
@@ -309,44 +318,67 @@ namespace Microsoft.Unity.VisualStudio.Editor
solution = solution.Replace("^", "^^"); solution = solution.Replace("^", "^^");
} }
var process = new Process
{ var psi = ProcessRunner.ProcessStartInfoFor(progpath, $"\"{CodeEditor.CurrentEditorInstallation}\" {solution} \"{absolutePath}\" {line}");
StartInfo = new ProcessStartInfo psi.StandardOutputEncoding = System.Text.Encoding.Unicode;
{ psi.StandardErrorEncoding = System.Text.Encoding.Unicode;
FileName = progpath,
Arguments = $"\"{CodeEditor.CurrentEditorInstallation}\" {solution} \"{absolutePath}\" {line}",
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
StandardOutputEncoding = System.Text.Encoding.Unicode,
RedirectStandardError = true,
StandardErrorEncoding = System.Text.Encoding.Unicode,
}
};
var result = process.Start();
while (!process.StandardOutput.EndOfStream) // inter thread communication
{ var messages = new BlockingCollection<COMIntegrationState>();
var outputLine = process.StandardOutput.ReadLine();
if (outputLine == "displayProgressBar")
{
EditorUtility.DisplayProgressBar("Opening Visual Studio", "Starting up Visual Studio, this might take some time.", .5f);
}
if (outputLine == "clearprogressbar") 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)
{ {
EditorUtility.ClearProgressBar(); 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);
} }
var errorOutput = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(errorOutput))
{
Console.WriteLine("Error: \n" + errorOutput);
}
process.WaitForExit();
return result;
} }
[DllImport("AppleEventIntegration")] [DllImport("AppleEventIntegration")]

View File

@@ -43,6 +43,10 @@ namespace Microsoft.Unity.VisualStudio.Editor
// C# language version support for Visual Studio // C# language version support for Visual Studio
private static VersionPair[] WindowsVersionTable = private static VersionPair[] WindowsVersionTable =
{ {
// VisualStudio 2022
new VersionPair(17,4, /* => */ 11,0),
new VersionPair(17,0, /* => */ 10,0),
// VisualStudio 2019 // VisualStudio 2019
new VersionPair(16,8, /* => */ 9,0), new VersionPair(16,8, /* => */ 9,0),
new VersionPair(16,0, /* => */ 8,0), new VersionPair(16,0, /* => */ 8,0),
@@ -57,6 +61,10 @@ namespace Microsoft.Unity.VisualStudio.Editor
// C# language version support for Visual Studio for Mac // C# language version support for Visual Studio for Mac
private static VersionPair[] OSXVersionTable = 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 // VisualStudio for Mac 8.x
new VersionPair(8,8, /* => */ 9,0), new VersionPair(8,8, /* => */ 9,0),
new VersionPair(8,3, /* => */ 8,0), new VersionPair(8,3, /* => */ 8,0),

View File

@@ -2,24 +2,22 @@
"name": "com.unity.ide.visualstudio", "name": "com.unity.ide.visualstudio",
"displayName": "Visual Studio Editor", "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.", "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.16", "version": "2.0.17",
"unity": "2019.4", "unity": "2019.4",
"unityRelease": "25f1", "unityRelease": "25f1",
"dependencies": { "dependencies": {
"com.unity.test-framework": "1.1.9" "com.unity.test-framework": "1.1.9"
}, },
"relatedPackages": { "relatedPackages": {
"com.unity.ide.visualstudio.tests": "2.0.16" "com.unity.ide.visualstudio.tests": "2.0.17"
},
"_upm": {
"changelog": "Integration:\n\n- Prevent ADB Refresh while being in safe-mode with a URP project\n- Fixed an issue keeping the progress bar visible even after opening a script with Visual Studio."
}, },
"upmCi": { "upmCi": {
"footprint": "3d5e14bed71dd5b89e088160c170e814d0058248" "footprint": "95a297ed65f40d1df2fe8239f87deab3217a10b0"
}, },
"documentationUrl": "https://docs.unity3d.com/Packages/com.unity.ide.visualstudio@2.0/manual/index.html",
"repository": { "repository": {
"url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.visualstudio.git", "url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.visualstudio.git",
"type": "git", "type": "git",
"revision": "c01855ef6461b821ab0226135e96a4ee86de96be" "revision": "1f126893bfb18ea9661fb15771613e841467073c"
} }
} }