Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/AppStateModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static AppStateModel LoadState()
// Read the JSON content from the file
var jsonContent = File.ReadAllText(FilePath);

var loaded = JsonSerializer.Deserialize<AppStateModel>(jsonContent, _deserializerOptions);
var loaded = JsonSerializer.Deserialize<AppStateModel>(jsonContent, JsonSerializationContext.Default.AppStateModel);

Debug.WriteLine(loaded != null ? "Loaded settings file" : "Failed to parse");

Expand All @@ -73,7 +73,7 @@ public static void SaveState(AppStateModel model)
try
{
// Serialize the main dictionary to JSON and save it to the file
var settingsJson = JsonSerializer.Serialize(model, _serializerOptions);
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.AppStateModel);

// Is it valid JSON?
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
Expand All @@ -89,7 +89,7 @@ public static void SaveState(AppStateModel model)
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
}

var serialized = savedSettings.ToJsonString(_serializerOptions);
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel.Options);
File.WriteAllText(FilePath, serialized);

// TODO: Instead of just raising the event here, we should
Expand Down Expand Up @@ -122,18 +122,19 @@ internal static string StateJsonPath()
return Path.Combine(directory, "state.json");
}

private static readonly JsonSerializerOptions _serializerOptions = new()
{
WriteIndented = true,
Converters = { new JsonStringEnumConverter() },
};

private static readonly JsonSerializerOptions _deserializerOptions = new()
{
PropertyNameCaseInsensitive = true,
IncludeFields = true,
AllowTrailingCommas = true,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate,
ReadCommentHandling = JsonCommentHandling.Skip,
};
// [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
// private static readonly JsonSerializerOptions _serializerOptions = new()
// {
// WriteIndented = true,
// Converters = { new JsonStringEnumConverter() },
// };

