[PT Run] Windows Terminal Plugin (#13367)

* run windows terminal plugin

* fixes
This commit is contained in:
Davide Giacometti
2021-10-05 00:45:41 +02:00
committed by GitHub
parent 7daf35d898
commit cf2ec690db
23 changed files with 1118 additions and 5 deletions

View File

@@ -0,0 +1,25 @@
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers
{
// Application Activation Manager Class
[ComImport]
[Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
public class ApplicationActivationManager : IApplicationActivationManager
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)/*, PreserveSig*/]
public extern IntPtr ActivateApplication([In] string appUserModelId, [In] string arguments, [In] ActivateOptions options, [Out] out uint processId);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public extern IntPtr ActivateForFile([In] string appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] string verb, [Out] out uint processId);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
public extern IntPtr ActivateForProtocol([In] string appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out uint processId);
}
}

View File

@@ -0,0 +1,32 @@
// 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.Runtime.InteropServices;
namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers
{
// Reference : https://github.com/MicrosoftEdge/edge-launcher/blob/108e63df0b4cb5cd9d5e45aa7a264690851ec51d/MIcrosoftEdgeLauncherCsharp/Program.cs
[Flags]
public enum ActivateOptions
{
None = 0x00000000,
DesignMode = 0x00000001,
NoErrorUI = 0x00000002,
NoSplashScreen = 0x00000004,
}
// ApplicationActivationManager
[ComImport]
[Guid("2e941141-7f97-4756-ba1d-9decde894a3d")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IApplicationActivationManager
{
IntPtr ActivateApplication([In] string appUserModelId, [In] string arguments, [In] ActivateOptions options, [Out] out uint processId);
IntPtr ActivateForFile([In] string appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] string verb, [Out] out uint processId);
IntPtr ActivateForProtocol([In] string appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out uint processId);
}
}

View File

@@ -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.
using System.Collections.Generic;
namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers
{
public interface ITerminalQuery
{
IEnumerable<TerminalProfile> GetProfiles();
}
}

View File

@@ -0,0 +1,78 @@
// 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.Text.Json;
namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers
{
public static class TerminalHelper
{
/// <summary>
/// Return the arguments for launch Windows Terminal
/// </summary>
/// <param name="profileName">Name of the Terminal profile</param>
/// <param name="openNewTab">Whether to launch the profile in a new tab</param>
public static string GetArguments(string profileName, bool openNewTab)
{
return openNewTab ? $"--window 0 nt --profile \"{profileName}\"" : $"--profile \"{profileName}\"";
}
/// <summary>
/// Return a list of profiles for the Windows Terminal
/// </summary>
/// <param name="terminal">Windows Terminal package</param>
/// <param name="settingsJson">Content of the settings JSON file of the Terminal</param>
public static List<TerminalProfile> ParseSettings(TerminalPackage terminal, string settingsJson)
{
var profiles = new List<TerminalProfile>();
var options = new JsonDocumentOptions
{
CommentHandling = JsonCommentHandling.Skip,
};
var json = JsonDocument.Parse(settingsJson, options);
json.RootElement.TryGetProperty("profiles", out JsonElement profilesElement);
if (profilesElement.ValueKind != JsonValueKind.Object)
{
return profiles;
}
profilesElement.TryGetProperty("list", out JsonElement profilesList);
if (profilesList.ValueKind != JsonValueKind.Array)
{
return profiles;
}
foreach (var profile in profilesList.EnumerateArray())
{
profiles.Add(ParseProfile(terminal, profile));
}
return profiles;
}
/// <summary>
/// Return a profile for the Windows Terminal
/// </summary>
/// <param name="terminal">Windows Terminal package</param>
/// <param name="profileElement">Profile from the settings JSON file</param>
public static TerminalProfile ParseProfile(TerminalPackage terminal, JsonElement profileElement)
{
profileElement.TryGetProperty("name", out JsonElement nameElement);
var name = nameElement.ValueKind == JsonValueKind.String ? nameElement.GetString() : null;
profileElement.TryGetProperty("hidden", out JsonElement hiddenElement);
var hidden = (hiddenElement.ValueKind == JsonValueKind.False || hiddenElement.ValueKind == JsonValueKind.True) && hiddenElement.GetBoolean();
profileElement.TryGetProperty("guid", out JsonElement guidElement);
var guid = guidElement.ValueKind == JsonValueKind.String ? Guid.Parse(guidElement.GetString()) : null as Guid?;
return new TerminalProfile(terminal, name, guid, hidden);
}
}
}

View File

@@ -0,0 +1,64 @@
// 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.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Security.Principal;
using Windows.Management.Deployment;
namespace Microsoft.PowerToys.Run.Plugin.WindowsTerminal.Helpers
{
public class TerminalQuery : ITerminalQuery
{
private readonly PackageManager _packageManager;
private static ReadOnlyCollection<string> Packages => new List<string>
{
"Microsoft.WindowsTerminal",
"Microsoft.WindowsTerminalPreview",
}.AsReadOnly();
private IEnumerable<TerminalPackage> Terminals => GetTerminals();
public TerminalQuery()
{
_packageManager = new PackageManager();
}
public IEnumerable<TerminalProfile> GetProfiles()
{
var profiles = new List<TerminalProfile>();
foreach (var terminal in Terminals)
{
if (!File.Exists(terminal.SettingsPath))
{
continue;
}
var settingsJson = File.ReadAllText(terminal.SettingsPath);
profiles.AddRange(TerminalHelper.ParseSettings(terminal, settingsJson));
}
return profiles.OrderBy(p => p.Name);
}
private IEnumerable<TerminalPackage> GetTerminals()
{
var user = WindowsIdentity.GetCurrent().User;
var localAppDataPath = Environment.GetEnvironmentVariable("LOCALAPPDATA");
foreach (var p in _packageManager.FindPackagesForUser(user.Value).Where(p => Packages.Contains(p.Id.Name)))
{
var aumid = p.GetAppListEntries().Single().AppUserModelId;
var version = new Version(p.Id.Version.Major, p.Id.Version.Minor, p.Id.Version.Build, p.Id.Version.Revision);
var settingsPath = Path.Combine(localAppDataPath, "Packages", p.Id.FamilyName, "LocalState", "settings.json");
yield return new TerminalPackage(aumid, version, p.DisplayName, settingsPath, p.Logo.LocalPath);
}
}
}
}