diff --git a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs index b42631bd..07b01719 100644 --- a/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs +++ b/Assets/Fungus/Scripts/Editor/FlowchartWindow.cs @@ -312,7 +312,7 @@ namespace Fungus.EditorUtils block._NodeRect = tempRect; - Undo.RecordObject(block, "Node Position " + i); + Undo.RecordObject(block, "Node Position"); tempRect.x = newPos.x; tempRect.y = newPos.y; @@ -464,7 +464,8 @@ namespace Fungus.EditorUtils protected virtual void HandleSelectionBox(Flowchart flowchart) { - if (Event.current.button == 0 && Event.current.modifiers != EventModifiers.Alt) + if (Event.current.button == 0 && Event.current.modifiers != EventModifiers.Alt && + !(UnityEditor.Tools.current == Tool.View && UnityEditor.Tools.viewTool == ViewTool.Pan)) { switch (Event.current.type) { @@ -578,7 +579,7 @@ namespace Fungus.EditorUtils zoom = true; } - if (zoom) + if (zoom && selectionBox.size == Vector2.zero) { flowchart.Zoom -= Event.current.delta.y * 0.01f; flowchart.Zoom = Mathf.Clamp(flowchart.Zoom, minZoomValue, maxZoomValue); diff --git a/Assets/New Animator Controller.controller b/Assets/New Animator Controller.controller new file mode 100644 index 00000000..aea327a4 --- /dev/null +++ b/Assets/New Animator Controller.controller @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: New Animator Controller + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: [] + m_MultiThreadedStateMachine: 1 diff --git a/Assets/New Animator Controller.controller.meta b/Assets/New Animator Controller.controller.meta new file mode 100644 index 00000000..f5a307f3 --- /dev/null +++ b/Assets/New Animator Controller.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a5dab9bd0111248c897b67ddef5ee675 +timeCreated: 1478062001 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode.meta b/Assets/VSCode.meta new file mode 100644 index 00000000..409047f1 --- /dev/null +++ b/Assets/VSCode.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f60a9bceb41e41d292fc16cc056d6d5 +folderAsset: yes +timeCreated: 1477762468 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/HOWTO.pdf b/Assets/VSCode/HOWTO.pdf new file mode 100644 index 00000000..a94dd3f2 Binary files /dev/null and b/Assets/VSCode/HOWTO.pdf differ diff --git a/Assets/VSCode/HOWTO.pdf.meta b/Assets/VSCode/HOWTO.pdf.meta new file mode 100644 index 00000000..53b138f8 --- /dev/null +++ b/Assets/VSCode/HOWTO.pdf.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9519be3d5789b4c5ca14e07b375d6884 +timeCreated: 1444651605 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/LICENSE b/Assets/VSCode/LICENSE new file mode 100644 index 00000000..13b5259a --- /dev/null +++ b/Assets/VSCode/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 dotBunny Inc. + +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. + diff --git a/Assets/VSCode/LICENSE.meta b/Assets/VSCode/LICENSE.meta new file mode 100644 index 00000000..a24433e2 --- /dev/null +++ b/Assets/VSCode/LICENSE.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edc517f07ba5e4cf9984f8753de7388f +timeCreated: 1444651605 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/Plugins.meta b/Assets/VSCode/Plugins.meta new file mode 100644 index 00000000..71559cf3 --- /dev/null +++ b/Assets/VSCode/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0d0aa2ea87e4246f3b7fd58b757ff82c +folderAsset: yes +timeCreated: 1444652904 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/Plugins/Editor.meta b/Assets/VSCode/Plugins/Editor.meta new file mode 100644 index 00000000..b44f6815 --- /dev/null +++ b/Assets/VSCode/Plugins/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 47b6573edc17b4b19b6f06515ff01748 +folderAsset: yes +timeCreated: 1444652910 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/Plugins/Editor/VSCode.cs b/Assets/VSCode/Plugins/Editor/VSCode.cs new file mode 100644 index 00000000..cbd6fa9f --- /dev/null +++ b/Assets/VSCode/Plugins/Editor/VSCode.cs @@ -0,0 +1,1304 @@ +/* + * Unity VSCode Support + * + * Seamless support for Microsoft Visual Studio Code in Unity + * + * Version: + * 2.7 + * + * Authors: + * Matthew Davey + */ +namespace dotBunny.Unity +{ + using System; + using System.IO; + using System.Text.RegularExpressions; + using UnityEditor; + using UnityEngine; + + [InitializeOnLoad] + public static class VSCode + { + /// + /// Current Version Number + /// + public const float Version = 2.7f; + + /// + /// Current Version Code + /// + public const string VersionCode = "-RELEASE"; + + /// + /// Download URL for Unity Debbuger + /// + public const string UnityDebuggerURL = "https://raw.githubusercontent.com/dotBunny/VSCode-Test/master/Downloads/unity-debug-101.vsix"; + + #region Properties + + /// + /// Path to VSCode executable + public static string CodePath + { + get + { + string current = EditorPrefs.GetString("VSCode_CodePath", ""); + if(current == "" || !VSCodeExists(current)) + { + //Value not set, set to "" or current path is invalid, try to autodetect it + //If autodetect fails, a error will be printed and the default value set + EditorPrefs.SetString("VSCode_CodePath", AutodetectCodePath()); + //If its not installed or the install folder isn't a "normal" one, + //AutodetectCodePath will print a error message to the Unity Console + } + return EditorPrefs.GetString("VSCode_CodePath", current); + } + set + { + EditorPrefs.SetString("VSCode_CodePath", value); + } + } + + /// + /// Get Program Files Path + /// + /// The platforms "Program Files" path. + static string ProgramFilesx86() + { + if( 8 == IntPtr.Size + || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")))) + { + return Environment.GetEnvironmentVariable("ProgramFiles(x86)"); + } + + return Environment.GetEnvironmentVariable("ProgramFiles"); + } + + + /// + /// Should debug information be displayed in the Unity terminal? + /// + public static bool Debug + { + get + { + return EditorPrefs.GetBool("VSCode_Debug", false); + } + set + { + EditorPrefs.SetBool("VSCode_Debug", value); + } + } + + /// + /// Is the Visual Studio Code Integration Enabled? + /// + /// + /// We do not want to automatically turn it on, for in larger projects not everyone is using VSCode + /// + public static bool Enabled + { + get + { + return EditorPrefs.GetBool("VSCode_Enabled", false); + } + set + { + // When turning the plugin on, we should remove all the previous project files + if (!Enabled && value) + { + ClearProjectFiles(); + } + EditorPrefs.SetBool("VSCode_Enabled", value); + } + } + public static bool UseUnityDebugger + { + get + { + return EditorPrefs.GetBool("VSCode_UseUnityDebugger", false); + } + set + { + if ( value != UseUnityDebugger ) { + + // Set value + EditorPrefs.SetBool("VSCode_UseUnityDebugger", value); + + // Do not write the launch JSON file because the debugger uses its own + if ( value ) { + WriteLaunchFile = false; + } + + // Update launch file + UpdateLaunchFile(); + } + } + } + + /// + /// Should the launch.json file be written? + /// + /// + /// Useful to disable if someone has their own custom one rigged up + /// + public static bool WriteLaunchFile + { + get + { + return EditorPrefs.GetBool("VSCode_WriteLaunchFile", true); + } + set + { + EditorPrefs.SetBool("VSCode_WriteLaunchFile", value); + } + } + + /// + /// Should the plugin automatically update itself. + /// + static bool AutomaticUpdates + { + get + { + return EditorPrefs.GetBool("VSCode_AutomaticUpdates", false); + } + set + { + EditorPrefs.SetBool("VSCode_AutomaticUpdates", value); + } + } + + static float GitHubVersion + { + get + { + return EditorPrefs.GetFloat("VSCode_GitHubVersion", Version); + } + set + { + EditorPrefs.SetFloat("VSCode_GitHubVersion", value); + } + } + + /// + /// When was the last time that the plugin was updated? + /// + static DateTime LastUpdate + { + get + { + // Feature creation date. + DateTime lastTime = new DateTime(2015, 10, 8); + + if (EditorPrefs.HasKey("VSCode_LastUpdate")) + { + DateTime.TryParse(EditorPrefs.GetString("VSCode_LastUpdate"), out lastTime); + } + return lastTime; + } + set + { + EditorPrefs.SetString("VSCode_LastUpdate", value.ToString()); + } + } + + /// + /// Quick reference to the VSCode launch settings file + /// + static string LaunchPath + { + get + { + return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "launch.json"; + } + } + + /// + /// The full path to the project + /// + static string ProjectPath + { + get + { + return System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath); + } + } + + /// + /// Should the script editor be reverted when quiting Unity. + /// + /// + /// Useful for environments where you do not use VSCode for everything. + /// + static bool RevertExternalScriptEditorOnExit + { + get + { + return EditorPrefs.GetBool("VSCode_RevertScriptEditorOnExit", true); + } + set + { + EditorPrefs.SetBool("VSCode_RevertScriptEditorOnExit", value); + } + } + + /// + /// Quick reference to the VSCode settings folder + /// + static string SettingsFolder + { + get + { + return ProjectPath + System.IO.Path.DirectorySeparatorChar + ".vscode"; + } + } + + static string SettingsPath + { + + get + { + return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "settings.json"; + } + } + + static int UpdateTime + { + get + { + return EditorPrefs.GetInt("VSCode_UpdateTime", 7); + } + set + { + EditorPrefs.SetInt("VSCode_UpdateTime", value); + } + } + + #endregion + + /// + /// Integration Constructor + /// + static VSCode() + { + if (Enabled) + { + UpdateUnityPreferences(true); + UpdateLaunchFile(); + + // Add Update Check + DateTime targetDate = LastUpdate.AddDays(UpdateTime); + if (DateTime.Now >= targetDate && AutomaticUpdates) + { + CheckForUpdate(); + } + } + + // Event for when script is reloaded + System.AppDomain.CurrentDomain.DomainUnload += System_AppDomain_CurrentDomain_DomainUnload; + } + static void System_AppDomain_CurrentDomain_DomainUnload(object sender, System.EventArgs e) + { + if (Enabled && RevertExternalScriptEditorOnExit) + { + UpdateUnityPreferences(false); + } + } + + + #region Public Members + + /// + /// Force Unity To Write Project File + /// + /// + /// Reflection! + /// + public static void SyncSolution() + { + System.Type T = System.Type.GetType("UnityEditor.SyncVS,UnityEditor"); + System.Reflection.MethodInfo SyncSolution = T.GetMethod("SyncSolution", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + SyncSolution.Invoke(null, null); + + } + + /// + /// Update the solution files so that they work with VS Code + /// + public static void UpdateSolution() + { + // No need to process if we are not enabled + if (!VSCode.Enabled) + { + return; + } + + if (VSCode.Debug) + { + UnityEngine.Debug.Log("[VSCode] Updating Solution & Project Files"); + } + + var currentDirectory = Directory.GetCurrentDirectory(); + var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln"); + var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj"); + + foreach (var filePath in solutionFiles) + { + string content = File.ReadAllText(filePath); + content = ScrubSolutionContent(content); + + File.WriteAllText(filePath, content); + + ScrubFile(filePath); + } + + foreach (var filePath in projectFiles) + { + string content = File.ReadAllText(filePath); + content = ScrubProjectContent(content); + + File.WriteAllText(filePath, content); + + ScrubFile(filePath); + } + + } + + #endregion + + #region Private Members + + /// + /// Try to find automatically the installation of VSCode + /// + static string AutodetectCodePath() + { + string[] possiblePaths = +#if UNITY_EDITOR_OSX + { + "/Applications/Visual Studio Code.app", + "/Applications/Visual Studio Code - Insiders.app" + }; +#elif UNITY_EDITOR_WIN + { + ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code" + + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code.cmd", + ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code Insiders" + + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code-insiders.cmd" + }; +#else + { + "/usr/bin/code", + "/bin/code", + "/usr/local/bin/code" + }; +#endif + for(int i = 0; i < possiblePaths.Length; i++) + { + if(VSCodeExists(possiblePaths[i])) + { + return possiblePaths[i]; + } + } + PrintNotFound(possiblePaths[0]); + return possiblePaths[0]; //returns the default one, printing a warning message 'executable not found' + } + + /// + /// Call VSCode with arguments + /// + static void CallVSCode(string args) + { + System.Diagnostics.Process proc = new System.Diagnostics.Process(); + if(!VSCodeExists(CodePath)) + { + PrintNotFound(CodePath); + return; + } + +#if UNITY_EDITOR_OSX + proc.StartInfo.FileName = "open"; + + // Check the path to see if there is "Insiders" + if (CodePath.Contains("Insiders")) + { + proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCodeInsiders\" --args " + args.Replace(@"\", @"\\"); + } + else + { + proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCode\" --args " + args.Replace(@"\", @"\\"); + } + + proc.StartInfo.UseShellExecute = false; +#elif UNITY_EDITOR_WIN + proc.StartInfo.FileName = CodePath; + proc.StartInfo.Arguments = args; + proc.StartInfo.UseShellExecute = false; +#else + proc.StartInfo.FileName = CodePath; + proc.StartInfo.Arguments = args.Replace(@"\", @"\\"); + proc.StartInfo.UseShellExecute = false; +#endif + proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; + proc.StartInfo.CreateNoWindow = true; + proc.StartInfo.RedirectStandardOutput = true; + proc.Start(); + } + + /// + /// Check for Updates with GitHub + /// + static void CheckForUpdate() + { + var fileContent = string.Empty; + + EditorUtility.DisplayProgressBar("VSCode", "Checking for updates ...", 0.5f); + + // Because were not a runtime framework, lets just use the simplest way of doing this + try + { + using (var webClient = new System.Net.WebClient()) + { + fileContent = webClient.DownloadString("https://raw.githubusercontent.com/dotBunny/VSCode/master/Plugins/Editor/VSCode.cs"); + } + } + catch (Exception e) + { + if (Debug) + { + UnityEngine.Debug.Log("[VSCode] " + e.Message); + + } + + // Don't go any further if there is an error + return; + } + finally + { + EditorUtility.ClearProgressBar(); + } + + // Set the last update time + LastUpdate = DateTime.Now; + + // Fix for oddity in downlo + if (fileContent.Substring(0, 2) != "/*") + { + int startPosition = fileContent.IndexOf("/*", StringComparison.CurrentCultureIgnoreCase); + + // Jump over junk characters + fileContent = fileContent.Substring(startPosition); + } + + string[] fileExploded = fileContent.Split('\n'); + if (fileExploded.Length > 7) + { + float github = Version; + if (float.TryParse(fileExploded[6].Replace("*", "").Trim(), out github)) + { + GitHubVersion = github; + } + + + if (github > Version) + { + var GUIDs = AssetDatabase.FindAssets("t:Script VSCode"); + var path = Application.dataPath.Substring(0, Application.dataPath.Length - "/Assets".Length) + System.IO.Path.DirectorySeparatorChar + + AssetDatabase.GUIDToAssetPath(GUIDs[0]).Replace('/', System.IO.Path.DirectorySeparatorChar); + + if (EditorUtility.DisplayDialog("VSCode Update", "A newer version of the VSCode plugin is available, would you like to update your version?", "Yes", "No")) + { + // Always make sure the file is writable + System.IO.FileInfo fileInfo = new System.IO.FileInfo(path); + fileInfo.IsReadOnly = false; + + // Write update file + File.WriteAllText(path, fileContent); + + // Force update on text file + AssetDatabase.ImportAsset(AssetDatabase.GUIDToAssetPath(GUIDs[0]), ImportAssetOptions.ForceUpdate); + } + + } + } + } + + /// + /// Clear out any existing project files and lingering stuff that might cause problems + /// + static void ClearProjectFiles() + { + var currentDirectory = Directory.GetCurrentDirectory(); + var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln"); + var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj"); + var unityProjectFiles = Directory.GetFiles(currentDirectory, "*.unityproj"); + + foreach (string solutionFile in solutionFiles) + { + File.Delete(solutionFile); + } + foreach (string projectFile in projectFiles) + { + File.Delete(projectFile); + } + foreach (string unityProjectFile in unityProjectFiles) + { + File.Delete(unityProjectFile); + } + + // Replace with our clean files (only in Unity 5) +#if !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6 && !UNITY_4_7 + SyncSolution(); +#endif + } + + /// + /// Force Unity Preferences Window To Read From Settings + /// + static void FixUnityPreferences() + { + // I want that window, please and thank you + System.Type T = System.Type.GetType("UnityEditor.PreferencesWindow,UnityEditor"); + + if (EditorWindow.focusedWindow == null) + return; + + // Only run this when the editor window is visible (cause its what screwed us up) + if (EditorWindow.focusedWindow.GetType() == T) + { + var window = EditorWindow.GetWindow(T, true, "Unity Preferences"); + + + if (window == null) + { + if (Debug) + { + UnityEngine.Debug.Log("[VSCode] No Preferences Window Found (really?)"); + } + return; + } + + var invokerType = window.GetType(); + var invokerMethod = invokerType.GetMethod("ReadPreferences", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + if (invokerMethod != null) + { + invokerMethod.Invoke(window, null); + } + else if (Debug) + { + UnityEngine.Debug.Log("[VSCode] No Reflection Method Found For Preferences"); + } + } + } + + /// + /// Determine what port Unity is listening for on Windows + /// + static int GetDebugPort() + { +#if UNITY_EDITOR_WIN + System.Diagnostics.Process process = new System.Diagnostics.Process(); + process.StartInfo.FileName = "netstat"; + process.StartInfo.Arguments = "-a -n -o -p TCP"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.Start(); + + string output = process.StandardOutput.ReadToEnd(); + string[] lines = output.Split('\n'); + + process.WaitForExit(); + + foreach (string line in lines) + { + string[] tokens = Regex.Split(line, "\\s+"); + if (tokens.Length > 4) + { + int test = -1; + int.TryParse(tokens[5], out test); + + if (test > 1023) + { + try + { + var p = System.Diagnostics.Process.GetProcessById(test); + if (p.ProcessName == "Unity") + { + return test; + } + } + catch + { + + } + } + } + } +#else + System.Diagnostics.Process process = new System.Diagnostics.Process(); + process.StartInfo.FileName = "lsof"; + process.StartInfo.Arguments = "-c /^Unity$/ -i 4tcp -a"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.Start(); + + // Not thread safe (yet!) + string output = process.StandardOutput.ReadToEnd(); + string[] lines = output.Split('\n'); + + process.WaitForExit(); + + foreach (string line in lines) + { + int port = -1; + if (line.StartsWith("Unity")) + { + string[] portions = line.Split(new string[] { "TCP *:" }, System.StringSplitOptions.None); + if (portions.Length >= 2) + { + Regex digitsOnly = new Regex(@"[^\d]"); + string cleanPort = digitsOnly.Replace(portions[1], ""); + if (int.TryParse(cleanPort, out port)) + { + if (port > -1) + { + return port; + } + } + } + } + } +#endif + return -1; + } + + /// + /// Manually install the original Unity Debuger + /// + /// + /// This should auto update to the latest. + /// + static void InstallUnityDebugger() + { + EditorUtility.DisplayProgressBar("VSCode", "Downloading Unity Debugger ...", 0.1f); + byte[] fileContent; + + try + { + using (var webClient = new System.Net.WebClient()) + { + fileContent = webClient.DownloadData(UnityDebuggerURL); + } + } + catch (Exception e) + { + if (Debug) + { + UnityEngine.Debug.Log("[VSCode] " + e.Message); + } + // Don't go any further if there is an error + return; + } + finally + { + EditorUtility.ClearProgressBar(); + } + + // Do we have a file to install? + if ( fileContent != null ) { + string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".vsix"; + File.WriteAllBytes(fileName, fileContent); + + CallVSCode(fileName); + } + + } + + // HACK: This is in until Unity can figure out why MD keeps opening even though a different program is selected. + [MenuItem("Assets/Open C# Project In Code", false, 1000)] + static void MenuOpenProject() + { + // Force the project files to be sync + SyncSolution(); + + // Load Project + CallVSCode("\"" + ProjectPath + "\" -r"); + } + + /// + /// Print a error message to the Unity Console about not finding the code executable + /// + static void PrintNotFound(string path) + { + UnityEngine.Debug.LogError("[VSCode] Code executable in '" + path + "' not found. Check your" + + "Visual Studio Code installation and insert the correct path in the Preferences menu."); + } + + [MenuItem("Assets/Open C# Project In Code", true, 1000)] + static bool ValidateMenuOpenProject() + { + return Enabled; + } + + /// + /// VS Code Integration Preferences Item + /// + /// + /// Contains all 3 toggles: Enable/Disable; Debug On/Off; Writing Launch File On/Off + /// + [PreferenceItem("VSCode")] + static void VSCodePreferencesItem() + { + if (EditorApplication.isCompiling) + { + EditorGUILayout.HelpBox("Please wait for Unity to finish compiling. \nIf the window doesn't refresh, simply click on the window or move it around to cause a repaint to happen.", MessageType.Warning); + return; + } + EditorGUILayout.BeginVertical(); + + EditorGUILayout.HelpBox("Support development of this plugin, follow @reapazor and @dotbunny on Twitter.", MessageType.Info); + + EditorGUI.BeginChangeCheck(); + +// Need the VS Code executable + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("VS Code Path", GUILayout.Width(75)); +#if UNITY_5_3_OR_NEWER + CodePath = EditorGUILayout.DelayedTextField(CodePath, GUILayout.ExpandWidth(true)); +#else + CodePath = EditorGUILayout.TextField(CodePath, GUILayout.ExpandWidth(true)); +#endif + GUI.SetNextControlName("PathSetButton"); + if(GUILayout.Button("...", GUILayout.Height(14), GUILayout.Width(20))) + { + GUI.FocusControl("PathSetButton"); + string path = EditorUtility.OpenFilePanel( "Visual Studio Code Executable", "", "" ); + if( path.Length != 0 && File.Exists(path) || Directory.Exists(path)) + { + CodePath = path; + } + } + EditorGUILayout.EndHorizontal(); + EditorGUILayout.Space(); + + Enabled = EditorGUILayout.Toggle(new GUIContent("Enable Integration", "Should the integration work its magic for you?"), Enabled); + + UseUnityDebugger = EditorGUILayout.Toggle(new GUIContent("Use Unity Debugger", "Should the integration integrate with Unity's VSCode Extension (must be installed)."), UseUnityDebugger); + + EditorGUILayout.Space(); + RevertExternalScriptEditorOnExit = EditorGUILayout.Toggle(new GUIContent("Revert Script Editor On Unload", "Should the external script editor setting be reverted to its previous setting on project unload? This is useful if you do not use Code with all your projects."),RevertExternalScriptEditorOnExit); + + Debug = EditorGUILayout.Toggle(new GUIContent("Output Messages To Console", "Should informational messages be sent to Unity's Console?"), Debug); + + WriteLaunchFile = EditorGUILayout.Toggle(new GUIContent("Always Write Launch File", "Always write the launch.json settings when entering play mode?"), WriteLaunchFile); + + EditorGUILayout.Space(); + + AutomaticUpdates = EditorGUILayout.Toggle(new GUIContent("Automatic Updates", "Should the plugin automatically update itself?"), AutomaticUpdates); + + UpdateTime = EditorGUILayout.IntSlider(new GUIContent("Update Timer (Days)", "After how many days should updates be checked for?"), UpdateTime, 1, 31); + + EditorGUILayout.Space(); + EditorGUILayout.Space(); + + if (EditorGUI.EndChangeCheck()) + { + UpdateUnityPreferences(Enabled); + + // TODO: Force Unity To Reload Preferences + // This seems to be a hick up / issue + if (VSCode.Debug) + { + if (Enabled) + { + UnityEngine.Debug.Log("[VSCode] Integration Enabled"); + } + else + { + UnityEngine.Debug.Log("[VSCode] Integration Disabled"); + } + } + } + + if (GUILayout.Button(new GUIContent("Force Update", "Check for updates to the plugin, right NOW!"))) + { + CheckForUpdate(); + EditorGUILayout.EndVertical(); + return; + } + if (GUILayout.Button(new GUIContent("Write Workspace Settings", "Output a default set of workspace settings for VSCode to use, ignoring many different types of files."))) + { + WriteWorkspaceSettings(); + EditorGUILayout.EndVertical(); + return; + } + EditorGUILayout.Space(); + + if (UseUnityDebugger) + { + EditorGUILayout.HelpBox("In order for the \"Use Unity Debuggger\" option to function above, you need to have installed the Unity Debugger Extension for Visual Studio Code.", MessageType.Warning); + if (GUILayout.Button(new GUIContent("Install Unity Debugger", "Install the Unity Debugger Extension into Code"))) + { + InstallUnityDebugger(); + EditorGUILayout.EndVertical(); + return; + } + } + + GUILayout.FlexibleSpace(); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + GUILayout.Label( + new GUIContent( + string.Format("{0:0.00}", Version) + VersionCode, + "GitHub's Version @ " + string.Format("{0:0.00}", GitHubVersion))); + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + } + + /// + /// Asset Open Callback (from Unity) + /// + /// + /// Called when Unity is about to open an asset. + /// + [UnityEditor.Callbacks.OnOpenAssetAttribute()] + static bool OnOpenedAsset(int instanceID, int line) + { + // bail out if we are not using VSCode + if (!Enabled) + { + return false; + } + + // current path without the asset folder + string appPath = ProjectPath; + + // determine asset that has been double clicked in the project view + UnityEngine.Object selected = EditorUtility.InstanceIDToObject(instanceID); + + if (selected.GetType().ToString() == "UnityEditor.MonoScript" || + selected.GetType().ToString() == "UnityEngine.Shader") + { + string completeFilepath = appPath + Path.DirectorySeparatorChar + AssetDatabase.GetAssetPath(selected); + + string args = null; + if (line == -1) + { + args = "\"" + ProjectPath + "\" \"" + completeFilepath + "\" -r"; + } + else + { + args = "\"" + ProjectPath + "\" -g \"" + completeFilepath + ":" + line.ToString() + "\" -r"; + } + // call 'open' + CallVSCode(args); + + return true; + } + + // Didnt find a code file? let Unity figure it out + return false; + + } + + /// + /// Executed when the Editor's playmode changes allowing for capture of required data + /// + static void OnPlaymodeStateChanged() + { + if (UnityEngine.Application.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode) + { + UpdateLaunchFile(); + } + } + + /// + /// Detect when scripts are reloaded and relink playmode detection + /// + [UnityEditor.Callbacks.DidReloadScripts()] + static void OnScriptReload() + { + EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged; + EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged; + } + + /// + /// Remove extra/erroneous lines from a file. + static void ScrubFile(string path) + { + string[] lines = File.ReadAllLines(path); + System.Collections.Generic.List newLines = new System.Collections.Generic.List(); + for (int i = 0; i < lines.Length; i++) + { + // Check Empty + if (string.IsNullOrEmpty(lines[i].Trim()) || lines[i].Trim() == "\t" || lines[i].Trim() == "\t\t") + { + + } + else + { + newLines.Add(lines[i]); + } + } + File.WriteAllLines(path, newLines.ToArray()); + } + + /// + /// Remove extra/erroneous data from project file (content). + /// + static string ScrubProjectContent(string content) + { + if (content.Length == 0) + return ""; + +#if !UNITY_EDITOR_WIN + // Moved to 3.5, 2.0 is legacy. + if (content.IndexOf("v3.5") != -1) + { + content = Regex.Replace(content, "v3.5", "v2.0"); + } +#endif + + string targetPath = "";// "Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + ""; //OutputPath + string langVersion = "default"; + + + bool found = true; + int location = 0; + string addedOptions = ""; + int startLocation = -1; + int endLocation = -1; + int endLength = 0; + + while (found) + { + startLocation = -1; + endLocation = -1; + endLength = 0; + addedOptions = ""; + startLocation = content.IndexOf("", startLocation); + endLength = (endLocation - startLocation); + + + if (endLocation == -1) + { + found = false; + continue; + } + else + { + found = true; + location = endLocation; + } + + if (content.Substring(startLocation, endLength).IndexOf("") == -1) + { + addedOptions += "\n\r\t" + targetPath + "\n\r"; + } + + if (content.Substring(startLocation, endLength).IndexOf("") == -1) + { + addedOptions += "\n\r\t" + langVersion + "\n\r"; + } + + if (!string.IsNullOrEmpty(addedOptions)) + { + content = content.Substring(0, endLocation) + addedOptions + content.Substring(endLocation); + } + } + else + { + found = false; + } + } + + return content; + } + + /// + /// Remove extra/erroneous data from solution file (content). + /// + static string ScrubSolutionContent(string content) + { + // Replace Solution Version + content = content.Replace( + "Microsoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2008\r\n", + "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2012"); + + // Remove Solution Properties (Unity Junk) + int startIndex = content.IndexOf("GlobalSection(SolutionProperties) = preSolution"); + if (startIndex != -1) + { + int endIndex = content.IndexOf("EndGlobalSection", startIndex); + content = content.Substring(0, startIndex) + content.Substring(endIndex + 16); + } + + return content; + } + + /// + /// Update Visual Studio Code Launch file + /// + static void UpdateLaunchFile() + { + if (!VSCode.Enabled) + { + return; + } + else if (VSCode.UseUnityDebugger) + { + if (!Directory.Exists(VSCode.SettingsFolder)) + System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); + + // Write out proper formatted JSON (hence no more SimpleJSON here) + string fileContent = "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"name\": \"Unity Editor\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Windows Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"OSX Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Linux Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"iOS Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Android Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\n\t\t}\n\t]\n}"; + File.WriteAllText(VSCode.LaunchPath, fileContent); + } + else if (VSCode.WriteLaunchFile) + { + int port = GetDebugPort(); + if (port > -1) + { + if (!Directory.Exists(VSCode.SettingsFolder)) + System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); + + // Write out proper formatted JSON (hence no more SimpleJSON here) + string fileContent = "{\n\t\"version\":\"0.2.0\",\n\t\"configurations\":[ \n\t\t{\n\t\t\t\"name\":\"Unity\",\n\t\t\t\"type\":\"mono\",\n\t\t\t\"request\":\"attach\",\n\t\t\t\"address\":\"localhost\",\n\t\t\t\"port\":" + port + "\n\t\t}\n\t]\n}"; + File.WriteAllText(VSCode.LaunchPath, fileContent); + + if (VSCode.Debug) + { + UnityEngine.Debug.Log("[VSCode] Debug Port Found (" + port + ")"); + } + } + else + { + if (VSCode.Debug) + { + UnityEngine.Debug.LogWarning("[VSCode] Unable to determine debug port."); + } + } + } + } + + /// + /// Update Unity Editor Preferences + /// + /// Should we turn on this party! + static void UpdateUnityPreferences(bool enabled) + { + if (enabled) + { + // App + if (EditorPrefs.GetString("kScriptsDefaultApp") != CodePath) + { + EditorPrefs.SetString("VSCode_PreviousApp", EditorPrefs.GetString("kScriptsDefaultApp")); + } + EditorPrefs.SetString("kScriptsDefaultApp", CodePath); + + // Arguments + if (EditorPrefs.GetString("kScriptEditorArgs") != "-r -g \"$(File):$(Line)\"") + { + EditorPrefs.SetString("VSCode_PreviousArgs", EditorPrefs.GetString("kScriptEditorArgs")); + } + + EditorPrefs.SetString("kScriptEditorArgs", "-r -g \"$(File):$(Line)\""); + EditorPrefs.SetString("kScriptEditorArgs" + CodePath, "-r -g \"$(File):$(Line)\""); + + + // MonoDevelop Solution + if (EditorPrefs.GetBool("kMonoDevelopSolutionProperties", false)) + { + EditorPrefs.SetBool("VSCode_PreviousMD", true); + } + EditorPrefs.SetBool("kMonoDevelopSolutionProperties", false); + + // Support Unity Proj (JS) + if (EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false)) + { + EditorPrefs.SetBool("VSCode_PreviousUnityProj", true); + } + EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", false); + + if (!EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", false)) + { + EditorPrefs.SetBool("VSCode_PreviousAttach", false); + } + EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true); + + } + else + { + // Restore previous app + if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousApp"))) + { + EditorPrefs.SetString("kScriptsDefaultApp", EditorPrefs.GetString("VSCode_PreviousApp")); + } + + // Restore previous args + if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousArgs"))) + { + EditorPrefs.SetString("kScriptEditorArgs", EditorPrefs.GetString("VSCode_PreviousArgs")); + } + + // Restore MD setting + if (EditorPrefs.GetBool("VSCode_PreviousMD", false)) + { + EditorPrefs.SetBool("kMonoDevelopSolutionProperties", true); + } + + // Restore MD setting + if (EditorPrefs.GetBool("VSCode_PreviousUnityProj", false)) + { + EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", true); + } + + // Always leave editor attaching on, I know, it solves the problem of needing to restart for this + // to actually work + EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true); + + } + + FixUnityPreferences(); + } + + /// + /// Determines if the current path to the code executable is valid or not (exists) + /// + static bool VSCodeExists(string curPath) + { + #if UNITY_EDITOR_OSX + return System.IO.Directory.Exists(curPath); + #else + System.IO.FileInfo code = new System.IO.FileInfo(curPath); + return code.Exists; + #endif + } + + /// + /// Write Default Workspace Settings + /// + static void WriteWorkspaceSettings() + { + if (Debug) + { + UnityEngine.Debug.Log("[VSCode] Workspace Settings Written"); + } + + if (!Directory.Exists(VSCode.SettingsFolder)) + { + System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); + } + + string exclusions = + "{\n" + + "\t\"files.exclude\":\n" + + "\t{\n" + + // Hidden Files + "\t\t\"**/.DS_Store\":true,\n" + + "\t\t\"**/.git\":true,\n" + + "\t\t\"**/.gitignore\":true,\n" + + "\t\t\"**/.gitattributes\":true,\n" + + "\t\t\"**/.gitmodules\":true,\n" + + "\t\t\"**/.svn\":true,\n" + + + + // Project Files + "\t\t\"**/*.booproj\":true,\n" + + "\t\t\"**/*.pidb\":true,\n" + + "\t\t\"**/*.suo\":true,\n" + + "\t\t\"**/*.user\":true,\n" + + "\t\t\"**/*.userprefs\":true,\n" + + "\t\t\"**/*.unityproj\":true,\n" + + "\t\t\"**/*.dll\":true,\n" + + "\t\t\"**/*.exe\":true,\n" + + + // Media Files + "\t\t\"**/*.pdf\":true,\n" + + + // Audio + "\t\t\"**/*.mid\":true,\n" + + "\t\t\"**/*.midi\":true,\n" + + "\t\t\"**/*.wav\":true,\n" + + + // Textures + "\t\t\"**/*.gif\":true,\n" + + "\t\t\"**/*.ico\":true,\n" + + "\t\t\"**/*.jpg\":true,\n" + + "\t\t\"**/*.jpeg\":true,\n" + + "\t\t\"**/*.png\":true,\n" + + "\t\t\"**/*.psd\":true,\n" + + "\t\t\"**/*.tga\":true,\n" + + "\t\t\"**/*.tif\":true,\n" + + "\t\t\"**/*.tiff\":true,\n" + + + // Models + "\t\t\"**/*.3ds\":true,\n" + + "\t\t\"**/*.3DS\":true,\n" + + "\t\t\"**/*.fbx\":true,\n" + + "\t\t\"**/*.FBX\":true,\n" + + "\t\t\"**/*.lxo\":true,\n" + + "\t\t\"**/*.LXO\":true,\n" + + "\t\t\"**/*.ma\":true,\n" + + "\t\t\"**/*.MA\":true,\n" + + "\t\t\"**/*.obj\":true,\n" + + "\t\t\"**/*.OBJ\":true,\n" + + + // Unity File Types + "\t\t\"**/*.asset\":true,\n" + + "\t\t\"**/*.cubemap\":true,\n" + + "\t\t\"**/*.flare\":true,\n" + + "\t\t\"**/*.mat\":true,\n" + + "\t\t\"**/*.meta\":true,\n" + + "\t\t\"**/*.prefab\":true,\n" + + "\t\t\"**/*.unity\":true,\n" + + + // Folders + "\t\t\"build/\":true,\n" + + "\t\t\"Build/\":true,\n" + + "\t\t\"Library/\":true,\n" + + "\t\t\"library/\":true,\n" + + "\t\t\"obj/\":true,\n" + + "\t\t\"Obj/\":true,\n" + + "\t\t\"ProjectSettings/\":true,\r" + + "\t\t\"temp/\":true,\n" + + "\t\t\"Temp/\":true\n" + + "\t}\n" + + "}"; + + // Dont like the replace but it fixes the issue with the JSON + File.WriteAllText(VSCode.SettingsPath, exclusions); + } + + #endregion + } + + /// + /// VSCode Asset AssetPostprocessor + /// This will ensure any time that the project files are generated the VSCode versions will be made + /// + /// Undocumented Event + public class VSCodeAssetPostprocessor : AssetPostprocessor + { + /// + /// On documented, project generation event callback + /// + private static void OnGeneratedCSProjectFiles() + { + // Force execution of VSCode update + VSCode.UpdateSolution(); + } + } +} \ No newline at end of file diff --git a/Assets/VSCode/Plugins/Editor/VSCode.cs.meta b/Assets/VSCode/Plugins/Editor/VSCode.cs.meta new file mode 100644 index 00000000..d2c039f0 --- /dev/null +++ b/Assets/VSCode/Plugins/Editor/VSCode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c34beeaf0d4cf44c49f1039006a08591 +timeCreated: 1444653497 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VSCode/README.md b/Assets/VSCode/README.md new file mode 100644 index 00000000..3e4df0ce --- /dev/null +++ b/Assets/VSCode/README.md @@ -0,0 +1,37 @@ +# VSCode +> Seamless Visual Studio Code Integration in Unity - As seen in the [Visual Studio Code documentation!](https://code.visualstudio.com/Docs/runtimes/unity) + +### Requirements +##### Unity > 4.5 && Unity < 5.5 +I am not sure exactly where in the 4.x cycle some of the features I'm using were introduced, but I'm guessing its around the 4.5+ mark. I've checked with the latest 4.5.0f6 release. Unity has also committed to having full support for Code when Unity 5.5 drops. So at that point all bets are off for the usefulness of this plugin. Like our MonoDevelop.Unity plugin of past, Unity catches up eventually. + +#####Visual Studio Code 0.10.1+ +Get the [latest version](https://code.visualstudio.com), or have a look at the past releases of the VSCode [plugin](https://github.com/dotBunny/VSCode/releases/tag/1.6.5) for support for your version. + +######Mono +A good number of people have needed to install Mono in order for many of the issues with OmniSharp to be resolved. +I would suggest installing the latest package available at the [Mono Project](http://www.mono-project.com/download/). Don't worry it will not mess with Unity. + +### Installation +It is important to make sure that the `VSCode.cs` file is placed under an `Editor` folder in the project. An example of this arrangement would be placing the file in `/Assets/Plugins/Editor/VSCode.cs`. By default it has its own folder structure which does this for you. + +### Unity Asset Store Package +A UAS packaged version of the plugin is [available](http://u3d.as/jmM) for your consumption. + +### Usage +Once the VSCode file is in place, simply navigate your way to the `Unity Preferences` and select `VSCode` and check the `Enable Integration` option. + +That's it! Your ready to go! + +OK, so maybe some people need a little video explaining some of the finer details of how to use the plugin. So I shot a [quick video](https://vimeo.com/dotbunny/vscode) that highlights the ups and the downs (like Unity hanging after debugging sometimes) for people to watch. Please note this video is from a previous version of the plugin where things are in the menu, this has changed since then. + +### Platform Support +I use the plugin every day on a Mac (so it's battle tested there), and occasionally test it on a Windows VM. As for the recently announced Linux support, it should work just like the Mac version. I'll get around to installing the Linux editor sometime in the near future. + +The Windows version of Visual Studio Code currently does not support debugging Mono, and will just throw a warning if you try to do it. The "Code" team is aware of this limitation, and we'll leave it at that. + +### Automatic Update +With version 2.0 of the plugin, I've introduced a feature where it will auto-update itself if allowed. This should make things a lot easier in the future. + +### Support +Please provide feedback through the GitHub [Issue](https://github.com/dotBunny/VSCode/issues) system. diff --git a/Assets/VSCode/README.md.meta b/Assets/VSCode/README.md.meta new file mode 100644 index 00000000..6f6e8a5e --- /dev/null +++ b/Assets/VSCode/README.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a47489a858c74f3ea182d15dec0dd72 +timeCreated: 1444651605 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: