Skip to content

Commit 4c749b0

Browse files
committed
Integrate vscode
1 parent 268443f commit 4c749b0

File tree

4 files changed

+323
-3
lines changed

4 files changed

+323
-3
lines changed

.vsconfig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
{
1+
{
22
"version": "1.0",
3-
"components": [
3+
"components": [
44
"Microsoft.VisualStudio.Workload.ManagedGame"
55
]
6-
}
6+
}

Packages/com.unity.ide.visualstudio/Editor/Discovery.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
* Copyright (c) Microsoft Corporation. All rights reserved.
44
* Licensed under the MIT License. See License.txt in the project root for license information.
55
*--------------------------------------------------------------------------------------------*/
6+
7+
using System;
68
using System.Collections.Generic;
79
using System.IO;
10+
using System.Linq;
11+
using UnityEngine;
812

913
namespace Microsoft.Unity.VisualStudio.Editor
1014
{
@@ -17,6 +21,22 @@ public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallation
1721

1822
foreach (var installation in VisualStudioForMacInstallation.GetVisualStudioInstallations())
1923
yield return installation;
24+
25+
foreach (var installation in VisualStudioCodeInstallation.GetVisualStudioInstallations())
26+
yield return installation;
27+
28+
if (IsLegacyVSCodePackageLoaded())
29+
{
30+
Debug.LogWarning("[Visual Studio Editor] package has now built-in support for the whole Visual Studio family of products, including Visual Studio code. Please remove the legacy [Visual Studio Code Editor] package to avoid incompatibilities.");
31+
}
32+
}
33+
34+
private static bool IsLegacyVSCodePackageLoaded()
35+
{
36+
return AppDomain
37+
.CurrentDomain
38+
.GetAssemblies()
39+
.Any(a => a.FullName.StartsWith("Unity.VSCode.Editor"));
2040
}
2141

2242
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation)
@@ -28,6 +48,9 @@ public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioI
2848

