You've already forked com.unity.ide.cursor
mirror of
https://github.com/boxqkrtm/com.unity.ide.cursor.git
synced 2026-05-14 22:30:10 +00:00
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:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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=..
|
||||||
|
|||||||
Binary file not shown.
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
96
Editor/ProcessRunner.cs
Normal file
96
Editor/ProcessRunner.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/ProcessRunner.cs.meta
Normal file
11
Editor/ProcessRunner.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 957a5f2d2660a894d926660de2a9d577
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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.
@@ -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")]
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user