mirror of
https://github.com/Project-Redacted/Highscores-Server.git
synced 2025-05-18 09:24:57 +00:00
Add example Unity Project
This commit is contained in:
parent
fda7ff28dd
commit
e3acdb9d6b
7122 changed files with 505543 additions and 2 deletions
|
@ -0,0 +1,90 @@
|
|||
# Code Editor Package for Visual Studio Code
|
||||
|
||||
## [1.2.5] - 2022-02-07
|
||||
|
||||
- Introduce OnGeneratedCSProjectFiles, OnGeneratedCSProject and OnGeneratedSlnSolution callbacks.
|
||||
- Always use forward slash in source paths
|
||||
- Analyzers use absolute paths
|
||||
- Ruleset files for roslyn analyzers
|
||||
- Extra snap search paths on Ubuntu
|
||||
- Specific c# language version for specific unity versions
|
||||
- No longer hide .gitignore in VSCode file explorer
|
||||
|
||||
|
||||
## [1.2.3] - 2020-10-23
|
||||
|
||||
Remove workaround for VSCode omnisharp (as of https://github.com/OmniSharp/omnisharp-vscode/issues/4113 we no longer need to disable the referenceoutputassemblies).
|
||||
|
||||
|
||||
## [1.2.2] - 2020-09-04
|
||||
|
||||
VSC-14 - synchronize solution file when adding new assembly
|
||||
|
||||
|
||||
## [1.2.1] - 2020-05-15
|
||||
|
||||
Source filtering adds support for asmref
|
||||
|
||||
|
||||
## [1.2.0] - 2020-03-04
|
||||
|
||||
Do not reference projects that has not been generated (case 1211057)
|
||||
Only open files that exists (case 1188394)
|
||||
Add individual toggle buttons for generating csprojects for packages
|
||||
Add support for Roslyn analyzers in project generation through csc.rsp and compiled assembly references
|
||||
Remove Release build target from csproj and sln
|
||||
|
||||
|
||||
## [1.1.4] - 2020-01-02
|
||||
|
||||
Delta project generation, only recompute the csproj files whose script modified.
|
||||
|
||||
|
||||
## [1.1.3] - 2019-10-22
|
||||
|
||||
Exe version of vscode will use Normal ProcessWindowStyle while cmd will use Hidden
|
||||
|
||||
|
||||
## [1.1.2] - 2019-08-30
|
||||
|
||||
Fixing OSX open command arguments
|
||||
|
||||
|
||||
## [1.1.1] - 2019-08-19
|
||||
|
||||
Support for Player Project. Generates specific csproj files containing files, reference, defines,
|
||||
etc. that will show how the assembly will be compiled for a target platform.
|
||||
|
||||
|
||||
## [1.1.0] - 2019-08-07
|
||||
|
||||
Adds support for choosing extensions to be opened with VSCode. This can be done through the GUI in Preferences.
|
||||
Avoids opening all extensions after the change in core unity.
|
||||
|
||||
|
||||
## [1.0.7] - 2019-05-15
|
||||
|
||||
Fix various OSX specific issues.
|
||||
Generate project on load if they are not generated.
|
||||
Fix path recognition.
|
||||
|
||||
|
||||
## [1.0.6] - 2019-04-30
|
||||
|
||||
Ensure asset database is refreshed when generating csproj and solution files.
|
||||
|
||||
## [1.0.5] - 2019-04-27
|
||||
|
||||
Add support for generating all csproj files.
|
||||
|
||||
## [1.0.4] - 2019-04-18
|
||||
|
||||
Fix relative package paths.
|
||||
Fix opening editor on mac.
|
||||
Add %LOCALAPPDATA%/Programs to the path of install paths.
|
||||
|
||||
## [1.0.3] - 2019-01-01
|
||||
|
||||
### This is the first release of *Unity Package vscode_editor*.
|
||||
|
||||
Using the newly created api to integrate Visual Studio Code with Unity.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ddcdc3816429494a8bea67e973875f7
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,6 @@
|
|||
# Contributing
|
||||
|
||||
## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement)
|
||||
By making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions.
|
||||
|
||||
## Once you have a change ready following these ground rules. Simply make a pull request
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fcb9be00baf924c4183fc0313e6185c5
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 58628227479c34542ac8c5193ccced84
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c779d3735d950f341ba35154e8b3234b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEditor.PackageManager;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
public interface IAssemblyNameProvider
|
||||
{
|
||||
string[] ProjectSupportedExtensions { get; }
|
||||
ProjectGenerationFlag ProjectGenerationFlag { get; }
|
||||
string GetAssemblyNameFromScriptPath(string path);
|
||||
IEnumerable<Assembly> GetAssemblies(Func<string, bool> shouldFileBePartOfSolution);
|
||||
IEnumerable<string> GetAllAssetPaths();
|
||||
IEnumerable<string> GetRoslynAnalyzerPaths();
|
||||
UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath);
|
||||
ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories);
|
||||
bool IsInternalizedPackagePath(string path);
|
||||
void ToggleProjectGeneration(ProjectGenerationFlag preference);
|
||||
}
|
||||
|
||||
internal interface IPackageInfoCache{
|
||||
void ResetPackageInfoCache();
|
||||
}
|
||||
|
||||
internal class AssemblyNameProvider : IAssemblyNameProvider, IPackageInfoCache
|
||||
{
|
||||
private readonly Dictionary<string, UnityEditor.PackageManager.PackageInfo> m_PackageInfoCache = new Dictionary<string, UnityEditor.PackageManager.PackageInfo>();
|
||||
|
||||
ProjectGenerationFlag m_ProjectGenerationFlag = (ProjectGenerationFlag)EditorPrefs.GetInt("unity_project_generation_flag", 0);
|
||||
|
||||
public string[] ProjectSupportedExtensions => EditorSettings.projectGenerationUserExtensions;
|
||||
|
||||
public ProjectGenerationFlag ProjectGenerationFlag
|
||||
{
|
||||
get => m_ProjectGenerationFlag;
|
||||
private set
|
||||
{
|
||||
EditorPrefs.SetInt("unity_project_generation_flag", (int)value);
|
||||
m_ProjectGenerationFlag = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetAssemblyNameFromScriptPath(string path)
|
||||
{
|
||||
return CompilationPipeline.GetAssemblyNameFromScriptPath(path);
|
||||
}
|
||||
|
||||
public IEnumerable<Assembly> GetAssemblies(Func<string, bool> shouldFileBePartOfSolution)
|
||||
{
|
||||
return CompilationPipeline.GetAssemblies()
|
||||
.Where(i => 0 < i.sourceFiles.Length && i.sourceFiles.Any(shouldFileBePartOfSolution));
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllAssetPaths()
|
||||
{
|
||||
return AssetDatabase.GetAllAssetPaths();
|
||||
}
|
||||
|
||||
private static string ResolvePotentialParentPackageAssetPath(string assetPath)
|
||||
{
|
||||
const string packagesPrefix = "packages/";
|
||||
if (!assetPath.StartsWith(packagesPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var followupSeparator = assetPath.IndexOf('/', packagesPrefix.Length);
|
||||
if (followupSeparator == -1)
|
||||
{
|
||||
return assetPath.ToLowerInvariant();
|
||||
}
|
||||
|
||||
return assetPath.Substring(0, followupSeparator).ToLowerInvariant();
|
||||
}
|
||||
|
||||
public void ResetPackageInfoCache()
|
||||
{
|
||||
m_PackageInfoCache.Clear();
|
||||
}
|
||||
|
||||
public UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath)
|
||||
{
|
||||
var parentPackageAssetPath = ResolvePotentialParentPackageAssetPath(assetPath);
|
||||
if (parentPackageAssetPath == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_PackageInfoCache.TryGetValue(parentPackageAssetPath, out var cachedPackageInfo))
|
||||
{
|
||||
return cachedPackageInfo;
|
||||
}
|
||||
|
||||
var result = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(parentPackageAssetPath);
|
||||
m_PackageInfoCache[parentPackageAssetPath] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories)
|
||||
{
|
||||
return CompilationPipeline.ParseResponseFile(
|
||||
responseFilePath,
|
||||
projectDirectory,
|
||||
systemReferenceDirectories
|
||||
);
|
||||
}
|
||||
|
||||
public bool IsInternalizedPackagePath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var packageInfo = FindForAssetPath(path);
|
||||
if (packageInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var packageSource = packageInfo.source;
|
||||
switch (packageSource)
|
||||
{
|
||||
case PackageSource.Embedded:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Embedded);
|
||||
case PackageSource.Registry:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Registry);
|
||||
case PackageSource.BuiltIn:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.BuiltIn);
|
||||
case PackageSource.Unknown:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Unknown);
|
||||
case PackageSource.Local:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Local);
|
||||
case PackageSource.Git:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Git);
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
case PackageSource.LocalTarball:
|
||||
return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.LocalTarBall);
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ToggleProjectGeneration(ProjectGenerationFlag preference)
|
||||
{
|
||||
if (ProjectGenerationFlag.HasFlag(preference))
|
||||
{
|
||||
ProjectGenerationFlag ^= preference;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectGenerationFlag |= preference;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetRoslynAnalyzerPaths()
|
||||
{
|
||||
return PluginImporter.GetAllImporters()
|
||||
.Where(i => !i.isNativePlugin && AssetDatabase.GetLabels(i).SingleOrDefault(l => l == "RoslynAnalyzer") != null)
|
||||
.Select(i => i.assetPath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1d93ffb668978f7488211a331977b73b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
public interface IFileIO
|
||||
{
|
||||
bool Exists(string fileName);
|
||||
|
||||
string ReadAllText(string fileName);
|
||||
void WriteAllText(string fileName, string content);
|
||||
|
||||
void CreateDirectory(string pathName);
|
||||
string EscapedRelativePathFor(string file, string projectDirectory);
|
||||
}
|
||||
|
||||
class FileIOProvider : IFileIO
|
||||
{
|
||||
public bool Exists(string fileName)
|
||||
{
|
||||
return File.Exists(fileName);
|
||||
}
|
||||
|
||||
public string ReadAllText(string fileName)
|
||||
{
|
||||
return File.ReadAllText(fileName);
|
||||
}
|
||||
|
||||
public void WriteAllText(string fileName, string content)
|
||||
{
|
||||
File.WriteAllText(fileName, content, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public void CreateDirectory(string pathName)
|
||||
{
|
||||
Directory.CreateDirectory(pathName);
|
||||
}
|
||||
|
||||
public string EscapedRelativePathFor(string file, string projectDirectory)
|
||||
{
|
||||
var projectDir = Path.GetFullPath(projectDirectory);
|
||||
|
||||
// We have to normalize the path, because the PackageManagerRemapper assumes
|
||||
// dir seperators will be os specific.
|
||||
var absolutePath = Path.GetFullPath(file.NormalizePath());
|
||||
var path = SkipPathPrefix(absolutePath, projectDir);
|
||||
|
||||
return SecurityElement.Escape(path);
|
||||
}
|
||||
|
||||
private static string SkipPathPrefix(string path, string prefix)
|
||||
{
|
||||
return path.StartsWith($@"{prefix}{Path.DirectorySeparatorChar}", StringComparison.Ordinal)
|
||||
? path.Substring(prefix.Length + 1)
|
||||
: path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eb221cf55b3544646b0c3b6bc790080f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
|||
namespace VSCodeEditor
|
||||
{
|
||||
public interface IGUIDGenerator
|
||||
{
|
||||
string ProjectGuid(string projectName, string assemblyName);
|
||||
string SolutionGuid(string projectName, string extension);
|
||||
}
|
||||
|
||||
class GUIDProvider : IGUIDGenerator
|
||||
{
|
||||
public string ProjectGuid(string projectName, string assemblyName)
|
||||
{
|
||||
return SolutionGuidGenerator.GuidForProject(projectName + assemblyName);
|
||||
}
|
||||
|
||||
public string SolutionGuid(string projectName, string extension)
|
||||
{
|
||||
return SolutionGuidGenerator.GuidForSolution(projectName, extension); // GetExtensionOfSourceFiles(assembly.sourceFiles)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e58bd3cca6475e54b93632bb6837aeea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,829 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
using SR = System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
public interface IGenerator
|
||||
{
|
||||
bool SyncIfNeeded(List<string> affectedFiles, string[] reimportedFiles);
|
||||
void Sync();
|
||||
string SolutionFile();
|
||||
string ProjectDirectory { get; }
|
||||
IAssemblyNameProvider AssemblyNameProvider { get; }
|
||||
void GenerateAll(bool generateAll);
|
||||
bool SolutionExists();
|
||||
}
|
||||
|
||||
public class ProjectGeneration : IGenerator
|
||||
{
|
||||
enum ScriptingLanguage
|
||||
{
|
||||
None,
|
||||
CSharp
|
||||
}
|
||||
|
||||
public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003";
|
||||
|
||||
const string k_WindowsNewline = "\r\n";
|
||||
|
||||
const string k_SettingsJson = @"{
|
||||
""files.exclude"":
|
||||
{
|
||||
""**/.DS_Store"":true,
|
||||
""**/.git"":true,
|
||||
""**/.gitmodules"":true,
|
||||
""**/*.booproj"":true,
|
||||
""**/*.pidb"":true,
|
||||
""**/*.suo"":true,
|
||||
""**/*.user"":true,
|
||||
""**/*.userprefs"":true,
|
||||
""**/*.unityproj"":true,
|
||||
""**/*.dll"":true,
|
||||
""**/*.exe"":true,
|
||||
""**/*.pdf"":true,
|
||||
""**/*.mid"":true,
|
||||
""**/*.midi"":true,
|
||||
""**/*.wav"":true,
|
||||
""**/*.gif"":true,
|
||||
""**/*.ico"":true,
|
||||
""**/*.jpg"":true,
|
||||
""**/*.jpeg"":true,
|
||||
""**/*.png"":true,
|
||||
""**/*.psd"":true,
|
||||
""**/*.tga"":true,
|
||||
""**/*.tif"":true,
|
||||
""**/*.tiff"":true,
|
||||
""**/*.3ds"":true,
|
||||
""**/*.3DS"":true,
|
||||
""**/*.fbx"":true,
|
||||
""**/*.FBX"":true,
|
||||
""**/*.lxo"":true,
|
||||
""**/*.LXO"":true,
|
||||
""**/*.ma"":true,
|
||||
""**/*.MA"":true,
|
||||
""**/*.obj"":true,
|
||||
""**/*.OBJ"":true,
|
||||
""**/*.asset"":true,
|
||||
""**/*.cubemap"":true,
|
||||
""**/*.flare"":true,
|
||||
""**/*.mat"":true,
|
||||
""**/*.meta"":true,
|
||||
""**/*.prefab"":true,
|
||||
""**/*.unity"":true,
|
||||
""build/"":true,
|
||||
""Build/"":true,
|
||||
""Library/"":true,
|
||||
""library/"":true,
|
||||
""obj/"":true,
|
||||
""Obj/"":true,
|
||||
""ProjectSettings/"":true,
|
||||
""temp/"":true,
|
||||
""Temp/"":true
|
||||
}
|
||||
}";
|
||||
|
||||
/// <summary>
|
||||
/// Map source extensions to ScriptingLanguages
|
||||
/// </summary>
|
||||
static readonly Dictionary<string, ScriptingLanguage> k_BuiltinSupportedExtensions = new Dictionary<string, ScriptingLanguage>
|
||||
{
|
||||
{ "cs", ScriptingLanguage.CSharp },
|
||||
{ "uxml", ScriptingLanguage.None },
|
||||
{ "uss", ScriptingLanguage.None },
|
||||
{ "shader", ScriptingLanguage.None },
|
||||
{ "compute", ScriptingLanguage.None },
|
||||
{ "cginc", ScriptingLanguage.None },
|
||||
{ "hlsl", ScriptingLanguage.None },
|
||||
{ "glslinc", ScriptingLanguage.None },
|
||||
{ "template", ScriptingLanguage.None },
|
||||
{ "raytrace", ScriptingLanguage.None }
|
||||
};
|
||||
|
||||
readonly string m_SolutionProjectEntryTemplate = string.Join("\r\n", @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""", @"EndProject").Replace(" ", "\t");
|
||||
|
||||
readonly string m_SolutionProjectConfigurationTemplate = string.Join("\r\n", @" {{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", @" {{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU").Replace(" ", "\t");
|
||||
|
||||
static readonly string[] k_ReimportSyncExtensions = { ".dll", ".asmdef" };
|
||||
|
||||
string[] m_ProjectSupportedExtensions = Array.Empty<string>();
|
||||
const string k_TargetLanguageVersion = "latest";
|
||||
|
||||
public string ProjectDirectory { get; }
|
||||
IAssemblyNameProvider IGenerator.AssemblyNameProvider => m_AssemblyNameProvider;
|
||||
|
||||
public void GenerateAll(bool generateAll)
|
||||
{
|
||||
m_AssemblyNameProvider.ToggleProjectGeneration(
|
||||
ProjectGenerationFlag.BuiltIn
|
||||
| ProjectGenerationFlag.Embedded
|
||||
| ProjectGenerationFlag.Git
|
||||
| ProjectGenerationFlag.Local
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
| ProjectGenerationFlag.LocalTarBall
|
||||
#endif
|
||||
| ProjectGenerationFlag.PlayerAssemblies
|
||||
| ProjectGenerationFlag.Registry
|
||||
| ProjectGenerationFlag.Unknown);
|
||||
}
|
||||
|
||||
readonly string m_ProjectName;
|
||||
readonly IAssemblyNameProvider m_AssemblyNameProvider;
|
||||
readonly IFileIO m_FileIOProvider;
|
||||
readonly IGUIDGenerator m_GUIDProvider;
|
||||
|
||||
const string k_ToolsVersion = "4.0";
|
||||
const string k_ProductVersion = "10.0.20506";
|
||||
const string k_BaseDirectory = ".";
|
||||
const string k_TargetFrameworkVersion = "v4.7.1";
|
||||
public ProjectGeneration(string tempDirectory)
|
||||
: this(tempDirectory, new AssemblyNameProvider(), new FileIOProvider(), new GUIDProvider()) { }
|
||||
|
||||
public ProjectGeneration(string tempDirectory, IAssemblyNameProvider assemblyNameProvider, IFileIO fileIO, IGUIDGenerator guidGenerator)
|
||||
{
|
||||
ProjectDirectory = tempDirectory.NormalizePath();
|
||||
m_ProjectName = Path.GetFileName(ProjectDirectory);
|
||||
m_AssemblyNameProvider = assemblyNameProvider;
|
||||
m_FileIOProvider = fileIO;
|
||||
m_GUIDProvider = guidGenerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Syncs the scripting solution if any affected files are relevant.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Whether the solution was synced.
|
||||
/// </returns>
|
||||
/// <param name='affectedFiles'>
|
||||
/// A set of files whose status has changed
|
||||
/// </param>
|
||||
/// <param name="reimportedFiles">
|
||||
/// A set of files that got reimported
|
||||
/// </param>
|
||||
public bool SyncIfNeeded(List<string> affectedFiles, string[] reimportedFiles)
|
||||
{
|
||||
Profiler.BeginSample("SolutionSynchronizerSync");
|
||||
SetupProjectSupportedExtensions();
|
||||
|
||||
if (!HasFilesBeenModified(affectedFiles, reimportedFiles))
|
||||
{
|
||||
Profiler.EndSample();
|
||||
return false;
|
||||
}
|
||||
|
||||
var assemblies = m_AssemblyNameProvider.GetAssemblies(ShouldFileBePartOfSolution);
|
||||
var allProjectAssemblies = RelevantAssembliesForMode(assemblies).ToList();
|
||||
SyncSolution(allProjectAssemblies);
|
||||
|
||||
var allAssetProjectParts = GenerateAllAssetProjectParts();
|
||||
|
||||
var affectedNames = affectedFiles.Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset)).Where(name => !string.IsNullOrWhiteSpace(name)).Select(name => name.Split(new [] {".dll"}, StringSplitOptions.RemoveEmptyEntries)[0]);
|
||||
var reimportedNames = reimportedFiles.Select(asset => m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset)).Where(name => !string.IsNullOrWhiteSpace(name)).Select(name => name.Split(new [] {".dll"}, StringSplitOptions.RemoveEmptyEntries)[0]);
|
||||
var affectedAndReimported = new HashSet<string>(affectedNames.Concat(reimportedNames));
|
||||
|
||||
foreach (var assembly in allProjectAssemblies)
|
||||
{
|
||||
if (!affectedAndReimported.Contains(assembly.name))
|
||||
continue;
|
||||
|
||||
SyncProject(assembly, allAssetProjectParts, ParseResponseFileData(assembly));
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasFilesBeenModified(List<string> affectedFiles, string[] reimportedFiles)
|
||||
{
|
||||
return affectedFiles.Any(ShouldFileBePartOfSolution) || reimportedFiles.Any(ShouldSyncOnReimportedAsset);
|
||||
}
|
||||
|
||||
static bool ShouldSyncOnReimportedAsset(string asset)
|
||||
{
|
||||
return k_ReimportSyncExtensions.Contains(new FileInfo(asset).Extension);
|
||||
}
|
||||
|
||||
private static IEnumerable<SR.MethodInfo> GetPostProcessorCallbacks(string name)
|
||||
{
|
||||
return TypeCache
|
||||
.GetTypesDerivedFrom<AssetPostprocessor>()
|
||||
.Select(t => t.GetMethod(name, SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static))
|
||||
.Where(m => m != null);
|
||||
}
|
||||
|
||||
static void OnGeneratedCSProjectFiles()
|
||||
{
|
||||
foreach (var method in GetPostProcessorCallbacks(nameof(OnGeneratedCSProjectFiles)))
|
||||
{
|
||||
method.Invoke(null, Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
|
||||
private static string InvokeAssetPostProcessorGenerationCallbacks(string name, string path, string content)
|
||||
{
|
||||
foreach (var method in GetPostProcessorCallbacks(name))
|
||||
{
|
||||
var args = new[] { path, content };
|
||||
var returnValue = method.Invoke(null, args);
|
||||
if (method.ReturnType == typeof(string))
|
||||
{
|
||||
// We want to chain content update between invocations
|
||||
content = (string)returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private static string OnGeneratedCSProject(string path, string content)
|
||||
{
|
||||
return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedCSProject), path, content);
|
||||
}
|
||||
|
||||
private static string OnGeneratedSlnSolution(string path, string content)
|
||||
{
|
||||
return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedSlnSolution), path, content);
|
||||
}
|
||||
|
||||
public void Sync()
|
||||
{
|
||||
SetupProjectSupportedExtensions();
|
||||
GenerateAndWriteSolutionAndProjects();
|
||||
|
||||
OnGeneratedCSProjectFiles();
|
||||
}
|
||||
|
||||
public bool SolutionExists()
|
||||
{
|
||||
return m_FileIOProvider.Exists(SolutionFile());
|
||||
}
|
||||
|
||||
void SetupProjectSupportedExtensions()
|
||||
{
|
||||
m_ProjectSupportedExtensions = m_AssemblyNameProvider.ProjectSupportedExtensions;
|
||||
}
|
||||
|
||||
bool ShouldFileBePartOfSolution(string file)
|
||||
{
|
||||
// Exclude files coming from packages except if they are internalized.
|
||||
if (m_AssemblyNameProvider.IsInternalizedPackagePath(file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasValidExtension(file);
|
||||
}
|
||||
|
||||
bool HasValidExtension(string file)
|
||||
{
|
||||
string extension = Path.GetExtension(file);
|
||||
|
||||
// Dll's are not scripts but still need to be included..
|
||||
if (extension == ".dll")
|
||||
return true;
|
||||
|
||||
if (file.ToLower().EndsWith(".asmdef"))
|
||||
return true;
|
||||
|
||||
return IsSupportedExtension(extension);
|
||||
}
|
||||
|
||||
bool IsSupportedExtension(string extension)
|
||||
{
|
||||
extension = extension.TrimStart('.');
|
||||
if (k_BuiltinSupportedExtensions.ContainsKey(extension))
|
||||
return true;
|
||||
if (m_ProjectSupportedExtensions.Contains(extension))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static ScriptingLanguage ScriptingLanguageFor(Assembly assembly)
|
||||
{
|
||||
return ScriptingLanguageFor(GetExtensionOfSourceFiles(assembly.sourceFiles));
|
||||
}
|
||||
|
||||
static string GetExtensionOfSourceFiles(string[] files)
|
||||
{
|
||||
return files.Length > 0 ? GetExtensionOfSourceFile(files[0]) : "NA";
|
||||
}
|
||||
|
||||
static string GetExtensionOfSourceFile(string file)
|
||||
{
|
||||
var ext = Path.GetExtension(file).ToLower();
|
||||
ext = ext.Substring(1); //strip dot
|
||||
return ext;
|
||||
}
|
||||
|
||||
static ScriptingLanguage ScriptingLanguageFor(string extension)
|
||||
{
|
||||
return k_BuiltinSupportedExtensions.TryGetValue(extension.TrimStart('.'), out var result)
|
||||
? result
|
||||
: ScriptingLanguage.None;
|
||||
}
|
||||
|
||||
public void GenerateAndWriteSolutionAndProjects()
|
||||
{
|
||||
// Only synchronize assemblies that have associated source files and ones that we actually want in the project.
|
||||
// This also filters out DLLs coming from .asmdef files in packages.
|
||||
var assemblies = m_AssemblyNameProvider.GetAssemblies(ShouldFileBePartOfSolution).ToArray();
|
||||
|
||||
var allAssetProjectParts = GenerateAllAssetProjectParts();
|
||||
|
||||
SyncSolution(assemblies);
|
||||
var allProjectAssemblies = RelevantAssembliesForMode(assemblies).ToList();
|
||||
foreach (Assembly assembly in allProjectAssemblies)
|
||||
{
|
||||
var responseFileData = ParseResponseFileData(assembly);
|
||||
SyncProject(assembly, allAssetProjectParts, responseFileData);
|
||||
}
|
||||
|
||||
WriteVSCodeSettingsFiles();
|
||||
}
|
||||
|
||||
List<ResponseFileData> ParseResponseFileData(Assembly assembly)
|
||||
{
|
||||
var systemReferenceDirectories = CompilationPipeline.GetSystemAssemblyDirectories(assembly.compilerOptions.ApiCompatibilityLevel);
|
||||
|
||||
Dictionary<string, ResponseFileData> responseFilesData = assembly.compilerOptions.ResponseFiles.ToDictionary(x => x, x => m_AssemblyNameProvider.ParseResponseFile(
|
||||
x,
|
||||
ProjectDirectory,
|
||||
systemReferenceDirectories
|
||||
));
|
||||
|
||||
Dictionary<string, ResponseFileData> responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any())
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
if (responseFilesWithErrors.Any())
|
||||
{
|
||||
foreach (var error in responseFilesWithErrors)
|
||||
foreach (var valueError in error.Value.Errors)
|
||||
{
|
||||
Debug.LogError($"{error.Key} Parse Error : {valueError}");
|
||||
}
|
||||
}
|
||||
|
||||
return responseFilesData.Select(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
Dictionary<string, string> GenerateAllAssetProjectParts()
|
||||
{
|
||||
Dictionary<string, StringBuilder> stringBuilders = new Dictionary<string, StringBuilder>();
|
||||
|
||||
foreach (string asset in m_AssemblyNameProvider.GetAllAssetPaths())
|
||||
{
|
||||
// Exclude files coming from packages except if they are internalized.
|
||||
// TODO: We need assets from the assembly API
|
||||
if (m_AssemblyNameProvider.IsInternalizedPackagePath(asset))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string extension = Path.GetExtension(asset);
|
||||
if (IsSupportedExtension(extension) && ScriptingLanguage.None == ScriptingLanguageFor(extension))
|
||||
{
|
||||
// Find assembly the asset belongs to by adding script extension and using compilation pipeline.
|
||||
var assemblyName = m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset);
|
||||
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
|
||||
|
||||
if (!stringBuilders.TryGetValue(assemblyName, out var projectBuilder))
|
||||
{
|
||||
projectBuilder = new StringBuilder();
|
||||
stringBuilders[assemblyName] = projectBuilder;
|
||||
}
|
||||
|
||||
projectBuilder.Append(" <None Include=\"").Append(m_FileIOProvider.EscapedRelativePathFor(asset, ProjectDirectory)).Append("\" />").Append(k_WindowsNewline);
|
||||
}
|
||||
}
|
||||
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
foreach (var entry in stringBuilders)
|
||||
result[entry.Key] = entry.Value.ToString();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SyncProject(
|
||||
Assembly assembly,
|
||||
Dictionary<string, string> allAssetsProjectParts,
|
||||
List<ResponseFileData> responseFilesData)
|
||||
{
|
||||
SyncProjectFileIfNotChanged(ProjectFile(assembly), ProjectText(assembly, allAssetsProjectParts, responseFilesData));
|
||||
}
|
||||
|
||||
void SyncProjectFileIfNotChanged(string path, string newContents)
|
||||
{
|
||||
if (Path.GetExtension(path) == ".csproj")
|
||||
{
|
||||
newContents = OnGeneratedCSProject(path, newContents);
|
||||
}
|
||||
|
||||
SyncFileIfNotChanged(path, newContents);
|
||||
}
|
||||
|
||||
void SyncSolutionFileIfNotChanged(string path, string newContents)
|
||||
{
|
||||
newContents = OnGeneratedSlnSolution(path, newContents);
|
||||
|
||||
SyncFileIfNotChanged(path, newContents);
|
||||
}
|
||||
|
||||
void SyncFileIfNotChanged(string filename, string newContents)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_FileIOProvider.Exists(filename) && newContents == m_FileIOProvider.ReadAllText(filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogException(exception);
|
||||
}
|
||||
|
||||
m_FileIOProvider.WriteAllText(filename, newContents);
|
||||
}
|
||||
|
||||
string ProjectText(
|
||||
Assembly assembly,
|
||||
Dictionary<string, string> allAssetsProjectParts,
|
||||
List<ResponseFileData> responseFilesData)
|
||||
{
|
||||
var projectBuilder = new StringBuilder();
|
||||
ProjectHeader(assembly, responseFilesData, projectBuilder);
|
||||
var references = new List<string>();
|
||||
|
||||
foreach (string file in assembly.sourceFiles)
|
||||
{
|
||||
var fullFile = m_FileIOProvider.EscapedRelativePathFor(file, ProjectDirectory);
|
||||
projectBuilder.Append(" <Compile Include=\"").Append(fullFile).Append("\" />").Append(k_WindowsNewline);
|
||||
}
|
||||
|
||||
// Append additional non-script files that should be included in project generation.
|
||||
if (allAssetsProjectParts.TryGetValue(assembly.name, out var additionalAssetsForProject))
|
||||
projectBuilder.Append(additionalAssetsForProject);
|
||||
|
||||
var responseRefs = responseFilesData.SelectMany(x => x.FullPathReferences.Select(r => r));
|
||||
var internalAssemblyReferences = assembly.assemblyReferences
|
||||
.Where(i => !i.sourceFiles.Any(ShouldFileBePartOfSolution)).Select(i => i.outputPath);
|
||||
var allReferences =
|
||||
assembly.compiledAssemblyReferences
|
||||
.Union(responseRefs)
|
||||
.Union(references)
|
||||
.Union(internalAssemblyReferences);
|
||||
|
||||
foreach (var reference in allReferences)
|
||||
{
|
||||
string fullReference = Path.IsPathRooted(reference) ? reference : Path.Combine(ProjectDirectory, reference);
|
||||
AppendReference(fullReference, projectBuilder);
|
||||
}
|
||||
|
||||
if (0 < assembly.assemblyReferences.Length)
|
||||
{
|
||||
projectBuilder.Append(" </ItemGroup>").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" <ItemGroup>").Append(k_WindowsNewline);
|
||||
foreach (Assembly reference in assembly.assemblyReferences.Where(i => i.sourceFiles.Any(ShouldFileBePartOfSolution)))
|
||||
{
|
||||
projectBuilder.Append(" <ProjectReference Include=\"").Append(reference.name).Append(GetProjectExtension()).Append("\">").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" <Project>{").Append(ProjectGuid(reference.name)).Append("}</Project>").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" <Name>").Append(reference.name).Append("</Name>").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" </ProjectReference>").Append(k_WindowsNewline);
|
||||
}
|
||||
}
|
||||
|
||||
projectBuilder.Append(ProjectFooter());
|
||||
return projectBuilder.ToString();
|
||||
}
|
||||
|
||||
static void AppendReference(string fullReference, StringBuilder projectBuilder)
|
||||
{
|
||||
var escapedFullPath = SecurityElement.Escape(fullReference);
|
||||
escapedFullPath = escapedFullPath.NormalizePath();
|
||||
projectBuilder.Append(" <Reference Include=\"").Append(Path.GetFileNameWithoutExtension(escapedFullPath)).Append("\">").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" <HintPath>").Append(escapedFullPath).Append("</HintPath>").Append(k_WindowsNewline);
|
||||
projectBuilder.Append(" </Reference>").Append(k_WindowsNewline);
|
||||
}
|
||||
|
||||
public string ProjectFile(Assembly assembly)
|
||||
{
|
||||
var fileBuilder = new StringBuilder(assembly.name);
|
||||
fileBuilder.Append(".csproj");
|
||||
return Path.Combine(ProjectDirectory, fileBuilder.ToString());
|
||||
}
|
||||
|
||||
public string SolutionFile()
|
||||
{
|
||||
return Path.Combine(ProjectDirectory, $"{m_ProjectName}.sln");
|
||||
}
|
||||
|
||||
private void ProjectHeader(
|
||||
Assembly assembly,
|
||||
List<ResponseFileData> responseFilesData,
|
||||
StringBuilder builder
|
||||
)
|
||||
{
|
||||
var otherArguments = GetOtherArgumentsFromResponseFilesData(responseFilesData);
|
||||
GetProjectHeaderTemplate(
|
||||
builder,
|
||||
ProjectGuid(assembly.name),
|
||||
assembly.name,
|
||||
string.Join(";", new[] { "DEBUG", "TRACE" }.Concat(assembly.defines).Concat(responseFilesData.SelectMany(x => x.Defines)).Concat(EditorUserBuildSettings.activeScriptCompilationDefines).Distinct().ToArray()),
|
||||
GenerateLangVersion(otherArguments["langversion"], assembly),
|
||||
assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe),
|
||||
GenerateAnalyserItemGroup(RetrieveRoslynAnalyzers(assembly, otherArguments)),
|
||||
GenerateRoslynAnalyzerRulesetPath(assembly, otherArguments)
|
||||
);
|
||||
}
|
||||
|
||||
private static string GenerateLangVersion(IEnumerable<string> langVersionList, Assembly assembly)
|
||||
{
|
||||
var langVersion = langVersionList.FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(langVersion))
|
||||
return langVersion;
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
return assembly.compilerOptions.LanguageVersion;
|
||||
#else
|
||||
return k_TargetLanguageVersion;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static string GenerateRoslynAnalyzerRulesetPath(Assembly assembly, ILookup<string, string> otherResponseFilesData)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
return GenerateAnalyserRuleSet(otherResponseFilesData["ruleset"].Append(assembly.compilerOptions.RoslynAnalyzerRulesetPath).Where(a => !string.IsNullOrEmpty(a)).Distinct().Select(x => MakeAbsolutePath(x).NormalizePath()).ToArray());
|
||||
#else
|
||||
return GenerateAnalyserRuleSet(otherResponseFilesData["ruleset"].Distinct().Select(x => MakeAbsolutePath(x).NormalizePath()).ToArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
private static string GenerateAnalyserRuleSet(string[] paths)
|
||||
{
|
||||
return paths.Length == 0
|
||||
? string.Empty
|
||||
: $"{Environment.NewLine}{string.Join(Environment.NewLine, paths.Select(a => $" <CodeAnalysisRuleSet>{a}</CodeAnalysisRuleSet>"))}";
|
||||
}
|
||||
|
||||
private static string MakeAbsolutePath(string path)
|
||||
{
|
||||
return Path.IsPathRooted(path) ? path : Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
private static ILookup<string, string> GetOtherArgumentsFromResponseFilesData(List<ResponseFileData> responseFilesData)
|
||||
{
|
||||
var paths = responseFilesData.SelectMany(x =>
|
||||
{
|
||||
return x.OtherArguments.Where(a => a.StartsWith("/") || a.StartsWith("-"))
|
||||
.Select(b =>
|
||||
{
|
||||
var index = b.IndexOf(":", StringComparison.Ordinal);
|
||||
if (index > 0 && b.Length > index)
|
||||
{
|
||||
var key = b.Substring(1, index - 1);
|
||||
return new KeyValuePair<string, string>(key, b.Substring(index + 1));
|
||||
}
|
||||
|
||||
const string warnaserror = "warnaserror";
|
||||
return b.Substring(1).StartsWith(warnaserror)
|
||||
? new KeyValuePair<string, string>(warnaserror, b.Substring(warnaserror.Length + 1))
|
||||
: default;
|
||||
});
|
||||
})
|
||||
.Distinct()
|
||||
.ToLookup(o => o.Key, pair => pair.Value);
|
||||
return paths;
|
||||
}
|
||||
|
||||
string[] RetrieveRoslynAnalyzers(Assembly assembly, ILookup<string, string> otherArguments)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
return otherArguments["analyzer"].Concat(otherArguments["a"])
|
||||
.SelectMany(x=>x.Split(';'))
|
||||
#if !ROSLYN_ANALYZER_FIX
|
||||
.Concat(m_AssemblyNameProvider.GetRoslynAnalyzerPaths())
|
||||
#else
|
||||
.Concat(assembly.compilerOptions.RoslynAnalyzerDllPaths)
|
||||
#endif
|
||||
.Select(MakeAbsolutePath)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
#else
|
||||
return otherArguments["analyzer"].Concat(otherArguments["a"])
|
||||
.SelectMany(x=>x.Split(';'))
|
||||
.Distinct()
|
||||
.Select(MakeAbsolutePath)
|
||||
.ToArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
static string GenerateAnalyserItemGroup(string[] paths)
|
||||
{
|
||||
// <ItemGroup>
|
||||
// <Analyzer Include="..\packages\Comments_analyser.1.0.6626.21356\analyzers\dotnet\cs\Comments_analyser.dll" />
|
||||
// <Analyzer Include="..\packages\UnityEngineAnalyzer.1.0.0.0\analyzers\dotnet\cs\UnityEngineAnalyzer.dll" />
|
||||
// </ItemGroup>
|
||||
if (paths.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var analyserBuilder = new StringBuilder();
|
||||
analyserBuilder.Append(" <ItemGroup>").Append(k_WindowsNewline);
|
||||
foreach (var path in paths)
|
||||
{
|
||||
analyserBuilder.Append($" <Analyzer Include=\"{path.NormalizePath()}\" />").Append(k_WindowsNewline);
|
||||
}
|
||||
|
||||
analyserBuilder.Append(" </ItemGroup>").Append(k_WindowsNewline);
|
||||
return analyserBuilder.ToString();
|
||||
}
|
||||
|
||||
static string GetSolutionText()
|
||||
{
|
||||
return string.Join("\r\n", @"", @"Microsoft Visual Studio Solution File, Format Version {0}", @"# Visual Studio {1}", @"{2}", @"Global", @" GlobalSection(SolutionConfigurationPlatforms) = preSolution", @" Debug|Any CPU = Debug|Any CPU", @" EndGlobalSection", @" GlobalSection(ProjectConfigurationPlatforms) = postSolution", @"{3}", @" EndGlobalSection", @" GlobalSection(SolutionProperties) = preSolution", @" HideSolutionNode = FALSE", @" EndGlobalSection", @"EndGlobal", @"").Replace(" ", "\t");
|
||||
}
|
||||
|
||||
static string GetProjectFooterTemplate()
|
||||
{
|
||||
return string.Join("\r\n", @" </ItemGroup>", @" <Import Project=""$(MSBuildToolsPath)\Microsoft.CSharp.targets"" />", @" <!-- To modify your build process, add your task inside one of the targets below and uncomment it.", @" Other similar extension points exist, see Microsoft.Common.targets.", @" <Target Name=""BeforeBuild"">", @" </Target>", @" <Target Name=""AfterBuild"">", @" </Target>", @" -->", @"</Project>", @"");
|
||||
}
|
||||
|
||||
static void GetProjectHeaderTemplate(
|
||||
StringBuilder builder,
|
||||
string assemblyGUID,
|
||||
string assemblyName,
|
||||
string defines,
|
||||
string langVersion,
|
||||
bool allowUnsafe,
|
||||
string analyzerBlock,
|
||||
string rulesetBlock
|
||||
)
|
||||
{
|
||||
builder.Append(@"<?xml version=""1.0"" encoding=""utf-8""?>").Append(k_WindowsNewline);
|
||||
builder.Append(@"<Project ToolsVersion=""").Append(k_ToolsVersion).Append(@""" DefaultTargets=""Build"" xmlns=""").Append(MSBuildNamespaceUri).Append(@""">").Append(k_WindowsNewline);
|
||||
builder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <LangVersion>").Append(langVersion).Append("</LangVersion>").Append(k_WindowsNewline);
|
||||
builder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <Configuration Condition="" '$(Configuration)' == '' "">Debug</Configuration>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <Platform Condition="" '$(Platform)' == '' "">AnyCPU</Platform>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <ProductVersion>").Append(k_ProductVersion).Append("</ProductVersion>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <SchemaVersion>2.0</SchemaVersion>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <RootNamespace>").Append(EditorSettings.projectGenerationRootNamespace).Append("</RootNamespace>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <ProjectGuid>{").Append(assemblyGUID).Append("}</ProjectGuid>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <OutputType>Library</OutputType>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <AppDesignerFolder>Properties</AppDesignerFolder>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <AssemblyName>").Append(assemblyName).Append("</AssemblyName>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <TargetFrameworkVersion>").Append(k_TargetFrameworkVersion).Append("</TargetFrameworkVersion>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <FileAlignment>512</FileAlignment>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <BaseDirectory>").Append(k_BaseDirectory).Append("</BaseDirectory>").Append(k_WindowsNewline);
|
||||
builder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <PropertyGroup Condition="" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "">").Append(k_WindowsNewline);
|
||||
builder.Append(@" <DebugSymbols>true</DebugSymbols>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <DebugType>full</DebugType>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <Optimize>false</Optimize>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <OutputPath>Temp\bin\Debug\</OutputPath>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <DefineConstants>").Append(defines).Append("</DefineConstants>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <ErrorReport>prompt</ErrorReport>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <WarningLevel>4</WarningLevel>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <NoWarn>0169</NoWarn>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <AllowUnsafeBlocks>").Append(allowUnsafe).Append("</AllowUnsafeBlocks>").Append(k_WindowsNewline);
|
||||
builder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <NoConfig>true</NoConfig>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <NoStdLib>true</NoStdLib>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>").Append(k_WindowsNewline);
|
||||
builder.Append(@" <ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>").Append(k_WindowsNewline);
|
||||
builder.Append(rulesetBlock);
|
||||
builder.Append(@" </PropertyGroup>").Append(k_WindowsNewline);
|
||||
builder.Append(analyzerBlock);
|
||||
builder.Append(@" <ItemGroup>").Append(k_WindowsNewline);
|
||||
}
|
||||
|
||||
void SyncSolution(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
SyncSolutionFileIfNotChanged(SolutionFile(), SolutionText(assemblies));
|
||||
}
|
||||
|
||||
string SolutionText(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
var fileversion = "11.00";
|
||||
var vsversion = "2010";
|
||||
|
||||
var relevantAssemblies = RelevantAssembliesForMode(assemblies);
|
||||
string projectEntries = GetProjectEntries(relevantAssemblies);
|
||||
string projectConfigurations = string.Join(k_WindowsNewline, relevantAssemblies.Select(i => GetProjectActiveConfigurations(ProjectGuid(i.name))).ToArray());
|
||||
return string.Format(GetSolutionText(), fileversion, vsversion, projectEntries, projectConfigurations);
|
||||
}
|
||||
|
||||
static IEnumerable<Assembly> RelevantAssembliesForMode(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return assemblies.Where(i => ScriptingLanguage.CSharp == ScriptingLanguageFor(i));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Project("{guid}") = "MyProject", "MyProject.csproj", "{projectguid}"
|
||||
/// entry for each relevant language
|
||||
/// </summary>
|
||||
string GetProjectEntries(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
var projectEntries = assemblies.Select(i => string.Format(
|
||||
m_SolutionProjectEntryTemplate,
|
||||
SolutionGuid(i),
|
||||
i.name,
|
||||
Path.GetFileName(ProjectFile(i)),
|
||||
ProjectGuid(i.name)
|
||||
));
|
||||
|
||||
return string.Join(k_WindowsNewline, projectEntries.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the active configuration string for a given project guid
|
||||
/// </summary>
|
||||
string GetProjectActiveConfigurations(string projectGuid)
|
||||
{
|
||||
return string.Format(
|
||||
m_SolutionProjectConfigurationTemplate,
|
||||
projectGuid);
|
||||
}
|
||||
|
||||
static string SkipPathPrefix(string path, string prefix)
|
||||
{
|
||||
if (path.StartsWith($@"{prefix}{Path.DirectorySeparatorChar}"))
|
||||
return path.Substring(prefix.Length + 1);
|
||||
return path;
|
||||
}
|
||||
|
||||
string ProjectGuid(string assembly)
|
||||
{
|
||||
return m_GUIDProvider.ProjectGuid(m_ProjectName, assembly);
|
||||
}
|
||||
|
||||
string SolutionGuid(Assembly assembly)
|
||||
{
|
||||
return m_GUIDProvider.SolutionGuid(m_ProjectName, GetExtensionOfSourceFiles(assembly.sourceFiles));
|
||||
}
|
||||
|
||||
static string ProjectFooter()
|
||||
{
|
||||
return GetProjectFooterTemplate();
|
||||
}
|
||||
|
||||
static string GetProjectExtension()
|
||||
{
|
||||
return ".csproj";
|
||||
}
|
||||
|
||||
void WriteVSCodeSettingsFiles()
|
||||
{
|
||||
var vsCodeDirectory = Path.Combine(ProjectDirectory, ".vscode");
|
||||
|
||||
if (!m_FileIOProvider.Exists(vsCodeDirectory))
|
||||
m_FileIOProvider.CreateDirectory(vsCodeDirectory);
|
||||
|
||||
var vsCodeSettingsJson = Path.Combine(vsCodeDirectory, "settings.json");
|
||||
|
||||
if (!m_FileIOProvider.Exists(vsCodeSettingsJson))
|
||||
m_FileIOProvider.WriteAllText(vsCodeSettingsJson, k_SettingsJson);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SolutionGuidGenerator
|
||||
{
|
||||
static MD5 mD5 = MD5CryptoServiceProvider.Create();
|
||||
|
||||
public static string GuidForProject(string projectName)
|
||||
{
|
||||
return ComputeGuidHashFor(projectName + "salt");
|
||||
}
|
||||
|
||||
public static string GuidForSolution(string projectName, string sourceFileExtension)
|
||||
{
|
||||
return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
|
||||
}
|
||||
|
||||
static string ComputeGuidHashFor(string input)
|
||||
{
|
||||
var hash = mD5.ComputeHash(Encoding.Default.GetBytes(input));
|
||||
return new Guid(hash).ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 97d6c87381e3e51488b49f5891490b70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
[Flags]
|
||||
public enum ProjectGenerationFlag
|
||||
{
|
||||
None = 0,
|
||||
Embedded = 1,
|
||||
Local = 2,
|
||||
Registry = 4,
|
||||
Git = 8,
|
||||
BuiltIn = 16,
|
||||
Unknown = 32,
|
||||
PlayerAssemblies = 64,
|
||||
LocalTarBall = 128,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f239f506223a98f4e9b5dd3a9f80edea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,26 @@
|
|||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.VSCode.EditorTests")]
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
internal static class StringUtils
|
||||
{
|
||||
private const char WinSeparator = '\\';
|
||||
private const char UnixSeparator = '/';
|
||||
|
||||
public static string NormalizePath(this string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return path;
|
||||
|
||||
if (Path.DirectorySeparatorChar == WinSeparator)
|
||||
path = path.Replace(UnixSeparator, WinSeparator);
|
||||
if (Path.DirectorySeparatorChar == UnixSeparator)
|
||||
path = path.Replace(WinSeparator, UnixSeparator);
|
||||
|
||||
return path.Replace(string.Concat(WinSeparator, WinSeparator), WinSeparator.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee022071da7e4040bf2f949e15926ba1
|
||||
timeCreated: 1624968755
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "Unity.VSCode.Editor",
|
||||
"references": [],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "Unity",
|
||||
"expression": "2021.2.0a9",
|
||||
"define": "ROSLYN_ANALYZER_FIX"
|
||||
},
|
||||
{
|
||||
"name": "Unity",
|
||||
"expression": "[2021.1.2f1,2021.2.0a1]",
|
||||
"define": "ROSLYN_ANALYZER_FIX"
|
||||
},
|
||||
{
|
||||
"name": "Unity",
|
||||
"expression": "[2020.3.6f1,2021.0]",
|
||||
"define": "ROSLYN_ANALYZER_FIX"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8b845b123ab418448a8be2935fa804e0
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Unity.CodeEditor;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
public interface IDiscovery
|
||||
{
|
||||
CodeEditor.Installation[] PathCallback();
|
||||
}
|
||||
|
||||
public class VSCodeDiscovery : IDiscovery
|
||||
{
|
||||
List<CodeEditor.Installation> m_Installations;
|
||||
|
||||
public CodeEditor.Installation[] PathCallback()
|
||||
{
|
||||
if (m_Installations == null)
|
||||
{
|
||||
m_Installations = new List<CodeEditor.Installation>();
|
||||
FindInstallationPaths();
|
||||
}
|
||||
|
||||
return m_Installations.ToArray();
|
||||
}
|
||||
|
||||
void FindInstallationPaths()
|
||||
{
|
||||
string[] possiblePaths =
|
||||
#if UNITY_EDITOR_OSX
|
||||
{
|
||||
"/Applications/Visual Studio Code.app",
|
||||
"/Applications/Visual Studio Code - Insiders.app"
|
||||
};
|
||||
#elif UNITY_EDITOR_WIN
|
||||
{
|
||||
GetProgramFiles() + @"/Microsoft VS Code/bin/code.cmd",
|
||||
GetProgramFiles() + @"/Microsoft VS Code/Code.exe",
|
||||
GetProgramFiles() + @"/Microsoft VS Code Insiders/bin/code-insiders.cmd",
|
||||
GetProgramFiles() + @"/Microsoft VS Code Insiders/Code.exe",
|
||||
GetLocalAppData() + @"/Programs/Microsoft VS Code/bin/code.cmd",
|
||||
GetLocalAppData() + @"/Programs/Microsoft VS Code/Code.exe",
|
||||
GetLocalAppData() + @"/Programs/Microsoft VS Code Insiders/bin/code-insiders.cmd",
|
||||
GetLocalAppData() + @"/Programs/Microsoft VS Code Insiders/Code.exe",
|
||||
};
|
||||
#else
|
||||
{
|
||||
"/usr/bin/code",
|
||||
"/bin/code",
|
||||
"/usr/local/bin/code",
|
||||
"/var/lib/flatpak/exports/bin/com.visualstudio.code",
|
||||
"/snap/current/bin/code",
|
||||
"/snap/bin/code"
|
||||
};
|
||||
#endif
|
||||
var existingPaths = possiblePaths.Where(VSCodeExists).ToList();
|
||||
if (!existingPaths.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lcp = GetLongestCommonPrefix(existingPaths);
|
||||
switch (existingPaths.Count)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
var path = existingPaths.First();
|
||||
m_Installations = new List<CodeEditor.Installation>
|
||||
{
|
||||
new CodeEditor.Installation
|
||||
{
|
||||
Path = path,
|
||||
Name = path.Contains("Insiders")
|
||||
? "Visual Studio Code Insiders"
|
||||
: "Visual Studio Code"
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 2 when existingPaths.Any(path => !(path.Substring(lcp.Length).Contains("/") || path.Substring(lcp.Length).Contains("\\"))):
|
||||
{
|
||||
goto case 1;
|
||||
}
|
||||
default:
|
||||
{
|
||||
m_Installations = existingPaths.Select(path => new CodeEditor.Installation
|
||||
{
|
||||
Name = $"Visual Studio Code Insiders ({path.Substring(lcp.Length)})",
|
||||
Path = path
|
||||
}).ToList();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
static string GetProgramFiles()
|
||||
{
|
||||
return Environment.GetEnvironmentVariable("ProgramFiles")?.Replace("\\", "/");
|
||||
}
|
||||
|
||||
static string GetLocalAppData()
|
||||
{
|
||||
return Environment.GetEnvironmentVariable("LOCALAPPDATA")?.Replace("\\", "/");
|
||||
}
|
||||
#endif
|
||||
|
||||
static string GetLongestCommonPrefix(List<string> paths)
|
||||
{
|
||||
var baseLength = paths.First().Length;
|
||||
for (var pathIndex = 1; pathIndex < paths.Count; pathIndex++)
|
||||
{
|
||||
baseLength = Math.Min(baseLength, paths[pathIndex].Length);
|
||||
for (var i = 0; i < baseLength; i++)
|
||||
{
|
||||
if (paths[pathIndex][i] == paths[0][i]) continue;
|
||||
|
||||
baseLength = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return paths[0].Substring(0, baseLength);
|
||||
}
|
||||
|
||||
static bool VSCodeExists(string path)
|
||||
{
|
||||
#if UNITY_EDITOR_OSX
|
||||
return System.IO.Directory.Exists(path);
|
||||
#else
|
||||
return new FileInfo(path).Exists;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 380f7372e785c7d408552e2c760d269d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,282 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Unity.CodeEditor;
|
||||
|
||||
namespace VSCodeEditor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class VSCodeScriptEditor : IExternalCodeEditor
|
||||
{
|
||||
const string vscode_argument = "vscode_arguments";
|
||||
const string vscode_extension = "vscode_userExtensions";
|
||||
static readonly GUIContent k_ResetArguments = EditorGUIUtility.TrTextContent("Reset argument");
|
||||
string m_Arguments;
|
||||
|
||||
IDiscovery m_Discoverability;
|
||||
IGenerator m_ProjectGeneration;
|
||||
|
||||
static readonly string[] k_SupportedFileNames = { "code.exe", "visualstudiocode.app", "visualstudiocode-insiders.app", "vscode.app", "code.app", "code.cmd", "code-insiders.cmd", "code", "com.visualstudio.code" };
|
||||
|
||||
static bool IsOSX => Application.platform == RuntimePlatform.OSXEditor;
|
||||
|
||||
static string DefaultApp => EditorPrefs.GetString("kScriptsDefaultApp");
|
||||
|
||||
static string DefaultArgument { get; } = "\"$(ProjectPath)\" -g \"$(File)\":$(Line):$(Column)";
|
||||
|
||||
string Arguments
|
||||
{
|
||||
get => m_Arguments ?? (m_Arguments = EditorPrefs.GetString(vscode_argument, DefaultArgument));
|
||||
set
|
||||
{
|
||||
m_Arguments = value;
|
||||
EditorPrefs.SetString(vscode_argument, value);
|
||||
}
|
||||
}
|
||||
|
||||
static string[] defaultExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
var customExtensions = new[] { "json", "asmdef", "log" };
|
||||
return EditorSettings.projectGenerationBuiltinExtensions
|
||||
.Concat(EditorSettings.projectGenerationUserExtensions)
|
||||
.Concat(customExtensions)
|
||||
.Distinct().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
static string[] HandledExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
return HandledExtensionsString
|
||||
.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(s => s.TrimStart('.', '*'))
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
static string HandledExtensionsString
|
||||
{
|
||||
get => EditorPrefs.GetString(vscode_extension, string.Join(";", defaultExtensions));
|
||||
set => EditorPrefs.SetString(vscode_extension, value);
|
||||
}
|
||||
|
||||
public bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation)
|
||||
{
|
||||
var lowerCasePath = editorPath.ToLower();
|
||||
var filename = Path.GetFileName(lowerCasePath).Replace(" ", "");
|
||||
var installations = Installations;
|
||||
if (!k_SupportedFileNames.Contains(filename))
|
||||
{
|
||||
installation = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!installations.Any())
|
||||
{
|
||||
installation = new CodeEditor.Installation
|
||||
{
|
||||
Name = "Visual Studio Code",
|
||||
Path = editorPath
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
installation = installations.First(inst => inst.Path == editorPath);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
installation = new CodeEditor.Installation
|
||||
{
|
||||
Name = "Visual Studio Code",
|
||||
Path = editorPath
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
Arguments = EditorGUILayout.TextField("External Script Editor Args", Arguments);
|
||||
if (GUILayout.Button(k_ResetArguments, GUILayout.Width(120)))
|
||||
{
|
||||
Arguments = DefaultArgument;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Generate .csproj files for:");
|
||||
EditorGUI.indentLevel++;
|
||||
SettingsButton(ProjectGenerationFlag.Embedded, "Embedded packages", "");
|
||||
SettingsButton(ProjectGenerationFlag.Local, "Local packages", "");
|
||||
SettingsButton(ProjectGenerationFlag.Registry, "Registry packages", "");
|
||||
SettingsButton(ProjectGenerationFlag.Git, "Git packages", "");
|
||||
SettingsButton(ProjectGenerationFlag.BuiltIn, "Built-in packages", "");
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
SettingsButton(ProjectGenerationFlag.LocalTarBall, "Local tarball", "");
|
||||
#endif
|
||||
SettingsButton(ProjectGenerationFlag.Unknown, "Packages from unknown sources", "");
|
||||
RegenerateProjectFiles();
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
HandledExtensionsString = EditorGUILayout.TextField(new GUIContent("Extensions handled: "), HandledExtensionsString);
|
||||
}
|
||||
|
||||
void RegenerateProjectFiles()
|
||||
{
|
||||
var rect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(new GUILayoutOption[] { }));
|
||||
rect.width = 252;
|
||||
if (GUI.Button(rect, "Regenerate project files"))
|
||||
{
|
||||
m_ProjectGeneration.Sync();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsButton(ProjectGenerationFlag preference, string guiMessage, string toolTip)
|
||||
{
|
||||
var prevValue = m_ProjectGeneration.AssemblyNameProvider.ProjectGenerationFlag.HasFlag(preference);
|
||||
var newValue = EditorGUILayout.Toggle(new GUIContent(guiMessage, toolTip), prevValue);
|
||||
if (newValue != prevValue)
|
||||
{
|
||||
m_ProjectGeneration.AssemblyNameProvider.ToggleProjectGeneration(preference);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateIfDoesntExist()
|
||||
{
|
||||
if (!m_ProjectGeneration.SolutionExists())
|
||||
{
|
||||
m_ProjectGeneration.Sync();
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncIfNeeded(string[] addedFiles, string[] deletedFiles, string[] movedFiles, string[] movedFromFiles, string[] importedFiles)
|
||||
{
|
||||
(m_ProjectGeneration.AssemblyNameProvider as IPackageInfoCache)?.ResetPackageInfoCache();
|
||||
m_ProjectGeneration.SyncIfNeeded(addedFiles.Union(deletedFiles).Union(movedFiles).Union(movedFromFiles).ToList(), importedFiles);
|
||||
}
|
||||
|
||||
public void SyncAll()
|
||||
{
|
||||
(m_ProjectGeneration.AssemblyNameProvider as IPackageInfoCache)?.ResetPackageInfoCache();
|
||||
AssetDatabase.Refresh();
|
||||
m_ProjectGeneration.Sync();
|
||||
}
|
||||
|
||||
public bool OpenProject(string path, int line, int column)
|
||||
{
|
||||
if (path != "" && (!SupportsExtension(path) || !File.Exists(path))) // Assets - Open C# Project passes empty path here
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (line == -1)
|
||||
line = 1;
|
||||
if (column == -1)
|
||||
column = 0;
|
||||
|
||||
string arguments;
|
||||
if (Arguments != DefaultArgument)
|
||||
{
|
||||
arguments = m_ProjectGeneration.ProjectDirectory != path
|
||||
? CodeEditor.ParseArgument(Arguments, path, line, column)
|
||||
: m_ProjectGeneration.ProjectDirectory;
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = $@"""{m_ProjectGeneration.ProjectDirectory}""";
|
||||
if (m_ProjectGeneration.ProjectDirectory != path && path.Length != 0)
|
||||
{
|
||||
arguments += $@" -g ""{path}"":{line}:{column}";
|
||||
}
|
||||
}
|
||||
|
||||
if (IsOSX)
|
||||
{
|
||||
return OpenOSX(arguments);
|
||||
}
|
||||
|
||||
var app = DefaultApp;
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = app,
|
||||
Arguments = arguments,
|
||||
WindowStyle = app.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase) ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = true,
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool OpenOSX(string arguments)
|
||||
{
|
||||
var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "open",
|
||||
Arguments = $"-n \"{DefaultApp}\" --args {arguments}",
|
||||
UseShellExecute = true,
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SupportsExtension(string path)
|
||||
{
|
||||
var extension = Path.GetExtension(path);
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
return false;
|
||||
return HandledExtensions.Contains(extension.TrimStart('.'));
|
||||
}
|
||||
|
||||
public CodeEditor.Installation[] Installations => m_Discoverability.PathCallback();
|
||||
|
||||
public VSCodeScriptEditor(IDiscovery discovery, IGenerator projectGeneration)
|
||||
{
|
||||
m_Discoverability = discovery;
|
||||
m_ProjectGeneration = projectGeneration;
|
||||
}
|
||||
|
||||
static VSCodeScriptEditor()
|
||||
{
|
||||
var editor = new VSCodeScriptEditor(new VSCodeDiscovery(), new ProjectGeneration(Directory.GetParent(Application.dataPath).FullName));
|
||||
CodeEditor.Register(editor);
|
||||
|
||||
if (IsVSCodeInstallation(CodeEditor.CurrentEditorInstallation))
|
||||
{
|
||||
editor.CreateIfDoesntExist();
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsVSCodeInstallation(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var lowerCasePath = path.ToLower();
|
||||
var filename = Path
|
||||
.GetFileName(lowerCasePath.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar))
|
||||
.Replace(" ", "");
|
||||
return k_SupportedFileNames.Contains(filename);
|
||||
}
|
||||
|
||||
public void Initialize(string editorInstallationPath) { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac3f13489022aa34d861a0320a6917b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Unity Technologies
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9aabac5924106d4790d7b3a924ca34d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"ErrorExceptions": [
|
||||
{
|
||||
"ValidationTest": "API Validation",
|
||||
"ExceptionMessage": "Additions require a new minor or major version.",
|
||||
"PackageVersion": "1.2.3"
|
||||
}
|
||||
],
|
||||
"WarningExceptions": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc368c32d6432ff4bb374d520000749c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "com.unity.ide.vscode",
|
||||
"displayName": "Visual Studio Code Editor",
|
||||
"description": "Code editor integration for supporting Visual Studio Code as code editor for unity. Adds support for generating csproj files for intellisense purposes, auto discovery of installations, etc.",
|
||||
"version": "1.2.5",
|
||||
"unity": "2019.2",
|
||||
"unityRelease": "0a12",
|
||||
"relatedPackages": {
|
||||
"com.unity.ide.vscode.tests": "1.2.5"
|
||||
},
|
||||
"upmCi": {
|
||||
"footprint": "bc03b7bb076199fbe68649a647d0d32d98af6a0f"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/Unity-Technologies/com.unity.ide.vscode.git",
|
||||
"type": "git",
|
||||
"revision": "b0740c80bfc2440527c317109f7c3d9100132722"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ffc6271f08270b64ca0aae9c49235d81
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue