Skip to content

Commit 7496a47

Browse files
committed
Upgrade to Devlooped.JsonPoke
Fixes #64
1 parent d47eb49 commit 7496a47

3 files changed

Lines changed: 96 additions & 49 deletions

File tree

src/SmallSharp/ActiveDocumentMonitor.cs

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
using System.Diagnostics;
44
using System.IO;
55
using System.Linq;
6-
using System.Threading;
76
using System.Xml.Linq;
87
using Microsoft.VisualStudio.Shell.Interop;
9-
using Newtonsoft.Json;
108
using Newtonsoft.Json.Linq;
119

1210
namespace SmallSharp.Build
@@ -70,42 +68,104 @@ void UpdateStartupFile(string? path)
7068
{
7169
activeFile = path;
7270

71+
#if DEBUG && !CI
72+
//Debugger.Launch();
73+
#endif
74+
7375
if (!string.IsNullOrEmpty(path) &&
7476
path!.IndexOfAny(Path.GetInvalidPathChars()) == -1 &&
7577
startupFiles.TryGetValue(Path.GetFileName(path), out var startupFile))
7678
{
79+
// NOTE: we could skip writing the profiles altogether, since the
80+
// targets already JsonPoke these entries. This causes issues, however,
81+
// when the entries there don't match *exactly* what the compile files
82+
// are (i.e. WSL). In this scenario, the project system remains in an
83+
// in-memory "dirty" state where it doesn't refresh the active debug
84+
// profile anymore because it keeps its own WSL selection around.
7785
var settings = new JObject(
7886
new JProperty("profiles", new JObject(
79-
new JProperty(startupFile, new JObject(
87+
startupFiles.Select(file => new JProperty(file.Key, new JObject(
8088
new JProperty("commandName", "Project")
81-
))
89+
)))
8290
))
8391
);
8492

85-
var json = settings.ToString(Formatting.Indented);
93+
var json = settings.ToString(Newtonsoft.Json.Formatting.Indented);
8694

8795
// Only write if different content.
8896
if (File.Exists(launchProfilesPath) &&
89-
File.ReadAllText(launchProfilesPath) == json)
90-
return;
91-
92-
Directory.CreateDirectory(Path.GetDirectoryName(launchProfilesPath));
93-
File.WriteAllText(launchProfilesPath, json);
97+
File.ReadAllText(launchProfilesPath) != json)
98+
{
99+
Directory.CreateDirectory(Path.GetDirectoryName(launchProfilesPath));
100+
File.WriteAllText(launchProfilesPath, json);
101+
}
94102

95103
try
96104
{
97105
// Get the value as it was exists in the original dictionary,
98106
// since it has to match what the source generator created in the
99107
// launch profiles.
100108
var xdoc = XDocument.Load(userFile);
101-
var active = xdoc
109+
var save = false;
110+
111+
// The additional ActiveCompile is a prerequisite for supporting non-file
112+
// debug profiles, such as WSL. At this point, it's not working, but it's
113+
// will be based on this extra property eventually, so we keep it here.
114+
115+
var activeCompile = xdoc
116+
.Descendants("{http://schemas.microsoft.com/developer/msbuild/2003}ActiveCompile")
117+
.FirstOrDefault();
118+
119+
if (activeCompile == null)
120+
{
121+
var props = xdoc.Root.Elements("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup").LastOrDefault();
122+
if (props == null)
123+
{
124+
props = new XElement("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup");
125+
xdoc.Root.Add(props);
126+
}
127+
activeCompile = new XElement("{http://schemas.microsoft.com/developer/msbuild/2003}ActiveCompile", startupFile);
128+
props.Add(activeCompile);
129+
save = true;
130+
}
131+
132+
if (!startupFile.Equals(activeCompile.Value, StringComparison.OrdinalIgnoreCase))
133+
{
134+
activeCompile.Value = startupFile;
135+
save = true;
136+
}
137+
138+
var activeDebug = xdoc
102139
.Descendants("{http://schemas.microsoft.com/developer/msbuild/2003}ActiveDebugProfile")
103140
.FirstOrDefault();
104141

105-
if (active != null && !startupFile.Equals(active.Value, StringComparison.OrdinalIgnoreCase))
142+
if (activeDebug == null)
143+
{
144+
var props = xdoc.Root.Elements("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup").LastOrDefault();
145+
if (props == null)
146+
{
147+
props = new XElement("{http://schemas.microsoft.com/developer/msbuild/2003}PropertyGroup");
148+
xdoc.Root.Add(props);
149+
}
150+
activeDebug = new XElement("{http://schemas.microsoft.com/developer/msbuild/2003}ActiveDebugProfile", startupFile);
151+
props.Add(activeDebug);
152+
save = true;
153+
}
154+
155+
if (activeDebug.Value != null &&
156+
activeDebug.Value.IndexOfAny(Path.GetInvalidPathChars()) == -1 &&
157+
// TODO: Don't mess with debug profile unless it's a file-like name, so we can support WSL
158+
// Path.HasExtension(activeDebug.Value) &&
159+
!startupFile.Equals(activeDebug.Value, StringComparison.OrdinalIgnoreCase))
160+
{
161+
activeDebug.Value = startupFile;
162+
save = true;
163+
}
164+
165+
if (save)
106166
{
107-
active.Value = startupFile;
108167
xdoc.Save(userFile);
168+
File.SetLastWriteTime(launchProfilesPath, DateTime.Now);
109169
}
110170
}
111171
catch (Exception e)
@@ -186,13 +246,13 @@ int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved)
186246
int IVsRunningDocTableEvents.OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) => 0;
187247
int IVsSelectionEvents.OnElementValueChanged(uint elementid, object varValueOld, object varValueNew) => 0;
188248
int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) => 0;
189-
int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) => throw new NotImplementedException();
190-
int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) => throw new NotImplementedException();
191-
int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) => throw new NotImplementedException();
192-
int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) => throw new NotImplementedException();
193-
int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) => throw new NotImplementedException();
194-
int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution) => throw new NotImplementedException();
195-
int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) => throw new NotImplementedException();
196-
int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved) => throw new NotImplementedException();
249+
int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) => 0;
250+
int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel) => 0;
251+
int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved) => 0;
252+
int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy) => 0;
253+
int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel) => 0;
254+
int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution) => 0;
255+
int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel) => 0;
256+
int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved) => 0;
197257
}
198258
}

