Skip to content

Commit b90913e

Browse files
committed
Patch vscode setting files
1 parent 128e920 commit b90913e

File tree

1 file changed

+184
-20
lines changed

1 file changed

+184
-20
lines changed

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

Lines changed: 184 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
using System.Text.RegularExpressions;
1212
using UnityEngine;
1313
using IOPath = System.IO.Path;
14-
using System.Runtime.InteropServices;
15-
using System.Text;
14+
using Newtonsoft.Json;
15+
using Newtonsoft.Json.Linq;
1616

1717
namespace Microsoft.Unity.VisualStudio.Editor
1818
{
@@ -44,7 +44,7 @@ private string GetExtensionPath()
4444
return null;
4545

4646
return Directory
47-
.EnumerateDirectories(extensionsPath, "visualstudiotoolsforunity.vstuc*") // publisherid.extensionid
47+
.EnumerateDirectories(extensionsPath, $"{MicrosoftUnityExtensionId}*") // publisherid.extensionid
4848
.OrderByDescending(n => n)
4949
.FirstOrDefault();
5050
}
@@ -193,7 +193,6 @@ public override void CreateExtraFiles(string projectDirectory)
193193
{
194194
try
195195
{
196-
// see https://tattoocoder.com/recommending-vscode-extensions-within-your-open-source-projects/
197196
var vscodeDirectory = IOPath.Combine(projectDirectory.NormalizePathSeparators(), ".vscode");
198197
Directory.CreateDirectory(vscodeDirectory);
199198

@@ -206,31 +205,90 @@ public override void CreateExtraFiles(string projectDirectory)
206205
}
207206
}
208207

209-
private static void CreateLaunchFile(string vscodeDirectory)
210-
{
211-
var launchFile = IOPath.Combine(vscodeDirectory, "launch.json");
212-
if (File.Exists(launchFile))
213-
return;
214-
215-
const string content = @"{
208+
private const string DefaultLaunchFileContent = @"{
216209
""version"": ""0.2.0"",
217210
""configurations"": [
218211
{
219212
""name"": ""Attach to Unity"",
220213
""type"": ""vstuc"",
221-
""request"": ""attach"",
214+
""request"": ""attach""
222215
}
223216
]
224217
}";
225218

226-
File.WriteAllText(launchFile, content);
219+
private static void CreateLaunchFile(string vscodeDirectory)
220+
{
221+
var launchFile = IOPath.Combine(vscodeDirectory, "launch.json");
222+
if (File.Exists(launchFile))
223+
{
224+
PatchLaunchFile(launchFile);
225+
return;
226+
}
227+
228+
File.WriteAllText(launchFile, DefaultLaunchFileContent);
229+
}
230+
231+
private static void PatchLaunchFile(string launchFile)
232+
{
233+
try
234+
{
235+
const string configurationsKey = "configurations";
236+
const string typeKey = "type";
237+
238+
var content = File.ReadAllText(launchFile);
239+
var launch = JObject.Parse(content);
240+
241+
var configurations = (JArray)launch[configurationsKey];
242+
if (configurations == null)
243+
{
244+
configurations = new JArray();
245+
launch.Add(configurationsKey, configurations);
246+
}
247+
248+
var containsVstucEntry = false;
249+
var patched = false;
250+
251+
foreach (var entry in configurations.ToArray())
252+
{
253+
var type = entry[typeKey].Value<string>();
254+
255+
switch (type)
256+
{
257+
case "unity":
258+
entry.Remove();
259+
patched = true;
260+
break;
261+
262+
case "vstuc":
263+
containsVstucEntry = true;
264+
break;
265+
}
266+
}
267+
268+
if (!containsVstucEntry)
269+
{
270+
var defaultContent = JObject.Parse(DefaultLaunchFileContent);
271+
configurations.Add(defaultContent[configurationsKey].First());
272+
patched = true;
273+
}
274+
275+
if (patched)
276+
WriteAllTextFromJObject(launchFile, launch);
277+
}
278+
catch (Exception)
279+
{
280+
// do not fail if we cannot patch the launch.json file
281+
}
227282
}
228283