2949
if (VisualStudioForMacInstallation.TryDiscoverInstallation(editorPath, out installation))
3050
return true;
51+
52+
if (VisualStudioCodeInstallation.TryDiscoverInstallation(editorPath, out installation))
53+
return true;
3154
}
3255
catch (IOException)
3356
{
@@ -41,6 +64,7 @@ public static void Initialize()
4164
{
4265
VisualStudioForWindowsInstallation.Initialize();
4366
VisualStudioForMacInstallation.Initialize();
67+
VisualStudioCodeInstallation.Initialize();
4468
}
4569
}
4670
}
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
using System.IO;
10+
using System.Linq;
11+
using System.Text.RegularExpressions;
12+
using IOPath = System.IO.Path;
13+
14+
namespace Microsoft.Unity.VisualStudio.Editor
15+
{
16+
internal class VisualStudioCodeInstallation : VisualStudioInstallation
17+
{
18+
private static readonly IGenerator _generator = new SdkStyleProjectGeneration();
19+
20+
public override bool SupportsAnalyzers
21+
{
22+
get
23+
{
24+
return true;
25+
}
26+
}
27+
28+
public override Version LatestLanguageVersionSupported
29+
{
30+
get
31+
{
32+
return new Version(11, 0);
33+
}
34+
}
35+
36+
private string GetExtensionPath()
37+
{
38+
var vscode = IsPrerelease ? ".vscode-insiders" : ".vscode";
39+
var extensionsPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), vscode, "extensions");
40+
if (!Directory.Exists(extensionsPath))
41+
return null;
42+
43+
return Directory
44+
.EnumerateDirectories(extensionsPath, "visualstudiotoolsforunity.vstuc*") // publisherid.extensionid
45+
.OrderByDescending(n => n)
46+
.FirstOrDefault();
47+
}
48+
49+
public override string[] GetAnalyzers()
50+
{
51+
var vstuPath = GetExtensionPath();
52+
if (string.IsNullOrEmpty(vstuPath))
53+
return Array.Empty<string>();
54+
55+
return GetAnalyzers(vstuPath); }
56+
57+
public override IGenerator ProjectGenerator
58+
{
59+
get
60+
{
61+
return _generator;
62+
}
63+
}
64+
65+
private static bool IsCandidateForDiscovery(string path)
66+
{
67+
if (VisualStudioEditor.IsOSX)
68+
return Directory.Exists(path) && Regex.IsMatch(path, ".*Code.*.app$", RegexOptions.IgnoreCase);
69+
70+
if (VisualStudioEditor.IsWindows)
71+
return File.Exists(path) && Regex.IsMatch(path, ".*Code.*.exe$", RegexOptions.IgnoreCase);
72+
73+
return File.Exists(path) && path.EndsWith("code", StringComparison.OrdinalIgnoreCase);
74+
}
75+
76+
public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation)
77+
{
78+
installation = null;
79+
80+
if (string.IsNullOrEmpty(editorPath))
81+
return false;
82+
83+
if (!IsCandidateForDiscovery(editorPath))
84+
return false;
85+
86+
Version version = null;
87+
bool isPrerelease = false;
88+
89+
if (VisualStudioEditor.IsWindows) {
90+
// On windows we use the executable directly, so we can query extra information
91+
if (!File.Exists(editorPath))
92+
return false;
93+
94+
// VSCode preview are not using the isPrerelease flag so far
95+
var vi = FileVersionInfo.GetVersionInfo(editorPath);
96+
version = new Version(vi.ProductMajorPart, vi.ProductMinorPart, vi.ProductBuildPart);
97+
isPrerelease = vi.IsPreRelease || vi.FileDescription.ToLower().Contains("insider");
98+
} else if (VisualStudioEditor.IsOSX) {
99+
var plist = IOPath.Combine(editorPath, "Contents", "Info.plist");
100+
if (!File.Exists(plist))
101+
return false;
102+
103+
const string pattern = @"<key>CFBundleShortVersionString</key>\s*<string>(?<version>\d+\.\d+\.\d+).*</string>";
104+
var match = Regex.Match(File.ReadAllText(plist), pattern);
105+
if (!match.Success)
106+
return false;
107+
108+
version = new Version(match.Groups[nameof(version)].ToString());
109+
}
110+
111+
isPrerelease = isPrerelease || editorPath.ToLower().Contains("insider");
112+
installation = new VisualStudioCodeInstallation()
113+
{
114+
IsPrerelease = isPrerelease,
115+
Name = "Visual Studio Code" + (isPrerelease ? " - Insider" : string.Empty) + (version != null ? $" [{version.ToString(3)}]" : string.Empty),
116+
Path = editorPath,
117+
Version = version ?? new Version()
118+
};
119+
120+
return true;
121+
}
122+
123+
public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations()
124+
{
125+
var candidates = new List<string>();
126+
127+
if (VisualStudioEditor.IsWindows)
128+
{
129+
var localAppPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs");
130+
candidates.Add(IOPath.Combine(localAppPath, "Microsoft VS Code", "Code.exe"));
131+
candidates.Add(IOPath.Combine(localAppPath, "Microsoft VS Code Insiders", "Code - Insiders.exe"));
132+
} else if (VisualStudioEditor.IsOSX)
133+
{
134+
var appPath = IOPath.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles));
135+
candidates.AddRange(Directory.EnumerateDirectories(appPath, "Visual Studio Code*.app"));
136+
}
137+
else
138+
{
139+
candidates.Add("/usr/bin/code");
140+
candidates.Add("/bin/code");
141+
candidates.Add("/usr/local/bin/code");
142+
}
143+
144+
foreach (var candidate in candidates)
145+
{
146+
if (TryDiscoverInstallation(candidate, out var installation))
147+
yield return installation;
148+
}
149+
}
150+
151+
public override void CreateExtraFiles(string projectDirectory)
152+
{
153+
try
154+
{
155+
// see https://tattoocoder.com/recommending-vscode-extensions-within-your-open-source-projects/
156+
var vscodeDirectory = IOPath.Combine(projectDirectory.NormalizePathSeparators(), ".vscode");
157+
Directory.CreateDirectory(vscodeDirectory);
158+
159+
CreateRecommendedExtensionsFile(vscodeDirectory);
160+
CreateSettingsFile(vscodeDirectory);
161+
CreateLaunchFile(vscodeDirectory);
162+
}
163+
catch (IOException)
164+
{
165+
}
166+
}
167+
168+
private static void CreateLaunchFile(string vscodeDirectory)
169+
{
170+
var launchFile = IOPath.Combine(vscodeDirectory, "launch.json");
171+
if (File.Exists(launchFile))
172+
return;
173+
}
174+
175+
private static void CreateSettingsFile(string vscodeDirectory)
176+
{
177+
var settingsFile = IOPath.Combine(vscodeDirectory, "settings.json");
178+
if (File.Exists(settingsFile))
179+
return;
180+
181+
const string content = @"{
182+
""files.exclude"":
183+
{
184+
""**/.DS_Store"":true,
185+
""**/.git"":true,
186+
""**/.gitmodules"":true,
187+
""**/*.booproj"":true,
188+
""**/*.pidb"":true,
189+
""**/*.suo"":true,
190+
""**/*.user"":true,
191+
""**/*.userprefs"":true,
192+
""**/*.unityproj"":true,
193+
""**/*.dll"":true,
194+
""**/*.exe"":true,
195+
""**/*.pdf"":true,
196+
""**/*.mid"":true,
197+
""**/*.midi"":true,
198+
""**/*.wav"":true,
199+
""**/*.gif"":true,
200+
""**/*.ico"":true,
201+
""**/*.jpg"":true,
202+
""**/*.jpeg"":true,
203+
""**/*.png"":true,
204+
""**/*.psd"":true,
205+
""**/*.tga"":true,
206+
""**/*.tif"":true,
207+
""**/*.tiff"":true,
208+
""**/*.3ds"":true,
209+
""**/*.3DS"":true,
210+
""**/*.fbx"":true,
211+
""**/*.FBX"":true,
212+
""**/*.lxo"":true,
213+
""**/*.LXO"":true,
214+
""**/*.ma"":true,
215+
""**/*.MA"":true,
216+
""**/*.obj"":true,
217+
""**/*.OBJ"":true,
218+
""**/*.asset"":true,
219+
""**/*.cubemap"":true,
220+
""**/*.flare"":true,
221+
""**/*.mat"":true,
222+
""**/*.meta"":true,
223+
""**/*.prefab"":true,
224+
""**/*.unity"":true,
225+
""build/"":true,
226+
""Build/"":true,
227+
""Library/"":true,
228+
""library/"":true,
229+
""obj/"":true,
230+
""Obj/"":true,
231+
""ProjectSettings/"":true,
232+
""temp/"":true,
233+
""Temp/"":true
234+
}
235+
}";
236+
237+
File.WriteAllText(settingsFile, content);
238+
}
239+
240+
private static void CreateRecommendedExtensionsFile(string vscodeDirectory)
241+
{
242+
var extensionFile = IOPath.Combine(vscodeDirectory, "extensions.json");
243+
if (File.Exists(extensionFile))
244+
return;
245+
246+
const string content = @"{
247+
""recommendations"": [
248+
""ms-dotnettools.csharp""
249+
]
250+
}
251+
";
252+
File.WriteAllText(extensionFile, content);
253+
}
254+
255+
public override bool Open(string path, int line, int column, string solution)
256+
{
257+
line = Math.Max(1, line);
258+
column = Math.Max(0, column);
259+
260+
var directory = IOPath.GetDirectoryName(solution);
261+
var application = Path;
262+
263+
ProcessRunner.Start(string.IsNullOrEmpty(path) ?
264+
ProcessStartInfoFor(application, $"\"{directory}\"") :
265+
ProcessStartInfoFor(application, $"\"{directory}\" -g \"{path}\":{line}:{column}"));
266+
267+
return true;
268+
}
269+
270+
private static ProcessStartInfo ProcessStartInfoFor(string application, string arguments)
271+
{
272+
if (!VisualStudioEditor.IsOSX)
273+
return ProcessRunner.ProcessStartInfoFor(application, arguments, redirect: false);
274+
275+
// wrap with built-in OSX open feature
276+
arguments = $"-n \"{application}\" --args {arguments}";
277+
application = "open";
278+
return ProcessRunner.ProcessStartInfoFor(application, arguments, redirect:false, shell: true);
279+
}
280+
281+
public static void Initialize()
282+
{
283+
}
284+
}
285+
}

Packages/com.unity.ide.visualstudio/Editor/VisualStudioCodeInstallation.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)