Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,79 @@
# Code Editor Package for Visual Studio Code
## [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.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4ddcdc3816429494a8bea67e973875f7
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fcb9be00baf924c4183fc0313e6185c5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58628227479c34542ac8c5193ccced84
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c779d3735d950f341ba35154e8b3234b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,124 @@
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 class AssemblyNameProvider : IAssemblyNameProvider
{
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();
}
public UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath)
{
return UnityEditor.PackageManager.PackageInfo.FindForAssetPath(assetPath);
}
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);
}
}
}

View file

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

View file

@ -0,0 +1,38 @@
using System.IO;
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);
}
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);
}
}
}

View file

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

View file

@ -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)
}
}
}

View file

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

View file

@ -0,0 +1,777 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
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,
""**/.gitignore"":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 }
};
string m_SolutionProjectEntryTemplate = string.Join("\r\n", @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""", @"EndProject").Replace(" ", "\t");
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 = new string[0];
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";
const string k_TargetLanguageVersion = "latest";
public ProjectGeneration(string tempDirectory)
: this(tempDirectory, new AssemblyNameProvider(), new FileIOProvider(), new GUIDProvider()) { }
public ProjectGeneration(string tempDirectory, IAssemblyNameProvider assemblyNameProvider, IFileIO fileIO, IGUIDGenerator guidGenerator)
{
ProjectDirectory = tempDirectory.Replace('\\', '/');
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();
// Don't sync if we haven't synced before
if (SolutionExists() && HasFilesBeenModified(affectedFiles, reimportedFiles))
{
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));
var assemblyNames = new HashSet<string>(allProjectAssemblies.Select(assembly => Path.GetFileName(assembly.outputPath)));
foreach (var assembly in allProjectAssemblies)
{
if (!affectedAndReimported.Contains(assembly.name))
continue;
SyncProject(assembly, allAssetProjectParts, ParseResponseFileData(assembly), assemblyNames);
}
Profiler.EndSample();
return true;
}
Profiler.EndSample();
return false;
}
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);
}
public void Sync()
{
SetupProjectSupportedExtensions();
GenerateAndWriteSolutionAndProjects();
}
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);
var allAssetProjectParts = GenerateAllAssetProjectParts();
SyncSolution(assemblies);
var allProjectAssemblies = RelevantAssembliesForMode(assemblies).ToList();
var assemblyNames = new HashSet<string>(allProjectAssemblies.Select(assembly => Path.GetFileName(assembly.outputPath)));
foreach (Assembly assembly in allProjectAssemblies)
{
var responseFileData = ParseResponseFileData(assembly);
SyncProject(assembly, allAssetProjectParts, responseFileData, assemblyNames);
}
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(EscapedRelativePathFor(asset)).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,
HashSet<string> assemblyNames)
{
SyncProjectFileIfNotChanged(ProjectFile(assembly), ProjectText(assembly, allAssetsProjectParts, responseFilesData, assemblyNames, GetAllRoslynAnalyzerPaths().ToArray()));
}
private IEnumerable<string> GetAllRoslynAnalyzerPaths()
{
return m_AssemblyNameProvider.GetRoslynAnalyzerPaths();
}
void SyncProjectFileIfNotChanged(string path, string newContents)
{
SyncFileIfNotChanged(path, newContents);
}
void SyncSolutionFileIfNotChanged(string path, string newContents)
{
SyncFileIfNotChanged(path, newContents);
}
void SyncFileIfNotChanged(string filename, string newContents)
{
if (m_FileIOProvider.Exists(filename))
{
var currentContents = m_FileIOProvider.ReadAllText(filename);
if (currentContents == newContents)
{
return;
}
}
m_FileIOProvider.WriteAllText(filename, newContents);
}
string ProjectText(
Assembly assembly,
Dictionary<string, string> allAssetsProjectParts,
List<ResponseFileData> responseFilesData,
HashSet<string> assemblyNames,
string[] roslynAnalyzerDllPaths)
{
var projectBuilder = new StringBuilder();
ProjectHeader(assembly, responseFilesData, roslynAnalyzerDllPaths, projectBuilder);
var references = new List<string>();
foreach (string file in assembly.sourceFiles)
{
if (!HasValidExtension(file))
continue;
var extension = Path.GetExtension(file).ToLower();
var fullFile = EscapedRelativePathFor(file);
if (".dll" != extension)
{
projectBuilder.Append(" <Compile Include=\"").Append(fullFile).Append("\" />").Append(k_WindowsNewline);
}
else
{
references.Add(fullFile);
}
}
// 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)
.Except(roslynAnalyzerDllPaths);
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)))
{
var referencedProject = reference.outputPath;
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)
{
//replace \ with / and \\ with /
var escapedFullPath = SecurityElement.Escape(fullReference);
escapedFullPath = escapedFullPath.Replace("\\\\", "/");
escapedFullPath = escapedFullPath.Replace("\\", "/");
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");
}
void ProjectHeader(
Assembly assembly,
List<ResponseFileData> responseFilesData,
string[] roslynAnalyzerDllPaths,
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()),
assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe),
GenerateAnalyserItemGroup(otherArguments["analyzer"].Concat(otherArguments["a"])
.SelectMany(x => x.Split(';'))
.Concat(roslynAnalyzerDllPaths)
.Distinct()
.ToArray()));
}
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";
if (b.Substring(1).StartsWith(warnaserror))
{
return new KeyValuePair<string, string>(warnaserror, b.Substring(warnaserror.Length + 1));
}
return default;
});
})
.Distinct()
.ToLookup(o => o.Key, pair => pair.Value);
return paths;
}
private 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.Any())
return string.Empty;
var analyserBuilder = new StringBuilder();
analyserBuilder.Append(" <ItemGroup>").Append(k_WindowsNewline);
foreach (var path in paths)
{
analyserBuilder.Append($" <Analyzer Include=\"{path}\" />").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,
bool allowUnsafe,
string analyzerBlock
)
{
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(k_TargetLanguageVersion).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(@" </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);
}
string EscapedRelativePathFor(string file)
{
var projectDir = ProjectDirectory.Replace('/', '\\');
file = file.Replace('/', '\\');
var path = SkipPathPrefix(file, projectDir);
var packageInfo = m_AssemblyNameProvider.FindForAssetPath(path.Replace('\\', '/'));
if (packageInfo != null)
{
// We have to normalize the path, because the PackageManagerRemapper assumes
// dir seperators will be os specific.
var absolutePath = Path.GetFullPath(NormalizePath(path)).Replace('/', '\\');
path = SkipPathPrefix(absolutePath, projectDir);
}
return SecurityElement.Escape(path);
}
static string SkipPathPrefix(string path, string prefix)
{
if (path.StartsWith($@"{prefix}\"))
return path.Substring(prefix.Length + 1);
return path;
}
static string NormalizePath(string path)
{
if (Path.DirectorySeparatorChar == '\\')
return path.Replace('/', Path.DirectorySeparatorChar);
return path.Replace('\\', Path.DirectorySeparatorChar);
}
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)
{
if (sourceFileExtension.ToLower() == "cs")
// GUID for a C# class library: http://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs
return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
return ComputeGuidHashFor(projectName);
}
static string ComputeGuidHashFor(string input)
{
var hash = mD5.ComputeHash(Encoding.Default.GetBytes(input));
return new Guid(hash).ToString();
}
}
}

View file

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

View file

@ -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,
}
}

View file

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

View file

@ -0,0 +1,9 @@
{
"name": "Unity.VSCode.Editor",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": []
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8b845b123ab418448a8be2935fa804e0
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,137 @@
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"
};
#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
}
}
}

View file

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

View file

@ -0,0 +1,280 @@
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.SyncIfNeeded(addedFiles.Union(deletedFiles).Union(movedFiles).Union(movedFromFiles).ToList(), importedFiles);
}
public void SyncAll()
{
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) { }
}
}

View file

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

View file

@ -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.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c9aabac5924106d4790d7b3a924ca34d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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.3",
"unity": "2019.2",
"unityRelease": "0a12",
"relatedPackages": {
"com.unity.ide.vscode.tests": "1.2.3"
},
"upmCi": {
"footprint": "ab99793db10bad3c377fc6971b0b21989002c495"
},
"repository": {
"url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.vscode.git",
"type": "git",
"revision": "b5ec9b38109e52b1b26597d521e4df75e042ebb9"
}
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ffc6271f08270b64ca0aae9c49235d81
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: