mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
Cmdpal extension: Powertoys extension for cmdpal (#44006)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Installer built, and every command works as expected, Now use sparse app deployment, so we don't need an extra msix --------- Co-authored-by: kaitao-ms <kaitao1105@gmail.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
// 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.Text.Json.Serialization;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public struct ApplicationWrapper
|
||||
{
|
||||
public struct WindowPositionWrapper
|
||||
{
|
||||
[JsonPropertyName("x")]
|
||||
public int X { get; set; }
|
||||
|
||||
[JsonPropertyName("y")]
|
||||
public int Y { get; set; }
|
||||
|
||||
[JsonPropertyName("width")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonPropertyName("height")]
|
||||
public int Height { get; set; }
|
||||
}
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonPropertyName("application")]
|
||||
public string Application { get; set; }
|
||||
|
||||
[JsonPropertyName("application-path")]
|
||||
public string ApplicationPath { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("package-full-name")]
|
||||
public string PackageFullName { get; set; }
|
||||
|
||||
[JsonPropertyName("app-user-model-id")]
|
||||
public string AppUserModelId { get; set; }
|
||||
|
||||
[JsonPropertyName("pwa-app-id")]
|
||||
public string PwaAppId { get; set; }
|
||||
|
||||
[JsonPropertyName("command-line-arguments")]
|
||||
public string CommandLineArguments { get; set; }
|
||||
|
||||
[JsonPropertyName("is-elevated")]
|
||||
public bool IsElevated { get; set; }
|
||||
|
||||
[JsonPropertyName("can-launch-elevated")]
|
||||
public bool CanLaunchElevated { get; set; }
|
||||
|
||||
[JsonPropertyName("minimized")]
|
||||
public bool Minimized { get; set; }
|
||||
|
||||
[JsonPropertyName("maximized")]
|
||||
public bool Maximized { get; set; }
|
||||
|
||||
[JsonPropertyName("position")]
|
||||
public WindowPositionWrapper Position { get; set; }
|
||||
|
||||
[JsonPropertyName("monitor")]
|
||||
public int Monitor { get; set; }
|
||||
|
||||
[JsonPropertyName("version")]
|
||||
public string Version { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public enum InvokePoint
|
||||
{
|
||||
EditorButton = 0,
|
||||
Shortcut,
|
||||
LaunchAndEdit,
|
||||
CommandPaletteExtension,
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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.Text.Json.Serialization;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public struct MonitorConfigurationWrapper
|
||||
{
|
||||
public struct MonitorRectWrapper
|
||||
{
|
||||
[JsonPropertyName("top")]
|
||||
public int Top { get; set; }
|
||||
|
||||
[JsonPropertyName("left")]
|
||||
public int Left { get; set; }
|
||||
|
||||
[JsonPropertyName("width")]
|
||||
public int Width { get; set; }
|
||||
|
||||
[JsonPropertyName("height")]
|
||||
public int Height { get; set; }
|
||||
}
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonPropertyName("instance-id")]
|
||||
public string InstanceId { get; set; }
|
||||
|
||||
[JsonPropertyName("monitor-number")]
|
||||
public int MonitorNumber { get; set; }
|
||||
|
||||
[JsonPropertyName("dpi")]
|
||||
public int Dpi { get; set; }
|
||||
|
||||
[JsonPropertyName("monitor-rect-dpi-aware")]
|
||||
public MonitorRectWrapper MonitorRectDpiAware { get; set; }
|
||||
|
||||
[JsonPropertyName("monitor-rect-dpi-unaware")]
|
||||
public MonitorRectWrapper MonitorRectDpiUnaware { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// 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 WorkspacesCsharpLibrary.Data;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public class ProjectData : WorkspacesEditorData<ProjectWrapper>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public struct ProjectWrapper
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public long CreationTime { get; set; }
|
||||
|
||||
public long LastLaunchedTime { get; set; }
|
||||
|
||||
public bool IsShortcutNeeded { get; set; }
|
||||
|
||||
public bool MoveExistingWindows { get; set; }
|
||||
|
||||
public List<MonitorConfigurationWrapper> MonitorConfiguration { get; set; }
|
||||
|
||||
public List<ApplicationWrapper> Applications { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 WorkspacesCsharpLibrary.Data;
|
||||
using WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data
|
||||
{
|
||||
public class TempProjectData : ProjectData
|
||||
{
|
||||
public static string File => FolderUtils.DataFolder() + "\\temp-workspaces.json";
|
||||
|
||||
public static void DeleteTempFile()
|
||||
{
|
||||
if (System.IO.File.Exists(File))
|
||||
{
|
||||
System.IO.File.Delete(File);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 WorkspacesCsharpLibrary.Utils;
|
||||
using static WorkspacesCsharpLibrary.Data.WorkspacesData;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
public class WorkspacesData : WorkspacesEditorData<WorkspacesListWrapper>
|
||||
{
|
||||
public string File => FolderUtils.DataFolder() + "\\workspaces.json";
|
||||
|
||||
public struct WorkspacesListWrapper
|
||||
{
|
||||
public List<ProjectWrapper> Workspaces { get; set; }
|
||||
}
|
||||
|
||||
public enum OrderBy
|
||||
{
|
||||
LastViewed = 0,
|
||||
Created = 1,
|
||||
Name = 2,
|
||||
Unknown = 3,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Shared JSON serializer helper for Workspaces payloads.
|
||||
/// </summary>
|
||||
public class WorkspacesEditorData<T>
|
||||
{
|
||||
[RequiresUnreferencedCode("JSON serialization uses reflection-based serializer.")]
|
||||
[RequiresDynamicCode("JSON serialization uses reflection-based serializer.")]
|
||||
public T Read(string file)
|
||||
{
|
||||
IOUtils ioUtils = new();
|
||||
string data = ioUtils.ReadFile(file);
|
||||
return JsonSerializer.Deserialize<T>(data, WorkspacesJsonOptions.EditorOptions)!;
|
||||
}
|
||||
|
||||
[RequiresUnreferencedCode("JSON serialization uses reflection-based serializer.")]
|
||||
[RequiresDynamicCode("JSON serialization uses reflection-based serializer.")]
|
||||
public string Serialize(T data)
|
||||
{
|
||||
return JsonSerializer.Serialize(data, WorkspacesJsonOptions.EditorOptions);
|
||||
}
|
||||
|
||||
[RequiresUnreferencedCode("JSON serialization uses reflection-based serializer.")]
|
||||
[RequiresDynamicCode("JSON serialization uses reflection-based serializer.")]
|
||||
public T Deserialize(string json)
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(json, WorkspacesJsonOptions.EditorOptions)!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.Text.Json;
|
||||
using WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
internal static class WorkspacesJsonOptions
|
||||
{
|
||||
internal static readonly JsonSerializerOptions EditorOptions = new()
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
WriteIndented = true,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Lightweight reader for persisted workspaces.
|
||||
/// </summary>
|
||||
public static class WorkspacesStorage
|
||||
{
|
||||
public static IReadOnlyList<ProjectWrapper> Load()
|
||||
{
|
||||
var filePath = GetDefaultFilePath();
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var data = JsonSerializer.Deserialize(json, WorkspacesStorageJsonContext.Default.WorkspacesFile);
|
||||
|
||||
if (data?.Workspaces == null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return data.Workspaces
|
||||
.Where(ws => !string.IsNullOrWhiteSpace(ws.Id) && !string.IsNullOrWhiteSpace(ws.Name))
|
||||
.Select(ws => new ProjectWrapper
|
||||
{
|
||||
Id = ws.Id!,
|
||||
Name = ws.Name!,
|
||||
Applications = ws.Applications ?? new List<ApplicationWrapper>(),
|
||||
CreationTime = ws.CreationTime,
|
||||
LastLaunchedTime = ws.LastLaunchedTime,
|
||||
IsShortcutNeeded = ws.IsShortcutNeeded,
|
||||
MoveExistingWindows = ws.MoveExistingWindows,
|
||||
MonitorConfiguration = ws.MonitorConfiguration ?? new List<MonitorConfigurationWrapper>(),
|
||||
})
|
||||
.ToList()
|
||||
.AsReadOnly();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Array.Empty<ProjectWrapper>();
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetDefaultFilePath()
|
||||
{
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
return Path.Combine(localAppData, "Microsoft", "PowerToys", "Workspaces", "workspaces.json");
|
||||
}
|
||||
|
||||
internal sealed class WorkspacesFile
|
||||
{
|
||||
public List<WorkspaceProject> Workspaces { get; set; } = new();
|
||||
}
|
||||
|
||||
internal sealed class WorkspaceProject
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("applications")]
|
||||
public List<ApplicationWrapper> Applications { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("monitor-configuration")]
|
||||
public List<MonitorConfigurationWrapper> MonitorConfiguration { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("creation-time")]
|
||||
public long CreationTime { get; set; }
|
||||
|
||||
[JsonPropertyName("last-launched-time")]
|
||||
public long LastLaunchedTime { get; set; }
|
||||
|
||||
[JsonPropertyName("is-shortcut-needed")]
|
||||
public bool IsShortcutNeeded { get; set; }
|
||||
|
||||
[JsonPropertyName("move-existing-windows")]
|
||||
public bool MoveExistingWindows { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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.Text.Json.Serialization;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Data;
|
||||
|
||||
[JsonSourceGenerationOptions(PropertyNameCaseInsensitive = true)]
|
||||
[JsonSerializable(typeof(WorkspacesStorage.WorkspacesFile))]
|
||||
[JsonSerializable(typeof(WorkspacesStorage.WorkspaceProject))]
|
||||
[JsonSerializable(typeof(ApplicationWrapper))]
|
||||
[JsonSerializable(typeof(ApplicationWrapper.WindowPositionWrapper))]
|
||||
[JsonSerializable(typeof(MonitorConfigurationWrapper))]
|
||||
[JsonSerializable(typeof(MonitorConfigurationWrapper.MonitorRectWrapper))]
|
||||
internal sealed partial class WorkspacesStorageJsonContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -16,7 +16,7 @@ using Windows.Management.Deployment;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Models
|
||||
{
|
||||
public class BaseApplication : INotifyPropertyChanged, IDisposable
|
||||
public partial class BaseApplication : INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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.Text.Json;
|
||||
using WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
public class DashCaseNamingPolicy : JsonNamingPolicy
|
||||
{
|
||||
public static DashCaseNamingPolicy Instance { get; } = new DashCaseNamingPolicy();
|
||||
|
||||
public override string ConvertName(string name)
|
||||
{
|
||||
return name.UpperCamelCaseToDashCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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;
|
||||
using System.IO;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
public class FolderUtils
|
||||
{
|
||||
public static string Desktop()
|
||||
{
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
}
|
||||
|
||||
public static string Temp()
|
||||
{
|
||||
return Path.GetTempPath();
|
||||
}
|
||||
|
||||
// Note: the same path should be used in SnapshotTool and Launcher
|
||||
public static string DataFolder()
|
||||
{
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\Workspaces";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
public class IOUtils
|
||||
{
|
||||
private readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
public void WriteFile(string fileName, string data)
|
||||
{
|
||||
_fileSystem.File.WriteAllText(fileName, data);
|
||||
}
|
||||
|
||||
public string ReadFile(string fileName)
|
||||
{
|
||||
if (_fileSystem.File.Exists(fileName))
|
||||
{
|
||||
int attempts = 0;
|
||||
while (attempts < 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
using FileSystemStream inputStream = _fileSystem.File.Open(fileName, FileMode.Open);
|
||||
using StreamReader reader = new(inputStream);
|
||||
string data = reader.ReadToEnd();
|
||||
inputStream.Close();
|
||||
return data;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Task.Delay(10).Wait();
|
||||
}
|
||||
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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.Linq;
|
||||
|
||||
namespace WorkspacesCsharpLibrary.Utils;
|
||||
|
||||
public static class StringUtils
|
||||
{
|
||||
public static string UpperCamelCaseToDashCase(this string str)
|
||||
{
|
||||
// If it's a single letter variable, leave it as it is
|
||||
return str.Length == 1
|
||||
? str
|
||||
: string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "-" + x : x.ToString())).ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>PowerToys.WorkspacesCsharpLibrary</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys Workspaces Csharp Library</AssemblyDescription>
|
||||
<Description>PowerToys Workspaces Csharp Library</Description>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
@@ -15,4 +17,8 @@
|
||||
<AssemblyName>PowerToys.WorkspacesCsharpLibrary</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user