229284
private void CreateSettingsFile(string vscodeDirectory)
230285
{
231286
var settingsFile = IOPath.Combine(vscodeDirectory, "settings.json");
232287
if (File.Exists(settingsFile))
288+
{
289+
PatchSettingsFile(settingsFile);
233290
return;
291+
}
234292

235293
const string excludes = @" ""files.exclude"":
236294
{
@@ -299,19 +357,125 @@ private void CreateSettingsFile(string vscodeDirectory)
299357
File.WriteAllText(settingsFile, content);
300358
}
301359

302-
private static void CreateRecommendedExtensionsFile(string vscodeDirectory)
360+
private void PatchSettingsFile(string settingsFile)
303361
{
304-
var extensionFile = IOPath.Combine(vscodeDirectory, "extensions.json");
305-
if (File.Exists(extensionFile))
306-
return;
362+
try
363+
{
364+
const string excludesKey = "files.exclude";
365+
const string solutionKey = "dotnet.defaultSolution";
366+
367+
var content = File.ReadAllText(settingsFile);
368+
var settings = JObject.Parse(content);
369+
370+
var excludes = (JObject)settings[excludesKey];
371+
if (excludes == null)
372+
return;
307373

308-
const string content = @"{
374+
var patchList = new List<string>();
375+
var patched = false;
376+
377+
// Remove files.exclude for solution files in the project root
378+
foreach (var exclude in excludes)
379+
{
380+
if (!exclude.Value.Value<bool>())
381+
continue;
382+
383+
if (Regex.IsMatch(exclude.Key, "^(\\*\\*[\\\\\\/])?\\*\\.sln$"))
384+
{
385+
patchList.Add(exclude.Key);
386+
patched = true;
387+
}
388+
}
389+
390+
// Check default solution
391+
var defaultSolution = settings[solutionKey];
392+
var solutionFile = IOPath.GetFileName(ProjectGenerator.SolutionFile());
393+
if (defaultSolution == null || defaultSolution.Value<string>() != solutionFile)
394+
{
395+
settings[solutionKey] = solutionFile;
396+
patched = true;
397+
}
398+
399+
if (patched)
400+
{
401+
foreach (var patch in patchList)
402+
excludes.Remove(patch);
403+
404+
WriteAllTextFromJObject(settingsFile, settings);
405+
}
406+
}
407+
catch (Exception)
408+
{
409+
// do not fail if we cannot patch the settings.json file
410+
}
411+
}
412+
413+
private const string MicrosoftUnityExtensionId = "visualstudiotoolsforunity.vstuc";
414+
private const string DefaultRecommendedExtensionsContent = @"{
309415
""recommendations"": [
310-
""visualstudiotoolsforunity.vstuc""
416+
"""+ MicrosoftUnityExtensionId + @"""
311417
]
312418
}
313419
";
314-
File.WriteAllText(extensionFile, content);
420+
421+
private static void CreateRecommendedExtensionsFile(string vscodeDirectory)
422+
{
423+
// see https://tattoocoder.com/recommending-vscode-extensions-within-your-open-source-projects/
424+
var extensionFile = IOPath.Combine(vscodeDirectory, "extensions.json");
425+
if (File.Exists(extensionFile))
426+
{
427+
PatchRecommendedExtensionsFile(extensionFile);
428+
return;
429+
}
430+
431+
File.WriteAllText(extensionFile, DefaultRecommendedExtensionsContent);
432+
}
433+
434+
private static void PatchRecommendedExtensionsFile(string extensionFile)
435+
{
436+
try
437+
{
438+
const string recommendationsKey = "recommendations";
439+
440+
var content = File.ReadAllText(extensionFile);
441+
var extensions = JObject.Parse(content);
442+
443+
var recommendations = (JArray)extensions[recommendationsKey];
444+
if (recommendations == null)
445+
{
446+
recommendations = new JArray();
447+
extensions.Add(recommendationsKey, recommendations);
448+
}
449+
450+
foreach(var entry in recommendations)
451+
{
452+
if (entry.Value<string>() == MicrosoftUnityExtensionId)
453+
return;
454+
}
455+
456+
recommendations.Add(MicrosoftUnityExtensionId);
457+
WriteAllTextFromJObject(extensionFile, extensions);
458+
}
459+
catch (Exception)
460+
{
461+
// do not fail if we cannot patch the extensions.json file
462+
}
463+
}
464+
465+
private static void WriteAllTextFromJObject(string file, JObject jobject)
466+
{
467+
using (var fs = File.Open(file, FileMode.Create))
468+
using (var sw = new StreamWriter(fs))
469+
using (var jw = new JsonTextWriter(sw))
470+
{
471+
// Keep formatting/indent in sync with default contents
472+
jw.Formatting = Formatting.Indented;
473+
jw.IndentChar = ' ';
474+
jw.Indentation = 4;
475+
476+
var serializer = new JsonSerializer();
477+
serializer.Serialize(jw, jobject);
478+
}
315479
}
316480

317481
public override bool Open(string path, int line, int column, string solution)

0 commit comments

Comments
 (0)