VSCodeDiscovery.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Unity.CodeEditor;
  6. namespace VSCodeEditor
  7. {
  8. public interface IDiscovery
  9. {
  10. CodeEditor.Installation[] PathCallback();
  11. }
  12. public class VSCodeDiscovery : IDiscovery
  13. {
  14. List<CodeEditor.Installation> m_Installations;
  15. public CodeEditor.Installation[] PathCallback()
  16. {
  17. if (m_Installations == null)
  18. {
  19. m_Installations = new List<CodeEditor.Installation>();
  20. FindInstallationPaths();
  21. }
  22. return m_Installations.ToArray();
  23. }
  24. void FindInstallationPaths()
  25. {
  26. string[] possiblePaths =
  27. #if UNITY_EDITOR_OSX
  28. {
  29. "/Applications/Visual Studio Code.app",
  30. "/Applications/Visual Studio Code - Insiders.app"
  31. };
  32. #elif UNITY_EDITOR_WIN
  33. {
  34. GetProgramFiles() + @"/Microsoft VS Code/bin/code.cmd",
  35. GetProgramFiles() + @"/Microsoft VS Code/Code.exe",
  36. GetProgramFiles() + @"/Microsoft VS Code Insiders/bin/code-insiders.cmd",
  37. GetProgramFiles() + @"/Microsoft VS Code Insiders/Code.exe",
  38. GetLocalAppData() + @"/Programs/Microsoft VS Code/bin/code.cmd",
  39. GetLocalAppData() + @"/Programs/Microsoft VS Code/Code.exe",
  40. GetLocalAppData() + @"/Programs/Microsoft VS Code Insiders/bin/code-insiders.cmd",
  41. GetLocalAppData() + @"/Programs/Microsoft VS Code Insiders/Code.exe",
  42. };
  43. #else
  44. {
  45. "/usr/bin/code",
  46. "/bin/code",
  47. "/usr/local/bin/code",
  48. "/var/lib/flatpak/exports/bin/com.visualstudio.code",
  49. "/snap/current/bin/code"
  50. };
  51. #endif
  52. var existingPaths = possiblePaths.Where(VSCodeExists).ToList();
  53. if (!existingPaths.Any())
  54. {
  55. return;
  56. }
  57. var lcp = GetLongestCommonPrefix(existingPaths);
  58. switch (existingPaths.Count)
  59. {
  60. case 1:
  61. {
  62. var path = existingPaths.First();
  63. m_Installations = new List<CodeEditor.Installation>
  64. {
  65. new CodeEditor.Installation
  66. {
  67. Path = path,
  68. Name = path.Contains("Insiders")
  69. ? "Visual Studio Code Insiders"
  70. : "Visual Studio Code"
  71. }
  72. };
  73. break;
  74. }
  75. case 2 when existingPaths.Any(path => !(path.Substring(lcp.Length).Contains("/") || path.Substring(lcp.Length).Contains("\\"))):
  76. {
  77. goto case 1;
  78. }
  79. default:
  80. {
  81. m_Installations = existingPaths.Select(path => new CodeEditor.Installation
  82. {
  83. Name = $"Visual Studio Code Insiders ({path.Substring(lcp.Length)})",
  84. Path = path
  85. }).ToList();
  86. break;
  87. }
  88. }
  89. }
  90. #if UNITY_EDITOR_WIN
  91. static string GetProgramFiles()
  92. {
  93. return Environment.GetEnvironmentVariable("ProgramFiles")?.Replace("\\", "/");
  94. }
  95. static string GetLocalAppData()
  96. {
  97. return Environment.GetEnvironmentVariable("LOCALAPPDATA")?.Replace("\\", "/");
  98. }
  99. #endif
  100. static string GetLongestCommonPrefix(List<string> paths)
  101. {
  102. var baseLength = paths.First().Length;
  103. for (var pathIndex = 1; pathIndex < paths.Count; pathIndex++)
  104. {
  105. baseLength = Math.Min(baseLength, paths[pathIndex].Length);
  106. for (var i = 0; i < baseLength; i++)
  107. {
  108. if (paths[pathIndex][i] == paths[0][i]) continue;
  109. baseLength = i;
  110. break;
  111. }
  112. }
  113. return paths[0].Substring(0, baseLength);
  114. }
  115. static bool VSCodeExists(string path)
  116. {
  117. #if UNITY_EDITOR_OSX
  118. return System.IO.Directory.Exists(path);
  119. #else
  120. return new FileInfo(path).Exists;
  121. #endif
  122. }
  123. }
  124. }