mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
[PTRun][VSCode]Fix support for VSCodium and add support for Remote - Tunnels (#28742)
* feat: fix support for VSCodium stable & insider * feat: add support for Remote Tunnels
This commit is contained in:
@@ -74,7 +74,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.VSCodeHelper
|
|||||||
if (Directory.Exists(path))
|
if (Directory.Exists(path))
|
||||||
{
|
{
|
||||||
var files = Directory.GetFiles(path)
|
var files = Directory.GetFiles(path)
|
||||||
.Where(x => (x.Contains("code", StringComparison.OrdinalIgnoreCase) || x.Contains("VSCodium", StringComparison.OrdinalIgnoreCase))
|
.Where(x => (x.Contains("code", StringComparison.OrdinalIgnoreCase) || x.Contains("codium", StringComparison.OrdinalIgnoreCase))
|
||||||
&& !x.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase)).ToArray();
|
&& !x.EndsWith(".cmd", StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
|
|
||||||
var iconPath = Path.GetDirectoryName(path);
|
var iconPath = Path.GetDirectoryName(path);
|
||||||
@@ -104,10 +104,15 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.VSCodeHelper
|
|||||||
version = "Code - Exploration";
|
version = "Code - Exploration";
|
||||||
instance.VSCodeVersion = VSCodeVersion.Exploration;
|
instance.VSCodeVersion = VSCodeVersion.Exploration;
|
||||||
}
|
}
|
||||||
else if (file.EndsWith("VSCodium", StringComparison.OrdinalIgnoreCase))
|
else if (file.EndsWith("codium", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
version = "VSCodium";
|
version = "VSCodium";
|
||||||
instance.VSCodeVersion = VSCodeVersion.Stable; // ?
|
instance.VSCodeVersion = VSCodeVersion.Stable;
|
||||||
|
}
|
||||||
|
else if (file.EndsWith("codium-insiders", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
version = "VSCodium - Insiders";
|
||||||
|
instance.VSCodeVersion = VSCodeVersion.Insiders;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version != string.Empty)
|
if (version != string.Empty)
|
||||||
|
|||||||
@@ -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.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
||||||
|
{
|
||||||
|
public class ParseVSCodeAuthority
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, WorkspaceEnvironment> EnvironmentTypes = new()
|
||||||
|
{
|
||||||
|
{ string.Empty, WorkspaceEnvironment.Local },
|
||||||
|
{ "ssh-remote", WorkspaceEnvironment.RemoteSSH },
|
||||||
|
{ "wsl", WorkspaceEnvironment.RemoteWSL },
|
||||||
|
{ "vsonline", WorkspaceEnvironment.Codespaces },
|
||||||
|
{ "dev-container", WorkspaceEnvironment.DevContainer },
|
||||||
|
{ "tunnel", WorkspaceEnvironment.RemoteTunnel },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string GetRemoteName(string authority)
|
||||||
|
{
|
||||||
|
if (authority is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = authority.IndexOf('+');
|
||||||
|
if (pos < 0)
|
||||||
|
{
|
||||||
|
return authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
return authority[..pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (WorkspaceEnvironment? WorkspaceEnvironment, string MachineName) GetWorkspaceEnvironment(string authority)
|
||||||
|
{
|
||||||
|
var remoteName = GetRemoteName(authority);
|
||||||
|
var machineName = remoteName.Length < authority.Length ? authority[(remoteName.Length + 1)..] : null;
|
||||||
|
return EnvironmentTypes.TryGetValue(remoteName, out WorkspaceEnvironment workspace) ?
|
||||||
|
(workspace, machineName) :
|
||||||
|
(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
// 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.RegularExpressions;
|
|
||||||
|
|
||||||
namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|
||||||
{
|
|
||||||
public class ParseVSCodeUri
|
|
||||||
{
|
|
||||||
private static readonly Regex LocalWorkspace = new Regex("^file:///(.+)$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static readonly Regex RemoteSSHWorkspace = new Regex(@"^vscode-remote://ssh-remote\+(.+?(?=\/))(.+)$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static readonly Regex RemoteWSLWorkspace = new Regex(@"^vscode-remote://wsl\+(.+?(?=\/))(.+)$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static readonly Regex CodespacesWorkspace = new Regex(@"^vscode-remote://vsonline\+(.+?(?=\/))(.+)$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
private static readonly Regex DevContainerWorkspace = new Regex(@"^vscode-remote://dev-container\+(.+?(?=\/))(.+)$", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
public static (WorkspaceEnvironment? WorkspaceEnvironment, string MachineName, string Path) GetWorkspaceEnvironment(string uri)
|
|
||||||
{
|
|
||||||
if (LocalWorkspace.IsMatch(uri))
|
|
||||||
{
|
|
||||||
var match = LocalWorkspace.Match(uri);
|
|
||||||
|
|
||||||
if (match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
return (WorkspaceEnvironment.Local, null, match.Groups[1].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (RemoteSSHWorkspace.IsMatch(uri))
|
|
||||||
{
|
|
||||||
var match = RemoteSSHWorkspace.Match(uri);
|
|
||||||
|
|
||||||
if (match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
return (WorkspaceEnvironment.RemoteSSH, match.Groups[1].Value, match.Groups[2].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (RemoteWSLWorkspace.IsMatch(uri))
|
|
||||||
{
|
|
||||||
var match = RemoteWSLWorkspace.Match(uri);
|
|
||||||
|
|
||||||
if (match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
return (WorkspaceEnvironment.RemoteWSL, match.Groups[1].Value, match.Groups[2].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (CodespacesWorkspace.IsMatch(uri))
|
|
||||||
{
|
|
||||||
var match = CodespacesWorkspace.Match(uri);
|
|
||||||
|
|
||||||
if (match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
return (WorkspaceEnvironment.Codespaces, null, match.Groups[2].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (DevContainerWorkspace.IsMatch(uri))
|
|
||||||
{
|
|
||||||
var match = DevContainerWorkspace.Match(uri);
|
|
||||||
|
|
||||||
if (match.Groups.Count > 1)
|
|
||||||
{
|
|
||||||
return (WorkspaceEnvironment.DevContainer, null, match.Groups[2].Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (null, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// 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.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
||||||
|
{
|
||||||
|
// Use regex to parse URI since System.Uri is not compliant with RFC 3986, see https://github.com/dotnet/runtime/issues/64707
|
||||||
|
public partial class Rfc3986Uri
|
||||||
|
{
|
||||||
|
// The following regex is referenced from https://www.rfc-editor.org/rfc/rfc3986.html#appendix-B
|
||||||
|
[GeneratedRegex(@"^((?<scheme>[^:/?#]+):)?(//(?<authority>[^/?#]*))?(?<path>[^?#]*)(\?(?<query>[^#]*))?(#(?<fragment>.*))?$")]
|
||||||
|
private static partial Regex Rfc3986();
|
||||||
|
|
||||||
|
public string Scheme { get; private set; }
|
||||||
|
|
||||||
|
public string Authority { get; private set; }
|
||||||
|
|
||||||
|
public string Path { get; private set; }
|
||||||
|
|
||||||
|
public string Query { get; private set; }
|
||||||
|
|
||||||
|
public string Fragment { get; private set; }
|
||||||
|
|
||||||
|
public static Rfc3986Uri Parse([StringSyntax("Uri")] string uriString)
|
||||||
|
{
|
||||||
|
return uriString is not null && Rfc3986().Match(uriString) is { Success: true } match
|
||||||
|
? new Rfc3986Uri()
|
||||||
|
{
|
||||||
|
Scheme = match.Groups["scheme"].Value,
|
||||||
|
Authority = match.Groups["authority"].Value,
|
||||||
|
Path = match.Groups["path"].Value,
|
||||||
|
Query = match.Groups["query"].Value,
|
||||||
|
Fragment = match.Groups["fragment"].Value,
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,10 +29,10 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
{
|
{
|
||||||
case WorkspaceEnvironment.Local: return Resources.TypeWorkspaceLocal;
|
case WorkspaceEnvironment.Local: return Resources.TypeWorkspaceLocal;
|
||||||
case WorkspaceEnvironment.Codespaces: return "Codespaces";
|
case WorkspaceEnvironment.Codespaces: return "Codespaces";
|
||||||
case WorkspaceEnvironment.RemoteContainers: return Resources.TypeWorkspaceContainer;
|
|
||||||
case WorkspaceEnvironment.RemoteSSH: return "SSH";
|
case WorkspaceEnvironment.RemoteSSH: return "SSH";
|
||||||
case WorkspaceEnvironment.RemoteWSL: return "WSL";
|
case WorkspaceEnvironment.RemoteWSL: return "WSL";
|
||||||
case WorkspaceEnvironment.DevContainer: return Resources.TypeWorkspaceDevContainer;
|
case WorkspaceEnvironment.DevContainer: return Resources.TypeWorkspaceDevContainer;
|
||||||
|
case WorkspaceEnvironment.RemoteTunnel: return "Tunnel";
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
@@ -45,8 +45,8 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
Codespaces = 2,
|
Codespaces = 2,
|
||||||
RemoteWSL = 3,
|
RemoteWSL = 3,
|
||||||
RemoteSSH = 4,
|
RemoteSSH = 4,
|
||||||
RemoteContainers = 5,
|
DevContainer = 5,
|
||||||
DevContainer = 6,
|
RemoteTunnel = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WorkspaceType
|
public enum WorkspaceType
|
||||||
|
|||||||
@@ -19,37 +19,52 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private VSCodeWorkspace ParseVSCodeUri(string uri, VSCodeInstance vscodeInstance, bool isWorkspace = false)
|
private VSCodeWorkspace ParseVSCodeUriAndAuthority(string uri, string authority, VSCodeInstance vscodeInstance, bool isWorkspace = false)
|
||||||
{
|
{
|
||||||
if (uri != null && uri is string)
|
if (uri is null)
|
||||||
{
|
{
|
||||||
string unescapeUri = Uri.UnescapeDataString(uri);
|
return null;
|
||||||
var typeWorkspace = WorkspacesHelper.ParseVSCodeUri.GetWorkspaceEnvironment(unescapeUri);
|
|
||||||
if (typeWorkspace.WorkspaceEnvironment.HasValue)
|
|
||||||
{
|
|
||||||
var folderName = Path.GetFileName(unescapeUri);
|
|
||||||
|
|
||||||
// Check we haven't returned '' if we have a path like C:\
|
|
||||||
if (string.IsNullOrEmpty(folderName))
|
|
||||||
{
|
|
||||||
DirectoryInfo dirInfo = new DirectoryInfo(unescapeUri);
|
|
||||||
folderName = dirInfo.Name.TrimEnd(':');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new VSCodeWorkspace()
|
|
||||||
{
|
|
||||||
Path = uri,
|
|
||||||
WorkspaceType = isWorkspace ? WorkspaceType.WorkspaceFile : WorkspaceType.ProjectFolder,
|
|
||||||
RelativePath = typeWorkspace.Path,
|
|
||||||
FolderName = folderName,
|
|
||||||
ExtraInfo = typeWorkspace.MachineName,
|
|
||||||
WorkspaceEnvironment = typeWorkspace.WorkspaceEnvironment.Value,
|
|
||||||
VSCodeInstance = vscodeInstance,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
var rfc3986Uri = Rfc3986Uri.Parse(Uri.UnescapeDataString(uri));
|
||||||
|
if (rfc3986Uri is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (workspaceEnv, machineName) = ParseVSCodeAuthority.GetWorkspaceEnvironment(authority ?? rfc3986Uri.Authority);
|
||||||
|
if (workspaceEnv is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = rfc3986Uri.Path;
|
||||||
|
|
||||||
|
// Remove preceding '/' from local (Windows) path
|
||||||
|
if (workspaceEnv == WorkspaceEnvironment.Local)
|
||||||
|
{
|
||||||
|
path = path[1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
var folderName = Path.GetFileName(path);
|
||||||
|
|
||||||
|
// Check we haven't returned '' if we have a path like C:\
|
||||||
|
if (string.IsNullOrEmpty(folderName))
|
||||||
|
{
|
||||||
|
DirectoryInfo dirInfo = new(path);
|
||||||
|
folderName = dirInfo.Name.TrimEnd(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VSCodeWorkspace()
|
||||||
|
{
|
||||||
|
Path = uri,
|
||||||
|
WorkspaceType = isWorkspace ? WorkspaceType.WorkspaceFile : WorkspaceType.ProjectFolder,
|
||||||
|
RelativePath = path,
|
||||||
|
FolderName = folderName,
|
||||||
|
ExtraInfo = machineName,
|
||||||
|
WorkspaceEnvironment = workspaceEnv ?? default,
|
||||||
|
VSCodeInstance = vscodeInstance,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VSCodeWorkspace> Workspaces
|
public List<VSCodeWorkspace> Workspaces
|
||||||
@@ -100,7 +115,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
{
|
{
|
||||||
foreach (var workspaceUri in vscodeStorageFile.OpenedPathsList.Workspaces3)
|
foreach (var workspaceUri in vscodeStorageFile.OpenedPathsList.Workspaces3)
|
||||||
{
|
{
|
||||||
var workspace = ParseVSCodeUri(workspaceUri, vscodeInstance);
|
var workspace = ParseVSCodeUriAndAuthority(workspaceUri, null, vscodeInstance);
|
||||||
if (workspace != null)
|
if (workspace != null)
|
||||||
{
|
{
|
||||||
storageFileResults.Add(workspace);
|
storageFileResults.Add(workspace);
|
||||||
@@ -121,7 +136,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
uri = entry.Workspace.ConfigPath;
|
uri = entry.Workspace.ConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
var workspace = ParseVSCodeUri(uri, vscodeInstance, isWorkspaceFile);
|
var workspace = ParseVSCodeUriAndAuthority(uri, entry.RemoteAuthority, vscodeInstance, isWorkspaceFile);
|
||||||
if (workspace != null)
|
if (workspace != null)
|
||||||
{
|
{
|
||||||
storageFileResults.Add(workspace);
|
storageFileResults.Add(workspace);
|
||||||
@@ -174,7 +189,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
|
|||||||
uri = entry.Workspace.ConfigPath;
|
uri = entry.Workspace.ConfigPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
var workspace = ParseVSCodeUri(uri, vscodeInstance, isWorkspaceFile);
|
var workspace = ParseVSCodeUriAndAuthority(uri, entry.RemoteAuthority, vscodeInstance, isWorkspaceFile);
|
||||||
if (workspace != null)
|
if (workspace != null)
|
||||||
{
|
{
|
||||||
dbFileResults.Add(workspace);
|
dbFileResults.Add(workspace);
|
||||||
|
|||||||
Reference in New Issue
Block a user