├── HOWTO.pdf ├── .gitignore ├── LICENSE ├── README.md └── Plugins └── Editor └── VSCode.cs /HOWTO.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotBunny/VSCode/HEAD/HOWTO.pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | [Ll]ibrary/ 2 | [Tt]emp/ 3 | [Oo]bj/ 4 | [Bb]uild/ 5 | 6 | # Autogenerated VS/MD solution and project files 7 | *.csproj 8 | *.unityproj 9 | *.sln 10 | *.suo 11 | *.tmp 12 | *.user 13 | *.userprefs 14 | *.pidb 15 | *.booproj 16 | 17 | # Unity3D generated meta files 18 | *.pidb.meta 19 | 20 | # Unity3D Generated File On Crash Reports 21 | sysinfo.txt 22 | *.meta 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 dotBunny Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCode 2 | > Seamless Visual Studio Code Integration in Unity - As seen in the [Visual Studio Code documentation!](https://code.visualstudio.com/Docs/runtimes/unity) 3 | 4 | ### Requirements 5 | ##### Unity > 4.5 && Unity < 5.5 6 | 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. 7 | 8 | ##### Visual Studio Code 0.10.1+ 9 | 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. 10 | 11 | ###### Mono 12 | A good number of people have needed to install Mono in order for many of the issues with OmniSharp to be resolved. 13 | 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. 14 | 15 | ### Installation 16 | 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. 17 | 18 | ### Unity Asset Store Package 19 | A UAS packaged version of the plugin is [available](http://u3d.as/jmM) for your consumption. 20 | 21 | ### Usage 22 | Once the VSCode file is in place, simply navigate your way to the `Unity Preferences` and select `VSCode` and check the `Enable Integration` option. 23 | 24 | That's it! You're ready to go! 25 | 26 | 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. 27 | 28 | ### Platform Support 29 | 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. 30 | 31 | 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. 32 | 33 | ### Automatic Update 34 | 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. 35 | 36 | ### Support 37 | Please provide feedback through the GitHub [Issue](https://github.com/dotBunny/VSCode/issues) system. 38 | -------------------------------------------------------------------------------- /Plugins/Editor/VSCode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Unity VSCode Support 3 | * 4 | * Seamless support for Microsoft Visual Studio Code in Unity 5 | * 6 | * Version: 7 | * 2.9 8 | * 9 | * Authors: 10 | * Matthew Davey 11 | */ 12 | namespace dotBunny.Unity 13 | { 14 | using System; 15 | using System.IO; 16 | using System.Text.RegularExpressions; 17 | using UnityEditor; 18 | using UnityEngine; 19 | 20 | [InitializeOnLoad] 21 | public static class VSCode 22 | { 23 | /// 24 | /// Current Version Number 25 | /// 26 | public const float Version = 2.9f; 27 | 28 | /// 29 | /// Current Version Code 30 | /// 31 | public const string VersionCode = "-RELEASE"; 32 | 33 | /// 34 | /// Additional File Extensions 35 | /// 36 | public const string FileExtensions = ".ts, .bjs, .javascript, .json, .html, .shader, .template"; 37 | 38 | /// 39 | /// Download URL for Unity Debbuger 40 | /// 41 | public const string UnityDebuggerURL = "https://unity.gallery.vsassets.io/_apis/public/gallery/publisher/unity/extension/unity-debug/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"; 42 | 43 | // Used to keep Unity from crashing when the editor is quit 44 | static bool alreadyFixedPreferences; 45 | 46 | #region Properties 47 | 48 | /// 49 | /// Path to VSCode executable 50 | public static string CodePath 51 | { 52 | get 53 | { 54 | string current = EditorPrefs.GetString("VSCode_CodePath", ""); 55 | if(current == "" || !VSCodeExists(current)) 56 | { 57 | //Value not set, set to "" or current path is invalid, try to autodetect it 58 | //If autodetect fails, a error will be printed and the default value set 59 | EditorPrefs.SetString("VSCode_CodePath", AutodetectCodePath()); 60 | //If its not installed or the install folder isn't a "normal" one, 61 | //AutodetectCodePath will print a error message to the Unity Console 62 | } 63 | return EditorPrefs.GetString("VSCode_CodePath", current); 64 | } 65 | set 66 | { 67 | EditorPrefs.SetString("VSCode_CodePath", value); 68 | } 69 | } 70 | 71 | /// 72 | /// Get Program Files Path 73 | /// 74 | /// The platforms "Program Files" path. 75 | static string ProgramFilesx86() 76 | { 77 | return Environment.GetEnvironmentVariable("ProgramFiles(x86)"); 78 | } 79 | 80 | /// 81 | /// Get Program Files Path 82 | /// 83 | /// The platforms "Program Files" path. 84 | static string ProgramFiles() 85 | { 86 | return Environment.GetEnvironmentVariable("ProgramFiles"); 87 | } 88 | 89 | 90 | /// 91 | /// Should debug information be displayed in the Unity terminal? 92 | /// 93 | public static bool Debug 94 | { 95 | get 96 | { 97 | return EditorPrefs.GetBool("VSCode_Debug", false); 98 | } 99 | set 100 | { 101 | EditorPrefs.SetBool("VSCode_Debug", value); 102 | } 103 | } 104 | 105 | /// 106 | /// Is the Visual Studio Code Integration Enabled? 107 | /// 108 | /// 109 | /// We do not want to automatically turn it on, for in larger projects not everyone is using VSCode 110 | /// 111 | public static bool Enabled 112 | { 113 | get 114 | { 115 | return EditorPrefs.GetBool("VSCode_Enabled", false); 116 | } 117 | set 118 | { 119 | // When turning the plugin on, we should remove all the previous project files 120 | if (!Enabled && value) 121 | { 122 | ClearProjectFiles(); 123 | } 124 | EditorPrefs.SetBool("VSCode_Enabled", value); 125 | } 126 | } 127 | public static bool UseUnityDebugger 128 | { 129 | get 130 | { 131 | return EditorPrefs.GetBool("VSCode_UseUnityDebugger", false); 132 | } 133 | set 134 | { 135 | if ( value != UseUnityDebugger ) { 136 | 137 | // Set value 138 | EditorPrefs.SetBool("VSCode_UseUnityDebugger", value); 139 | 140 | // Do not write the launch JSON file because the debugger uses its own 141 | if ( value ) { 142 | WriteLaunchFile = false; 143 | } 144 | 145 | // Update launch file 146 | UpdateLaunchFile(); 147 | } 148 | } 149 | } 150 | 151 | /// 152 | /// When opening a project in Unity, should it automatically open in VS Code. 153 | /// 154 | public static bool AutoOpenEnabled 155 | { 156 | get 157 | { 158 | return EditorPrefs.GetBool("VSCode_AutoOpenEnabled", false); 159 | } 160 | set 161 | { 162 | EditorPrefs.SetBool("VSCode_AutoOpenEnabled", value); 163 | } 164 | } 165 | 166 | /// 167 | /// Should the launch.json file be written? 168 | /// 169 | /// 170 | /// Useful to disable if someone has their own custom one rigged up 171 | /// 172 | public static bool WriteLaunchFile 173 | { 174 | get 175 | { 176 | return EditorPrefs.GetBool("VSCode_WriteLaunchFile", true); 177 | } 178 | set 179 | { 180 | EditorPrefs.SetBool("VSCode_WriteLaunchFile", value); 181 | } 182 | } 183 | 184 | /// 185 | /// Should the plugin automatically update itself. 186 | /// 187 | static bool AutomaticUpdates 188 | { 189 | get 190 | { 191 | return EditorPrefs.GetBool("VSCode_AutomaticUpdates", false); 192 | } 193 | set 194 | { 195 | EditorPrefs.SetBool("VSCode_AutomaticUpdates", value); 196 | } 197 | } 198 | 199 | static float GitHubVersion 200 | { 201 | get 202 | { 203 | return EditorPrefs.GetFloat("VSCode_GitHubVersion", Version); 204 | } 205 | set 206 | { 207 | EditorPrefs.SetFloat("VSCode_GitHubVersion", value); 208 | } 209 | } 210 | 211 | /// 212 | /// When was the last time that the plugin was updated? 213 | /// 214 | static DateTime LastUpdate 215 | { 216 | get 217 | { 218 | // Feature creation date. 219 | DateTime lastTime = new DateTime(2015, 10, 8); 220 | 221 | if (EditorPrefs.HasKey("VSCode_LastUpdate")) 222 | { 223 | DateTime.TryParse(EditorPrefs.GetString("VSCode_LastUpdate"), out lastTime); 224 | } 225 | return lastTime; 226 | } 227 | set 228 | { 229 | EditorPrefs.SetString("VSCode_LastUpdate", value.ToString()); 230 | } 231 | } 232 | 233 | /// 234 | /// Quick reference to the VSCode launch settings file 235 | /// 236 | static string LaunchPath 237 | { 238 | get 239 | { 240 | return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "launch.json"; 241 | } 242 | } 243 | 244 | /// 245 | /// Should the parent of the unity project be used as the workspace directory. 246 | /// 247 | /// 248 | /// Usefull if you have your unity project as a sub-directory. 249 | /// 250 | static bool UseParentWorkspace 251 | { 252 | get 253 | { 254 | return EditorPrefs.GetBool("VSCode_UseParentWorkspace", false); 255 | } 256 | set 257 | { 258 | EditorPrefs.SetBool("VSCode_UseParentWorkspace", value); 259 | } 260 | } 261 | 262 | /// 263 | /// The full path to the Unity project. 264 | /// 265 | static string UnityProjectPath 266 | { 267 | get 268 | { 269 | return System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath); 270 | } 271 | } 272 | 273 | /// 274 | /// The full path to the workspace. 275 | /// 276 | static string WorkspacePath 277 | { 278 | get 279 | { 280 | return UseParentWorkspace ? 281 | Directory.GetParent(UnityProjectPath).FullName : 282 | UnityProjectPath; 283 | } 284 | } 285 | 286 | /// 287 | /// Should the script editor be reverted when quiting Unity. 288 | /// 289 | /// 290 | /// Useful for environments where you do not use VSCode for everything. 291 | /// 292 | static bool RevertExternalScriptEditorOnExit 293 | { 294 | get 295 | { 296 | return EditorPrefs.GetBool("VSCode_RevertScriptEditorOnExit", true); 297 | } 298 | set 299 | { 300 | EditorPrefs.SetBool("VSCode_RevertScriptEditorOnExit", value); 301 | } 302 | } 303 | 304 | /// 305 | /// Quick reference to the VSCode settings folder 306 | /// 307 | static string SettingsFolder 308 | { 309 | get 310 | { 311 | return WorkspacePath + System.IO.Path.DirectorySeparatorChar + ".vscode"; 312 | } 313 | } 314 | 315 | static string SettingsPath 316 | { 317 | 318 | get 319 | { 320 | return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "settings.json"; 321 | } 322 | } 323 | 324 | static int UpdateTime 325 | { 326 | get 327 | { 328 | return EditorPrefs.GetInt("VSCode_UpdateTime", 7); 329 | } 330 | set 331 | { 332 | EditorPrefs.SetInt("VSCode_UpdateTime", value); 333 | } 334 | } 335 | 336 | #endregion 337 | 338 | /// 339 | /// Integration Constructor 340 | /// 341 | static VSCode() 342 | { 343 | if (Enabled) 344 | { 345 | UpdateUnityPreferences(true); 346 | UpdateLaunchFile(); 347 | 348 | // Add Update Check 349 | DateTime targetDate = LastUpdate.AddDays(UpdateTime); 350 | if (DateTime.Now >= targetDate && AutomaticUpdates) 351 | { 352 | CheckForUpdate(); 353 | } 354 | 355 | // Open VS Code automatically when project is loaded 356 | if (AutoOpenEnabled) 357 | { 358 | CheckForAutoOpen(); 359 | } 360 | 361 | } 362 | 363 | // Event for when script is reloaded 364 | System.AppDomain.CurrentDomain.DomainUnload += System_AppDomain_CurrentDomain_DomainUnload; 365 | } 366 | static void System_AppDomain_CurrentDomain_DomainUnload(object sender, System.EventArgs e) 367 | { 368 | if (Enabled && RevertExternalScriptEditorOnExit) 369 | { 370 | UpdateUnityPreferences(false); 371 | } 372 | } 373 | 374 | 375 | #region Public Members 376 | 377 | /// 378 | /// Force Unity To Write Project File 379 | /// 380 | /// 381 | /// Reflection! 382 | /// 383 | public static void SyncSolution() 384 | { 385 | System.Type T = System.Type.GetType("UnityEditor.SyncVS,UnityEditor"); 386 | System.Reflection.MethodInfo SyncSolution = T.GetMethod("SyncSolution", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); 387 | SyncSolution.Invoke(null, null); 388 | 389 | } 390 | 391 | /// 392 | /// Update the solution files so that they work with VS Code 393 | /// 394 | public static void UpdateSolution() 395 | { 396 | // No need to process if we are not enabled 397 | if (!VSCode.Enabled) 398 | { 399 | return; 400 | } 401 | 402 | if (VSCode.Debug) 403 | { 404 | UnityEngine.Debug.Log("[VSCode] Updating Solution & Project Files"); 405 | } 406 | 407 | var currentDirectory = Directory.GetCurrentDirectory(); 408 | var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln"); 409 | var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj"); 410 | 411 | foreach (var filePath in solutionFiles) 412 | { 413 | string content = File.ReadAllText(filePath); 414 | content = ScrubSolutionContent(content); 415 | 416 | File.WriteAllText(filePath, content); 417 | 418 | ScrubFile(filePath); 419 | } 420 | 421 | foreach (var filePath in projectFiles) 422 | { 423 | string content = File.ReadAllText(filePath); 424 | content = ScrubProjectContent(content); 425 | 426 | File.WriteAllText(filePath, content); 427 | 428 | ScrubFile(filePath); 429 | } 430 | 431 | } 432 | 433 | #endregion 434 | 435 | #region Private Members 436 | 437 | /// 438 | /// Try to find automatically the installation of VSCode 439 | /// 440 | static string AutodetectCodePath() 441 | { 442 | string[] possiblePaths = 443 | #if UNITY_EDITOR_OSX 444 | { 445 | "/Applications/Visual Studio Code.app", 446 | "/Applications/Visual Studio Code - Insiders.app" 447 | }; 448 | #elif UNITY_EDITOR_WIN 449 | { 450 | ProgramFiles() + Path.DirectorySeparatorChar + "Microsoft VS Code" 451 | + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code.cmd", 452 | ProgramFiles() + Path.DirectorySeparatorChar + "Microsoft VS Code Insiders" 453 | + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code-insiders.cmd", 454 | ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code" 455 | + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code.cmd", 456 | ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code Insiders" 457 | + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code-insiders.cmd" 458 | }; 459 | #else 460 | { 461 | "/usr/bin/code", 462 | "/usr/bin/code-insiders", 463 | "/bin/code", 464 | "/usr/local/bin/code", 465 | "/var/lib/flatpak/exports/bin/com.visualstudio.code", 466 | "/snap/bin/code", 467 | "/snap/bin/code-insiders" 468 | }; 469 | #endif 470 | for(int i = 0; i < possiblePaths.Length; i++) 471 | { 472 | if(VSCodeExists(possiblePaths[i])) 473 | { 474 | return possiblePaths[i]; 475 | } 476 | } 477 | PrintNotFound(possiblePaths[0]); 478 | return possiblePaths[0]; //returns the default one, printing a warning message 'executable not found' 479 | } 480 | 481 | /// 482 | /// Call VSCode with arguments 483 | /// 484 | static void CallVSCode(string args) 485 | { 486 | System.Diagnostics.Process proc = new System.Diagnostics.Process(); 487 | if(!VSCodeExists(CodePath)) 488 | { 489 | PrintNotFound(CodePath); 490 | return; 491 | } 492 | 493 | #if UNITY_EDITOR_OSX 494 | proc.StartInfo.FileName = "open"; 495 | 496 | // Check the path to see if there is "Insiders" 497 | if (CodePath.Contains("Insiders")) 498 | { 499 | proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCodeInsiders\" --args " + args.Replace(@"\", @"\\"); 500 | } 501 | else 502 | { 503 | proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCode\" --args " + args.Replace(@"\", @"\\"); 504 | } 505 | 506 | proc.StartInfo.UseShellExecute = false; 507 | #elif UNITY_EDITOR_WIN 508 | proc.StartInfo.FileName = CodePath; 509 | proc.StartInfo.Arguments = args; 510 | proc.StartInfo.UseShellExecute = false; 511 | #else 512 | proc.StartInfo.FileName = CodePath; 513 | proc.StartInfo.Arguments = args.Replace(@"\", @"\\"); 514 | proc.StartInfo.UseShellExecute = false; 515 | #endif 516 | proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 517 | proc.StartInfo.CreateNoWindow = true; 518 | proc.StartInfo.RedirectStandardOutput = true; 519 | proc.Start(); 520 | } 521 | 522 | /// 523 | /// Check for Updates with GitHub 524 | /// 525 | static void CheckForUpdate() 526 | { 527 | var fileContent = string.Empty; 528 | 529 | EditorUtility.DisplayProgressBar("VSCode", "Checking for updates ...", 0.5f); 530 | 531 | // Because were not a runtime framework, lets just use the simplest way of doing this 532 | try 533 | { 534 | using (var webClient = new System.Net.WebClient()) 535 | { 536 | fileContent = webClient.DownloadString("https://raw.githubusercontent.com/dotBunny/VSCode/master/Plugins/Editor/VSCode.cs"); 537 | } 538 | } 539 | catch (Exception e) 540 | { 541 | if (Debug) 542 | { 543 | UnityEngine.Debug.Log("[VSCode] " + e.Message); 544 | 545 | } 546 | 547 | // Don't go any further if there is an error 548 | return; 549 | } 550 | finally 551 | { 552 | EditorUtility.ClearProgressBar(); 553 | } 554 | 555 | // Set the last update time 556 | LastUpdate = DateTime.Now; 557 | 558 | // Fix for oddity in downlo 559 | if (fileContent.Substring(0, 2) != "/*") 560 | { 561 | int startPosition = fileContent.IndexOf("/*", StringComparison.CurrentCultureIgnoreCase); 562 | 563 | // Jump over junk characters 564 | fileContent = fileContent.Substring(startPosition); 565 | } 566 | 567 | string[] fileExploded = fileContent.Split('\n'); 568 | if (fileExploded.Length > 7) 569 | { 570 | float github = Version; 571 | if (float.TryParse(fileExploded[6].Replace("*", "").Trim(), out github)) 572 | { 573 | GitHubVersion = github; 574 | } 575 | 576 | 577 | if (github > Version) 578 | { 579 | var GUIDs = AssetDatabase.FindAssets("t:Script VSCode"); 580 | var path = Application.dataPath.Substring(0, Application.dataPath.Length - "/Assets".Length) + System.IO.Path.DirectorySeparatorChar + 581 | AssetDatabase.GUIDToAssetPath(GUIDs[0]).Replace('/', System.IO.Path.DirectorySeparatorChar); 582 | 583 | if (EditorUtility.DisplayDialog("VSCode Update", "A newer version of the VSCode plugin is available, would you like to update your version?", "Yes", "No")) 584 | { 585 | // Always make sure the file is writable 586 | System.IO.FileInfo fileInfo = new System.IO.FileInfo(path); 587 | fileInfo.IsReadOnly = false; 588 | 589 | // Write update file 590 | File.WriteAllText(path, fileContent); 591 | 592 | // Force update on text file 593 | AssetDatabase.ImportAsset(AssetDatabase.GUIDToAssetPath(GUIDs[0]), ImportAssetOptions.ForceUpdate); 594 | } 595 | 596 | } 597 | } 598 | } 599 | 600 | /// 601 | /// Checks whether it should auto-open VSCode 602 | /// 603 | /// 604 | /// VSCode() gets called on Launch and Run, through IntializeOnLoad 605 | /// https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html 606 | /// To make sure it only opens VSCode when Unity (re)launches (i.e. opens a project), 607 | /// we compare the launch time, which we calculate using EditorApplication.timeSinceStartup. 608 | /// 609 | static void CheckForAutoOpen() 610 | { 611 | double timeInSeconds = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; 612 | int unityLaunchTimeInSeconds = (int)(timeInSeconds - EditorApplication.timeSinceStartup); 613 | int prevUnityLaunchTime = EditorPrefs.GetInt("VSCode_UnityLaunchTime", 0); 614 | // If launch time has changed, then Unity was re-opened 615 | if (unityLaunchTimeInSeconds > prevUnityLaunchTime) { 616 | // Launch VSCode 617 | VSCode.MenuOpenProject(); 618 | // Save new launch time 619 | EditorPrefs.SetInt("VSCode_UnityLaunchTime", unityLaunchTimeInSeconds); 620 | } 621 | } 622 | 623 | /// 624 | /// Clear out any existing project files and lingering stuff that might cause problems 625 | /// 626 | static void ClearProjectFiles() 627 | { 628 | var currentDirectory = Directory.GetCurrentDirectory(); 629 | var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln"); 630 | var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj"); 631 | var unityProjectFiles = Directory.GetFiles(currentDirectory, "*.unityproj"); 632 | 633 | foreach (string solutionFile in solutionFiles) 634 | { 635 | File.Delete(solutionFile); 636 | } 637 | foreach (string projectFile in projectFiles) 638 | { 639 | File.Delete(projectFile); 640 | } 641 | foreach (string unityProjectFile in unityProjectFiles) 642 | { 643 | File.Delete(unityProjectFile); 644 | } 645 | 646 | // Replace with our clean files (only in Unity 5) 647 | #if !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6 && !UNITY_4_7 648 | SyncSolution(); 649 | #endif 650 | } 651 | 652 | /// 653 | /// Force Unity Preferences Window To Read From Settings 654 | /// 655 | static void FixUnityPreferences() 656 | { 657 | // I want that window, please and thank you 658 | System.Type T = System.Type.GetType("UnityEditor.PreferencesWindow,UnityEditor"); 659 | 660 | if (EditorWindow.focusedWindow == null) 661 | return; 662 | 663 | // Only run this when the editor window is visible (cause its what screwed us up) 664 | if (EditorWindow.focusedWindow.GetType() == T) 665 | { 666 | var window = EditorWindow.GetWindow(T, true, "Unity Preferences"); 667 | 668 | 669 | if (window == null) 670 | { 671 | if (Debug) 672 | { 673 | UnityEngine.Debug.Log("[VSCode] No Preferences Window Found (really?)"); 674 | } 675 | return; 676 | } 677 | 678 | var invokerType = window.GetType(); 679 | var invokerMethod = invokerType.GetMethod("ReadPreferences", 680 | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 681 | 682 | if (invokerMethod != null) 683 | { 684 | invokerMethod.Invoke(window, null); 685 | } 686 | else if (Debug) 687 | { 688 | UnityEngine.Debug.Log("[VSCode] No Reflection Method Found For Preferences"); 689 | } 690 | } 691 | } 692 | 693 | /// 694 | /// Determine what port Unity is listening for on Windows 695 | /// 696 | static int GetDebugPort() 697 | { 698 | #if UNITY_EDITOR_WIN 699 | System.Diagnostics.Process process = new System.Diagnostics.Process(); 700 | process.StartInfo.FileName = "netstat"; 701 | process.StartInfo.Arguments = "-a -n -o -p TCP"; 702 | process.StartInfo.UseShellExecute = false; 703 | process.StartInfo.RedirectStandardOutput = true; 704 | process.Start(); 705 | 706 | string output = process.StandardOutput.ReadToEnd(); 707 | string[] lines = output.Split('\n'); 708 | 709 | process.WaitForExit(); 710 | 711 | foreach (string line in lines) 712 | { 713 | string[] tokens = Regex.Split(line, "\\s+"); 714 | if (tokens.Length > 4) 715 | { 716 | int test = -1; 717 | int.TryParse(tokens[5], out test); 718 | 719 | if (test > 1023) 720 | { 721 | try 722 | { 723 | var p = System.Diagnostics.Process.GetProcessById(test); 724 | if (p.ProcessName == "Unity") 725 | { 726 | return test; 727 | } 728 | } 729 | catch 730 | { 731 | 732 | } 733 | } 734 | } 735 | } 736 | #else 737 | System.Diagnostics.Process process = new System.Diagnostics.Process(); 738 | process.StartInfo.FileName = "lsof"; 739 | process.StartInfo.Arguments = "-c /^Unity$/ -i 4tcp -a"; 740 | process.StartInfo.UseShellExecute = false; 741 | process.StartInfo.RedirectStandardOutput = true; 742 | process.Start(); 743 | 744 | // Not thread safe (yet!) 745 | string output = process.StandardOutput.ReadToEnd(); 746 | string[] lines = output.Split('\n'); 747 | 748 | process.WaitForExit(); 749 | 750 | foreach (string line in lines) 751 | { 752 | int port = -1; 753 | if (line.StartsWith("Unity")) 754 | { 755 | string[] portions = line.Split(new string[] { "TCP *:" }, System.StringSplitOptions.None); 756 | if (portions.Length >= 2) 757 | { 758 | Regex digitsOnly = new Regex(@"[^\d]"); 759 | string cleanPort = digitsOnly.Replace(portions[1], ""); 760 | if (int.TryParse(cleanPort, out port)) 761 | { 762 | if (port > -1) 763 | { 764 | return port; 765 | } 766 | } 767 | } 768 | } 769 | } 770 | #endif 771 | return -1; 772 | } 773 | 774 | /// 775 | /// Manually install the original Unity Debuger 776 | /// 777 | /// 778 | /// This should auto update to the latest. 779 | /// 780 | static void InstallUnityDebugger() 781 | { 782 | EditorUtility.DisplayProgressBar("VSCode", "Downloading Unity Debugger ...", 0.1f); 783 | byte[] fileContent; 784 | 785 | try 786 | { 787 | using (var webClient = new System.Net.WebClient()) 788 | { 789 | fileContent = webClient.DownloadData(UnityDebuggerURL); 790 | } 791 | } 792 | catch (Exception e) 793 | { 794 | if (Debug) 795 | { 796 | UnityEngine.Debug.Log("[VSCode] " + e.Message); 797 | } 798 | // Don't go any further if there is an error 799 | return; 800 | } 801 | finally 802 | { 803 | EditorUtility.ClearProgressBar(); 804 | } 805 | 806 | // Do we have a file to install? 807 | if ( fileContent != null ) { 808 | string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".vsix"; 809 | File.WriteAllBytes(fileName, fileContent); 810 | 811 | CallVSCode(fileName); 812 | } 813 | 814 | } 815 | 816 | // HACK: This is in until Unity can figure out why MD keeps opening even though a different program is selected. 817 | [MenuItem("Assets/Open C# Project In Code", false, 1000)] 818 | static void MenuOpenProject() 819 | { 820 | // Force the project files to be sync 821 | SyncSolution(); 822 | 823 | // Load Project 824 | CallVSCode("\"" + WorkspacePath + "\""); 825 | } 826 | 827 | /// 828 | /// Print a error message to the Unity Console about not finding the code executable 829 | /// 830 | static void PrintNotFound(string path) 831 | { 832 | UnityEngine.Debug.LogError("[VSCode] Code executable in '" + path + "' not found. Check your" + 833 | "Visual Studio Code installation and insert the correct path in the Preferences menu."); 834 | } 835 | 836 | [MenuItem("Assets/Open C# Project In Code", true, 1000)] 837 | static bool ValidateMenuOpenProject() 838 | { 839 | return Enabled; 840 | } 841 | 842 | /// 843 | /// VS Code Integration Preferences Item 844 | /// 845 | /// 846 | /// Contains all 3 toggles: Enable/Disable; Debug On/Off; Writing Launch File On/Off 847 | /// 848 | [PreferenceItem("VSCode")] 849 | static void VSCodePreferencesItem() 850 | { 851 | if (EditorApplication.isCompiling) 852 | { 853 | 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); 854 | return; 855 | } 856 | EditorGUILayout.BeginVertical(); 857 | 858 | var developmentInfo = "Support development of this plugin, follow @reapazor and @dotbunny on Twitter."; 859 | var versionInfo = string.Format("{0:0.00}", Version) + VersionCode + ", GitHub version @ " + string.Format("{0:0.00}", GitHubVersion); 860 | EditorGUILayout.HelpBox(developmentInfo + " --- [ " + versionInfo + " ]", MessageType.None); 861 | 862 | EditorGUI.BeginChangeCheck(); 863 | 864 | // Need the VS Code executable 865 | EditorGUILayout.BeginHorizontal(); 866 | EditorGUILayout.LabelField("VS Code Path", GUILayout.Width(75)); 867 | #if UNITY_5_3_OR_NEWER 868 | CodePath = EditorGUILayout.DelayedTextField(CodePath, GUILayout.ExpandWidth(true)); 869 | #else 870 | CodePath = EditorGUILayout.TextField(CodePath, GUILayout.ExpandWidth(true)); 871 | #endif 872 | GUI.SetNextControlName("PathSetButton"); 873 | if(GUILayout.Button("...", GUILayout.Height(14), GUILayout.Width(20))) 874 | { 875 | GUI.FocusControl("PathSetButton"); 876 | string path = EditorUtility.OpenFilePanel( "Visual Studio Code Executable", "", "" ); 877 | if( path.Length != 0 && File.Exists(path) || Directory.Exists(path)) 878 | { 879 | CodePath = path; 880 | } 881 | } 882 | EditorGUILayout.EndHorizontal(); 883 | EditorGUILayout.Space(); 884 | 885 | Enabled = EditorGUILayout.Toggle(new GUIContent("Enable Integration", "Should the integration work its magic for you?"), Enabled); 886 | 887 | UseUnityDebugger = EditorGUILayout.Toggle(new GUIContent("Use Unity Debugger", "Should the integration integrate with Unity's VSCode Extension (must be installed)."), UseUnityDebugger); 888 | 889 | AutoOpenEnabled = EditorGUILayout.Toggle(new GUIContent("Enable Auto Open", "When opening a project in Unity, should it automatically open in VS Code?"), AutoOpenEnabled); 890 | 891 | EditorGUILayout.Space(); 892 | 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); 893 | 894 | EditorGUILayout.Space(); 895 | UseParentWorkspace = EditorGUILayout.Toggle(new GUIContent("Parent as workspace", "Should the parent of the project be used as the workspace directory? Usefull if you have the Unity project in a subdirectory."),UseParentWorkspace); 896 | 897 | Debug = EditorGUILayout.Toggle(new GUIContent("Output Messages To Console", "Should informational messages be sent to Unity's Console?"), Debug); 898 | 899 | WriteLaunchFile = EditorGUILayout.Toggle(new GUIContent("Always Write Launch File", "Always write the launch.json settings when entering play mode?"), WriteLaunchFile); 900 | 901 | EditorGUILayout.Space(); 902 | 903 | AutomaticUpdates = EditorGUILayout.Toggle(new GUIContent("Automatic Updates", "Should the plugin automatically update itself?"), AutomaticUpdates); 904 | 905 | UpdateTime = EditorGUILayout.IntSlider(new GUIContent("Update Timer (Days)", "After how many days should updates be checked for?"), UpdateTime, 1, 31); 906 | 907 | EditorGUILayout.Space(); 908 | EditorGUILayout.Space(); 909 | 910 | if (EditorGUI.EndChangeCheck()) 911 | { 912 | UpdateUnityPreferences(Enabled); 913 | 914 | // TODO: Force Unity To Reload Preferences 915 | // This seems to be a hick up / issue 916 | if (VSCode.Debug) 917 | { 918 | if (Enabled) 919 | { 920 | UnityEngine.Debug.Log("[VSCode] Integration Enabled"); 921 | } 922 | else 923 | { 924 | UnityEngine.Debug.Log("[VSCode] Integration Disabled"); 925 | } 926 | } 927 | } 928 | 929 | if (GUILayout.Button(new GUIContent("Force Update", "Check for updates to the plugin, right NOW!"))) 930 | { 931 | CheckForUpdate(); 932 | EditorGUILayout.EndVertical(); 933 | return; 934 | } 935 | 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."))) 936 | { 937 | WriteWorkspaceSettings(); 938 | EditorGUILayout.EndVertical(); 939 | return; 940 | } 941 | EditorGUILayout.Space(); 942 | 943 | if (UseUnityDebugger) 944 | { 945 | 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); 946 | if (GUILayout.Button(new GUIContent("Install Unity Debugger", "Install the Unity Debugger Extension into Code"))) 947 | { 948 | InstallUnityDebugger(); 949 | EditorGUILayout.EndVertical(); 950 | return; 951 | } 952 | } 953 | 954 | EditorGUILayout.EndVertical(); 955 | } 956 | 957 | /// 958 | /// Asset Open Callback (from Unity) 959 | /// 960 | /// 961 | /// Called when Unity is about to open an asset. 962 | /// 963 | [UnityEditor.Callbacks.OnOpenAssetAttribute()] 964 | static bool OnOpenedAsset(int instanceID, int line) 965 | { 966 | // bail out if we are not using VSCode 967 | if (!Enabled) 968 | { 969 | return false; 970 | } 971 | 972 | // current path without the asset folder 973 | string appPath = UnityProjectPath; 974 | 975 | // determine asset that has been double clicked in the project view 976 | UnityEngine.Object selected = EditorUtility.InstanceIDToObject(instanceID); 977 | 978 | // additional file extensions 979 | string selectedFilePath = AssetDatabase.GetAssetPath(selected); 980 | string selectedFileExt = Path.GetExtension(selectedFilePath); 981 | if (selectedFileExt == null) { 982 | selectedFileExt = String.Empty; 983 | } 984 | if (!String.IsNullOrEmpty(selectedFileExt)) { 985 | selectedFileExt = selectedFileExt.ToLower(); 986 | } 987 | 988 | // open supported object types 989 | if (selected.GetType().ToString() == "UnityEditor.MonoScript" || 990 | selected.GetType().ToString() == "UnityEngine.Shader" || 991 | VSCode.FileExtensions.IndexOf(selectedFileExt, StringComparison.OrdinalIgnoreCase) >= 0) 992 | { 993 | string completeFilepath = appPath + Path.DirectorySeparatorChar + AssetDatabase.GetAssetPath(selected); 994 | 995 | string args = null; 996 | if (line == -1) 997 | { 998 | args = "\"" + WorkspacePath + "\" \"" + completeFilepath + "\" -r"; 999 | } 1000 | else 1001 | { 1002 | args = "\"" + WorkspacePath + "\" -g \"" + completeFilepath + ":" + line.ToString() + "\" -r"; 1003 | } 1004 | // call 'open' 1005 | CallVSCode(args); 1006 | 1007 | return true; 1008 | } 1009 | 1010 | // Didnt find a code file? let Unity figure it out 1011 | return false; 1012 | 1013 | } 1014 | 1015 | /// 1016 | /// Executed when the Editor's playmode changes allowing for capture of required data 1017 | /// 1018 | #if UNITY_2017_2_OR_NEWER 1019 | static void OnPlaymodeStateChanged(UnityEditor.PlayModeStateChange state) 1020 | #else 1021 | static void OnPlaymodeStateChanged() 1022 | #endif 1023 | { 1024 | if (UnityEngine.Application.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode) 1025 | { 1026 | UpdateLaunchFile(); 1027 | } 1028 | } 1029 | 1030 | /// 1031 | /// Detect when scripts are reloaded and relink playmode detection 1032 | /// 1033 | [UnityEditor.Callbacks.DidReloadScripts()] 1034 | static void OnScriptReload() 1035 | { 1036 | #if UNITY_2017_2_OR_NEWER 1037 | EditorApplication.playModeStateChanged -= OnPlaymodeStateChanged; 1038 | EditorApplication.playModeStateChanged += OnPlaymodeStateChanged; 1039 | #else 1040 | EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged; 1041 | EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged; 1042 | #endif 1043 | } 1044 | 1045 | /// 1046 | /// Remove extra/erroneous lines from a file. 1047 | static void ScrubFile(string path) 1048 | { 1049 | string[] lines = File.ReadAllLines(path); 1050 | System.Collections.Generic.List newLines = new System.Collections.Generic.List(); 1051 | for (int i = 0; i < lines.Length; i++) 1052 | { 1053 | // Check Empty 1054 | if (string.IsNullOrEmpty(lines[i].Trim()) || lines[i].Trim() == "\t" || lines[i].Trim() == "\t\t") 1055 | { 1056 | 1057 | } 1058 | else 1059 | { 1060 | newLines.Add(lines[i]); 1061 | } 1062 | } 1063 | File.WriteAllLines(path, newLines.ToArray()); 1064 | } 1065 | 1066 | /// 1067 | /// Remove extra/erroneous data from project file (content). 1068 | /// 1069 | static string ScrubProjectContent(string content) 1070 | { 1071 | if (content.Length == 0) 1072 | return ""; 1073 | 1074 | #if !UNITY_EDITOR_WIN 1075 | // Moved to 3.5, 2.0 is legacy. 1076 | if (content.IndexOf("v3.5") != -1) 1077 | { 1078 | content = Regex.Replace(content, "v3.5", "v2.0"); 1079 | } 1080 | #endif 1081 | 1082 | string targetPath = "";// "Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + ""; //OutputPath 1083 | string langVersion = "default"; 1084 | 1085 | 1086 | bool found = true; 1087 | int location = 0; 1088 | string addedOptions = ""; 1089 | int startLocation = -1; 1090 | int endLocation = -1; 1091 | int endLength = 0; 1092 | 1093 | while (found) 1094 | { 1095 | startLocation = -1; 1096 | endLocation = -1; 1097 | endLength = 0; 1098 | addedOptions = ""; 1099 | startLocation = content.IndexOf("", startLocation); 1105 | endLength = (endLocation - startLocation); 1106 | 1107 | 1108 | if (endLocation == -1) 1109 | { 1110 | found = false; 1111 | continue; 1112 | } 1113 | else 1114 | { 1115 | found = true; 1116 | location = endLocation; 1117 | } 1118 | 1119 | if (content.Substring(startLocation, endLength).IndexOf("") == -1) 1120 | { 1121 | addedOptions += "\n\r\t" + targetPath + "\n\r"; 1122 | } 1123 | 1124 | if (content.Substring(startLocation, endLength).IndexOf("") == -1) 1125 | { 1126 | addedOptions += "\n\r\t" + langVersion + "\n\r"; 1127 | } 1128 | 1129 | if (!string.IsNullOrEmpty(addedOptions)) 1130 | { 1131 | content = content.Substring(0, endLocation) + addedOptions + content.Substring(endLocation); 1132 | } 1133 | } 1134 | else 1135 | { 1136 | found = false; 1137 | } 1138 | } 1139 | 1140 | return content; 1141 | } 1142 | 1143 | /// 1144 | /// Remove extra/erroneous data from solution file (content). 1145 | /// 1146 | static string ScrubSolutionContent(string content) 1147 | { 1148 | // Replace Solution Version 1149 | content = content.Replace( 1150 | "Microsoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2008\r\n", 1151 | "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2012"); 1152 | 1153 | // Remove Solution Properties (Unity Junk) 1154 | int startIndex = content.IndexOf("GlobalSection(SolutionProperties) = preSolution"); 1155 | if (startIndex != -1) 1156 | { 1157 | int endIndex = content.IndexOf("EndGlobalSection", startIndex); 1158 | content = content.Substring(0, startIndex) + content.Substring(endIndex + 16); 1159 | } 1160 | 1161 | return content; 1162 | } 1163 | 1164 | /// 1165 | /// Update Visual Studio Code Launch file 1166 | /// 1167 | static void UpdateLaunchFile() 1168 | { 1169 | if (!VSCode.Enabled) 1170 | { 1171 | return; 1172 | } 1173 | else if (VSCode.UseUnityDebugger) 1174 | { 1175 | if (!Directory.Exists(VSCode.SettingsFolder)) 1176 | System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); 1177 | 1178 | // Write out proper formatted JSON (hence no more SimpleJSON here) 1179 | 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}"; 1180 | File.WriteAllText(VSCode.LaunchPath, fileContent); 1181 | } 1182 | else if (VSCode.WriteLaunchFile) 1183 | { 1184 | int port = GetDebugPort(); 1185 | if (port > -1) 1186 | { 1187 | if (!Directory.Exists(VSCode.SettingsFolder)) 1188 | System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); 1189 | 1190 | // Write out proper formatted JSON (hence no more SimpleJSON here) 1191 | 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}"; 1192 | File.WriteAllText(VSCode.LaunchPath, fileContent); 1193 | 1194 | if (VSCode.Debug) 1195 | { 1196 | UnityEngine.Debug.Log("[VSCode] Debug Port Found (" + port + ")"); 1197 | } 1198 | } 1199 | else 1200 | { 1201 | if (VSCode.Debug) 1202 | { 1203 | UnityEngine.Debug.LogWarning("[VSCode] Unable to determine debug port."); 1204 | } 1205 | } 1206 | } 1207 | } 1208 | 1209 | /// 1210 | /// Update Unity Editor Preferences 1211 | /// 1212 | /// Should we turn on this party! 1213 | static void UpdateUnityPreferences(bool enabled) 1214 | { 1215 | if (enabled) 1216 | { 1217 | // App 1218 | if (EditorPrefs.GetString("kScriptsDefaultApp") != CodePath) 1219 | { 1220 | EditorPrefs.SetString("VSCode_PreviousApp", EditorPrefs.GetString("kScriptsDefaultApp")); 1221 | } 1222 | EditorPrefs.SetString("kScriptsDefaultApp", CodePath); 1223 | 1224 | // Arguments 1225 | if (EditorPrefs.GetString("kScriptEditorArgs") != "-r -g `$(File):$(Line)`") 1226 | { 1227 | EditorPrefs.SetString("VSCode_PreviousArgs", EditorPrefs.GetString("kScriptEditorArgs")); 1228 | } 1229 | 1230 | EditorPrefs.SetString("kScriptEditorArgs", "-r -g `$(File):$(Line)`"); 1231 | EditorPrefs.SetString("kScriptEditorArgs" + CodePath, "-r -g `$(File):$(Line)`"); 1232 | 1233 | 1234 | // MonoDevelop Solution 1235 | if (EditorPrefs.GetBool("kMonoDevelopSolutionProperties", false)) 1236 | { 1237 | EditorPrefs.SetBool("VSCode_PreviousMD", true); 1238 | } 1239 | EditorPrefs.SetBool("kMonoDevelopSolutionProperties", false); 1240 | 1241 | // Support Unity Proj (JS) 1242 | if (EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false)) 1243 | { 1244 | EditorPrefs.SetBool("VSCode_PreviousUnityProj", true); 1245 | } 1246 | EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", false); 1247 | 1248 | if (!EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", false)) 1249 | { 1250 | EditorPrefs.SetBool("VSCode_PreviousAttach", false); 1251 | } 1252 | EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true); 1253 | 1254 | } 1255 | else 1256 | { 1257 | // Restore previous app 1258 | if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousApp"))) 1259 | { 1260 | EditorPrefs.SetString("kScriptsDefaultApp", EditorPrefs.GetString("VSCode_PreviousApp")); 1261 | } 1262 | 1263 | // Restore previous args 1264 | if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousArgs"))) 1265 | { 1266 | EditorPrefs.SetString("kScriptEditorArgs", EditorPrefs.GetString("VSCode_PreviousArgs")); 1267 | } 1268 | 1269 | // Restore MD setting 1270 | if (EditorPrefs.GetBool("VSCode_PreviousMD", false)) 1271 | { 1272 | EditorPrefs.SetBool("kMonoDevelopSolutionProperties", true); 1273 | } 1274 | 1275 | // Restore MD setting 1276 | if (EditorPrefs.GetBool("VSCode_PreviousUnityProj", false)) 1277 | { 1278 | EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", true); 1279 | } 1280 | 1281 | // Always leave editor attaching on, I know, it solves the problem of needing to restart for this 1282 | // to actually work 1283 | EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true); 1284 | } 1285 | 1286 | if (!alreadyFixedPreferences) 1287 | { 1288 | alreadyFixedPreferences = true; 1289 | FixUnityPreferences(); 1290 | } 1291 | } 1292 | 1293 | /// 1294 | /// Determines if the current path to the code executable is valid or not (exists) 1295 | /// 1296 | static bool VSCodeExists(string curPath) 1297 | { 1298 | #if UNITY_EDITOR_OSX 1299 | return System.IO.Directory.Exists(curPath); 1300 | #else 1301 | System.IO.FileInfo code = new System.IO.FileInfo(curPath); 1302 | return code.Exists; 1303 | #endif 1304 | } 1305 | 1306 | /// 1307 | /// Write Default Workspace Settings 1308 | /// 1309 | static void WriteWorkspaceSettings() 1310 | { 1311 | if (Debug) 1312 | { 1313 | UnityEngine.Debug.Log("[VSCode] Workspace Settings Written"); 1314 | } 1315 | 1316 | if (!Directory.Exists(VSCode.SettingsFolder)) 1317 | { 1318 | System.IO.Directory.CreateDirectory(VSCode.SettingsFolder); 1319 | } 1320 | 1321 | string exclusions = 1322 | // Associations 1323 | "{\n" + 1324 | "\t\"files.associations\":\n" + 1325 | "\t{\n" + 1326 | "\t\t\"*.bjs\":\"javascript\",\n" + 1327 | "\t\t\"*.javascript\":\"javascript\"\n" + 1328 | "\t},\n" + 1329 | "\t\"files.exclude\":\n" + 1330 | "\t{\n" + 1331 | // Hidden Files 1332 | "\t\t\"**/.DS_Store\":true,\n" + 1333 | "\t\t\"**/.git\":true,\n" + 1334 | "\t\t\"**/.gitignore\":true,\n" + 1335 | "\t\t\"**/.gitattributes\":true,\n" + 1336 | "\t\t\"**/.gitmodules\":true,\n" + 1337 | "\t\t\"**/.svn\":true,\n" + 1338 | 1339 | // Compressed Files 1340 | "\t\t\"**/*.zip\":true,\n" + 1341 | "\t\t\"**/*.gz\":true,\n" + 1342 | "\t\t\"**/*.7z\":true,\n" + 1343 | 1344 | // Project Files 1345 | "\t\t\"**/*.booproj\":true,\n" + 1346 | "\t\t\"**/*.pidb\":true,\n" + 1347 | "\t\t\"**/*.suo\":true,\n" + 1348 | "\t\t\"**/*.user\":true,\n" + 1349 | "\t\t\"**/*.userprefs\":true,\n" + 1350 | "\t\t\"**/*.unityproj\":true,\n" + 1351 | "\t\t\"**/*.dll\":true,\n" + 1352 | "\t\t\"**/*.exe\":true,\n" + 1353 | 1354 | // Media Files 1355 | "\t\t\"**/*.pdf\":true,\n" + 1356 | 1357 | // Video 1358 | "\t\t\"**/*.mp4\":true,\n" + 1359 | 1360 | // Audio 1361 | "\t\t\"**/*.mid\":true,\n" + 1362 | "\t\t\"**/*.midi\":true,\n" + 1363 | "\t\t\"**/*.wav\":true,\n" + 1364 | "\t\t\"**/*.mp3\":true,\n" + 1365 | "\t\t\"**/*.ogg\":true,\n" + 1366 | 1367 | // Textures 1368 | "\t\t\"**/*.gif\":true,\n" + 1369 | "\t\t\"**/*.ico\":true,\n" + 1370 | "\t\t\"**/*.jpg\":true,\n" + 1371 | "\t\t\"**/*.jpeg\":true,\n" + 1372 | "\t\t\"**/*.png\":true,\n" + 1373 | "\t\t\"**/*.psd\":true,\n" + 1374 | "\t\t\"**/*.tga\":true,\n" + 1375 | "\t\t\"**/*.tif\":true,\n" + 1376 | "\t\t\"**/*.tiff\":true,\n" + 1377 | "\t\t\"**/*.hdr\":true,\n" + 1378 | "\t\t\"**/*.exr\":true,\n" + 1379 | 1380 | // Models 1381 | "\t\t\"**/*.3ds\":true,\n" + 1382 | "\t\t\"**/*.3DS\":true,\n" + 1383 | "\t\t\"**/*.fbx\":true,\n" + 1384 | "\t\t\"**/*.FBX\":true,\n" + 1385 | "\t\t\"**/*.lxo\":true,\n" + 1386 | "\t\t\"**/*.LXO\":true,\n" + 1387 | "\t\t\"**/*.ma\":true,\n" + 1388 | "\t\t\"**/*.MA\":true,\n" + 1389 | "\t\t\"**/*.obj\":true,\n" + 1390 | "\t\t\"**/*.OBJ\":true,\n" + 1391 | 1392 | // Unity File Types 1393 | "\t\t\"**/*.asset\":true,\n" + 1394 | "\t\t\"**/*.cubemap\":true,\n" + 1395 | "\t\t\"**/*.flare\":true,\n" + 1396 | "\t\t\"**/*.mat\":true,\n" + 1397 | "\t\t\"**/*.meta\":true,\n" + 1398 | "\t\t\"**/*.prefab\":true,\n" + 1399 | "\t\t\"**/*.unity\":true,\n" + 1400 | "\t\t\"**/*.anim\":true,\n" + 1401 | "\t\t\"**/*.controller\":true,\n" + 1402 | 1403 | // Folders 1404 | "\t\t\"build/\":true,\n" + 1405 | "\t\t\"Build/\":true,\n" + 1406 | "\t\t\"Library/\":true,\n" + 1407 | "\t\t\"library/\":true,\n" + 1408 | "\t\t\"obj/\":true,\n" + 1409 | "\t\t\"Obj/\":true,\n" + 1410 | "\t\t\"ProjectSettings/\":true,\r" + 1411 | "\t\t\"temp/\":true,\n" + 1412 | "\t\t\"Temp/\":true\n" + 1413 | "\t}\n" + 1414 | "}"; 1415 | 1416 | // Dont like the replace but it fixes the issue with the JSON 1417 | File.WriteAllText(VSCode.SettingsPath, exclusions); 1418 | } 1419 | 1420 | #endregion 1421 | } 1422 | 1423 | /// 1424 | /// VSCode Asset AssetPostprocessor 1425 | /// This will ensure any time that the project files are generated the VSCode versions will be made 1426 | /// 1427 | /// Undocumented Event 1428 | public class VSCodeAssetPostprocessor : AssetPostprocessor 1429 | { 1430 | /// 1431 | /// On documented, project generation event callback 1432 | /// 1433 | private static void OnGeneratedCSProjectFiles() 1434 | { 1435 | // Force execution of VSCode update 1436 | VSCode.UpdateSolution(); 1437 | } 1438 | } 1439 | } 1440 | --------------------------------------------------------------------------------