src/SmallSharp/SmallSharp.csproj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<PackFolder>build\netstandard2.0</PackFolder>
88
<PackNone>true</PackNone>
99
<PackageReadmeFile>readme.md</PackageReadmeFile>
10+
<GenerateDocumentationFile>false</GenerateDocumentationFile>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
@@ -18,16 +19,16 @@
1819
<PackageReference Include="Microsoft.VisualStudio.OLE.Interop" Version="16.7.30328.74" PrivateAssets="all" />
1920
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop" Version="16.7.30328.74" PrivateAssets="all" />
2021
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.12.0" Version="16.7.30328.74" PrivateAssets="all" />
21-
<PackageReference Include="JsonPoke.MSBuild" Version="1.0.9" GeneratePathProperty="true" Pack="false" />
22-
<PackageReference Include="Newtonsoft.Json" Version="6.0.5" Pack="false" />
22+
<PackageReference Include="JsonPoke" Version="1.1.0" GeneratePathProperty="true" Pack="false" />
23+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" Pack="false" />
2324
</ItemGroup>
2425

2526
<ItemGroup>
2627
<None Include="..\..\readme.md" PackagePath="readme.md" />
2728
<None Update="SmallSharp.targets" CopyToOutputDirectory="PreserveNewest" />
2829
<None Include="..\_._" PackFolder="lib\netstandard2.0" Visible="false" />
29-
<PackageFile Include="tools\JsonPeek.MSBuild.dll" PackagePath="$(PackFolder)\JsonPeek.MSBuild.dll" PackageReference="JsonPoke.MSBuild" Visible="false" />
30-
<PackageFile Include="tools\Newtonsoft.Json.dll" PackagePath="$(PackFolder)\Newtonsoft.Json.dll" PackageReference="JsonPoke.MSBuild" Visible="false" />
30+
<PackageFile Include="build\JsonPoke.dll" PackagePath="$(PackFolder)\JsonPoke.dll" PackageReference="JsonPoke" Visible="false" />
31+
<PackageFile Include="build\Newtonsoft.Json.dll" PackagePath="$(PackFolder)\Newtonsoft.Json.dll" PackageReference="JsonPoke" Visible="false" />
3132
</ItemGroup>
3233

3334
<ItemGroup>

src/SmallSharp/SmallSharp.targets

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
<Project>
22