// private static readonly JsonSerializerOptions _deserializerOptions = new()
// {
// PropertyNameCaseInsensitive = true,
// IncludeFields = true,
// AllowTrailingCommas = true,
// PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate,
// ReadCommentHandling = JsonCommentHandling.Skip,
// };
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
{
public CreatedExtensionForm(string name, string displayName, string path)
{
var serializeString = (string? s) => JsonSerializer.Serialize(s, JsonSerializationContext.Default.String);
TemplateJson = CardTemplate;
DataJson = $$"""
{
"name": {{JsonSerializer.Serialize(name)}},
"directory": {{JsonSerializer.Serialize(path)}},
"displayName": {{JsonSerializer.Serialize(displayName)}}
"name": {{serializeString(name)}},
"directory": {{serializeString(path)}},
"displayName": {{serializeString(displayName)}}
}
""";
_name = name;
Expand All @@ -28,13 +29,13 @@ public CreatedExtensionForm(string name, string displayName, string path)

public override ICommandResult SubmitForm(string inputs, string data)
{
JsonObject? dataInput = JsonNode.Parse(data)?.AsObject();
var dataInput = JsonNode.Parse(data)?.AsObject();
if (dataInput == null)
{
return CommandResult.KeepOpen();
}

string verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
var verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
return verb switch
{
"sln" => OpenSolution(),
Expand All @@ -47,15 +48,15 @@ public override ICommandResult SubmitForm(string inputs, string data)
private ICommandResult OpenSolution()
{
string[] parts = [_path, _name, $"{_name}.sln"];
string pathToSolution = Path.Combine(parts);
var pathToSolution = Path.Combine(parts);
ShellHelpers.OpenInShell(pathToSolution);
return CommandResult.Hide();
}

private ICommandResult OpenDirectory()
{
string[] parts = [_path, _name];
string pathToDir = Path.Combine(parts);
var pathToDir = Path.Combine(parts);
ShellHelpers.OpenInShell(pathToDir);
return CommandResult.Hide();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,8 @@ private void CreateExtension(string extensionName, string newDisplayName, string
Directory.Delete(tempDir, true);
}

private string FormatJsonString(string str)
{
private string FormatJsonString(string str) =>

// Escape the string for JSON
return JsonSerializer.Serialize(str);
}
JsonSerializer.Serialize(str, JsonSerializationContext.Default.String);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ public override void InitializeProperties()
// If we fail to parse the card JSON, then display _our own card_
// with the exception
AdaptiveCardTemplate template = new(ErrorCardJson);
var serializeString = (string? s) => JsonSerializer.Serialize(s, JsonSerializationContext.Default.String);

// todo: we could probably stick Card.Errors in there too
var dataJson = $$"""
{
"error_message": {{JsonSerializer.Serialize(e.Message)}},
"error_stack": {{JsonSerializer.Serialize(e.StackTrace)}},
"inner_exception": {{JsonSerializer.Serialize(e.InnerException?.Message)}},
"template_json": {{JsonSerializer.Serialize(TemplateJson)}},
"data_json": {{JsonSerializer.Serialize(DataJson)}}
"error_message": {{serializeString(e.Message)}},
"error_stack": {{serializeString(e.StackTrace)}},
"inner_exception": {{serializeString(e.InnerException?.Message)}},
"template_json": {{serializeString(TemplateJson)}},
"data_json": {{serializeString(DataJson)}}
}
""";
var cardJson = template.Expand(dataJson);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />

<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -67,4 +69,15 @@
</Content>
</ItemGroup>

<!-- Just mark it as AOT compatible. Do not publish with AOT now. We need fully test before we really publish it as AOT enabled-->
<!--<PropertyGroup>
<SelfContained>true</SelfContained>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
--><!-- <DisableRuntimeMarshalling>true</DisableRuntimeMarshalling> --><!--
<PublishAot>true</PublishAot>
<EnableMsixTooling>true</EnableMsixTooling>
</PropertyGroup>-->

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Microsoft.CmdPal.UI.ViewModels.Models;

public class ExtensionService : IExtensionService, IDisposable
public partial class ExtensionService : IExtensionService, IDisposable
{
public event TypedEventHandler<IExtensionService, IEnumerable<IExtensionWrapper>>? OnExtensionAdded;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Windows.Win32.System.Com;
using WinRT;

// [assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]
namespace Microsoft.CmdPal.UI.ViewModels.Models;

public class ExtensionWrapper : IExtensionWrapper
Expand Down Expand Up @@ -113,25 +114,36 @@ await Task.Run(() =>
// -2147467262: E_NOINTERFACE
// -2147024893: E_PATH_NOT_FOUND
var guid = typeof(IExtension).GUID;
var hr = PInvoke.CoCreateInstance(Guid.Parse(ExtensionClassId), null, CLSCTX.CLSCTX_LOCAL_SERVER, guid, out var extensionObj);

if (hr.Value == -2147024893)
unsafe
{
Logger.LogDebug($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");

// We don't really need to throw this exception.
// We'll just return out nothing.
return;
var hr = PInvoke.CoCreateInstance(Guid.Parse(ExtensionClassId), null, CLSCTX.CLSCTX_LOCAL_SERVER, guid, out var extensionObj);

if (hr.Value == -2147024893)
{
Logger.LogDebug($"Failed to find {ExtensionDisplayName}: {hr}. It may have been uninstalled or deleted.");

// We don't really need to throw this exception.
// We'll just return out nothing.
return;
}

extensionPtr = Marshal.GetIUnknownForObject((nint)extensionObj);
if (hr < 0)
{
Logger.LogDebug($"Failed to instantiate {ExtensionDisplayName}: {hr}");
Marshal.ThrowExceptionForHR(hr);
}

// extensionPtr = Marshal.GetIUnknownForObject(extensionObj);
extensionPtr = (nint)extensionObj;
if (hr < 0)
{
Marshal.ThrowExceptionForHR(hr);
}

_extensionObject = MarshalInterface<IExtension>.FromAbi(extensionPtr);
}

extensionPtr = Marshal.GetIUnknownForObject(extensionObj);
if (hr < 0)
{
Logger.LogDebug($"Failed to instantiate {ExtensionDisplayName}: {hr}");
Marshal.ThrowExceptionForHR(hr);
}

_extensionObject = MarshalInterface<IExtension>.FromAbi(extensionPtr);
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://aka.ms/CsWin32.schema.json",
"allowMarshaling": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private void UpdateHasStatusMessage()

//// Run on background thread from ListPage.xaml.cs
[RelayCommand]
private Task<bool> InitializeAsync()
internal Task<bool> InitializeAsync()
{
// TODO: We may want a SemaphoreSlim lock here.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
public partial class RecentCommandsManager : ObservableObject
{
[JsonInclude]
private List<HistoryItem> History { get; set; } = [];
internal List<HistoryItem> History { get; set; } = [];

public RecentCommandsManager()
{
Expand Down
45 changes: 30 additions & 15 deletions src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/SettingsModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static SettingsModel LoadSettings()
// Read the JSON content from the file
var jsonContent = File.ReadAllText(FilePath);

var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, _deserializerOptions);
var loaded = JsonSerializer.Deserialize<SettingsModel>(jsonContent, JsonSerializationContext.Default.SettingsModel);

Debug.WriteLine(loaded != null ? "Loaded settings file" : "Failed to parse");

Expand All @@ -117,7 +117,7 @@ public static void SaveSettings(SettingsModel model)
try
{
// Serialize the main dictionary to JSON and save it to the file
var settingsJson = JsonSerializer.Serialize(model, _serializerOptions);
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.SettingsModel);

// Is it valid JSON?
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
Expand All @@ -133,7 +133,7 @@ public static void SaveSettings(SettingsModel model)
savedSettings[item.Key] = item.Value != null ? item.Value.DeepClone() : null;
}

var serialized = savedSettings.ToJsonString(_serializerOptions);
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.Options);
File.WriteAllText(FilePath, serialized);

// TODO: Instead of just raising the event here, we should
Expand Down Expand Up @@ -166,19 +166,34 @@ internal static string SettingsJsonPath()
return Path.Combine(directory, "settings.json");
}

private static readonly JsonSerializerOptions _serializerOptions = new()
{
WriteIndented = true,
Converters = { new JsonStringEnumConverter() },
};
// [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "<Pending>")]
// private static readonly JsonSerializerOptions _serializerOptions = new()
// {
// WriteIndented = true,
// Converters = { new JsonStringEnumConverter() },
// };
// private static readonly JsonSerializerOptions _deserializerOptions = new()
// {
// PropertyNameCaseInsensitive = true,
// IncludeFields = true,
// Converters = { new JsonStringEnumConverter() },
// AllowTrailingCommas = true,
// };
}

private static readonly JsonSerializerOptions _deserializerOptions = new()
{
PropertyNameCaseInsensitive = true,
IncludeFields = true,
Converters = { new JsonStringEnumConverter() },
AllowTrailingCommas = true,
};
[JsonSerializable(typeof(float))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(HistoryItem))]
[JsonSerializable(typeof(SettingsModel))]
[JsonSerializable(typeof(AppStateModel))]
[JsonSerializable(typeof(List<HistoryItem>), TypeInfoPropertyName = "HistoryList")]
[JsonSerializable(typeof(Dictionary<string, object>), TypeInfoPropertyName = "Dictionary")]
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
internal sealed partial class JsonSerializationContext : JsonSerializerContext
{
}

public enum MonitorBehavior
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ public void LoadPageViewModel(PageViewModel viewModel)
// TODO GH #239 switch back when using the new MD text block
// _ = _queue.EnqueueAsync(() =>
_ = Task.Factory.StartNew(
() =>
async () =>
{
var result = (bool)viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault()!;
// bool f = await viewModel.InitializeCommand.ExecutionTask.;
// var result = viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault()!;
// var result = viewModel.InitializeCommand.ExecutionTask.GetResultOrDefault<bool?>()!;
var result = await viewModel.InitializeAsync();
Comment on lines +112 to +117

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh noooo this was so very wrong.

This didn't get the result of the existing async task, no.

This started the init again. This time, on the UI thread.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh... we need to fix it.

Do we need to release a new version for it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got the PR up in #39415. We can include it in a servicing release.


CurrentPage = viewModel; // result ? viewModel : null;
////LoadedState = result ? ViewModelLoadedState.Loaded : ViewModelLoadedState.Error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ public AddBookmarkForm(BookmarkData? bookmark)
"style": "text",
"id": "name",
"label": "{{Resources.bookmarks_form_name_label}}",
"value": {{JsonSerializer.Serialize(name)}},
"value": {{JsonSerializer.Serialize(name, BookmarkSerializationContext.Default.String)}},
"isRequired": true,
"errorMessage": "{{Resources.bookmarks_form_name_required}}"
},
{
"type": "Input.Text",
"style": "text",
"id": "bookmark",
"value": {{JsonSerializer.Serialize(url)}},
"value": {{JsonSerializer.Serialize(url, BookmarkSerializationContext.Default.String)}},
"label": "{{Resources.bookmarks_form_bookmark_label}}",
"isRequired": true,
"errorMessage": "{{Resources.bookmarks_form_bookmark_required}}"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Microsoft.CmdPal.Ext.Bookmarks;

[JsonSerializable(typeof(float))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(bool))]
[JsonSerializable(typeof(BookmarkData))]
[JsonSerializable(typeof(Bookmarks))]
[JsonSerializable(typeof(List<BookmarkData>), TypeInfoPropertyName = "BookmarkList")]
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true, IncludeFields = true, PropertyNameCaseInsensitive = true, AllowTrailingCommas = true)]
internal sealed partial class BookmarkSerializationContext : JsonSerializerContext
{
}
Loading