33
<UsingTask AssemblyFile="SmallSharp.dll" TaskName="MonitorActiveDocument" Condition="'$(BuildingInsideVisualStudio)' == 'true'" />
4-
<UsingTask AssemblyFile="JsonPeek.MSBuild.dll" TaskName="JsonPoke" />
4+
<UsingTask AssemblyFile="JsonPoke.dll" TaskName="JsonPoke" />
55

66
<PropertyGroup>
77
<!-- Excluding top-level files so we can only set to Compile the startup/active one -->
88
<DefaultItemExcludesInProjectFolder>*$(DefaultLanguageSourceExtension)</DefaultItemExcludesInProjectFolder>
99
<UserProjectNamespace>
1010
<Namespace Prefix="msb" Uri="http://schemas.microsoft.com/developer/msbuild/2003" />
1111
</UserProjectNamespace>
12-
<!-- ActiveDebugProfile comes from the .user file, automatically set to the only entry we generate in launchSettings.json -->
1312
<StartupFile>$(ActiveDebugProfile)</StartupFile>
13+
<StartupFile Condition="'$(ActiveDebugProfile)' == '' or !Exists('$(ActiveDebugProfile)')">$(ActiveCompile)</StartupFile>
1414
<StartupFileDependsOn>CollectStartupFile;SelectStartupFile;SelectTopLevelCompile;UpdateLaunchSettings</StartupFileDependsOn>
1515
</PropertyGroup>
1616

1717
<ItemGroup>
1818
<!-- Ensures all top-level files show up in the IDE -->
19-
<None Include="*$(DefaultLanguageSourceExtension)" Exclude="$(ActiveDebugProfile)" />
19+
<None Include="*$(DefaultLanguageSourceExtension)" Exclude="$(ActiveDebugProfile);$(ActiveCompile)" />
2020
<Compile Include="$(ActiveDebugProfile)" Condition="Exists('$(ActiveDebugProfile)')" />
21+
<Compile Include="$(ActiveCompile)" Condition="Exists('$(ActiveCompile)') and '$(ActiveCompile)' != '$(ActiveDebugProfile)'" />
2122
</ItemGroup>
2223

2324
<!-- NOTE: we only require VS16.8+ when running in the IDE, since for CLI builds we just do targets stuff -->
@@ -142,27 +143,12 @@
142143
</Target>
143144

144145
<Target Name="UpdateLaunchSettings">
145-
<PropertyGroup>
146-
<ProfileJsonPath>$(MSBuildProjectDirectory)\Properties\launchSettings.json</ProfileJsonPath>
147-
<!-- Additional metadata to be used for each profile entry -->
148-
<ProfileJsonMetadata>@(StartupFile -> '%(Filename)%(Extension)=')</ProfileJsonMetadata>
149-
<ProfileJsonMetadataNames>@(StartupFile -> '%(Filename)%(Extension)')</ProfileJsonMetadataNames>
150-
</PropertyGroup>
151-
<ItemGroup>
152-
<ProfileJsonCommandName Include="JObject" commandName="Project" />
153-
</ItemGroup>
154-
<CreateItem Include="$(ProfileJsonPath)"
155-
AdditionalMetadata="$(ProfileJsonMetadata)">
156-
<Output ItemName="ProfileJsonWithMetadata" TaskParameter="Include" />
157-
</CreateItem>
158-
<JsonPoke JsonInputPath="$(ProfileJsonPath)"
159-
JObject="@(ProfileJsonWithMetadata)"
160-
Metadata="$(ProfileJsonMetadataNames)"
161-
JPath="profiles" />
162-
<JsonPoke JsonInputPath="$(ProfileJsonPath)"
163-
JObject="@(ProfileJsonCommandName)"
164-
Metadata="commandName"
165-
JPath="$.profiles['%(StartupFile.Filename)%(StartupFile.Extension)']" />
146+
<WriteLinesToFile File="$(MSBuildProjectDirectory)\Properties\launchSettings.json"
147+
Lines="{ }"
148+
Condition="!Exists('$(MSBuildProjectDirectory)\Properties\launchSettings.json')" />
149+
<JsonPoke ContentPath="$(MSBuildProjectDirectory)\Properties\launchSettings.json"
150+
Query="$.profiles['%(StartupFile.Filename)%(StartupFile.Extension)'].commandName"
151+
Value="Project" />
166152
</Target>
167153

168154
<ItemGroup>

0 commit comments

Comments
 (0)