[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:
Zuo Zongyuan
2023-10-25 00:03:02 +08:00
committed by GitHub
parent d1e5a57b37
commit cd7a9cc696
6 changed files with 145 additions and 108 deletions

View File

@@ -74,7 +74,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.VSCodeHelper
if (Directory.Exists(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();
var iconPath = Path.GetDirectoryName(path);
@@ -104,10 +104,15 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.VSCodeHelper
version = "Code - Exploration";
instance.VSCodeVersion = VSCodeVersion.Exploration;
}
else if (file.EndsWith("VSCodium", StringComparison.OrdinalIgnoreCase))
else if (file.EndsWith("codium", StringComparison.OrdinalIgnoreCase))
{
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)

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -29,10 +29,10 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
{
case WorkspaceEnvironment.Local: return Resources.TypeWorkspaceLocal;
case WorkspaceEnvironment.Codespaces: return "Codespaces";
case WorkspaceEnvironment.RemoteContainers: return Resources.TypeWorkspaceContainer;
case WorkspaceEnvironment.RemoteSSH: return "SSH";
case WorkspaceEnvironment.RemoteWSL: return "WSL";
case WorkspaceEnvironment.DevContainer: return Resources.TypeWorkspaceDevContainer;
case WorkspaceEnvironment.RemoteTunnel: return "Tunnel";
}
return string.Empty;
@@ -45,8 +45,8 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
Codespaces = 2,
RemoteWSL = 3,
RemoteSSH = 4,
RemoteContainers = 5,
DevContainer = 6,
DevContainer = 5,
RemoteTunnel = 6,
}
public enum WorkspaceType

View File

@@ -19,20 +19,39 @@ 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);
var typeWorkspace = WorkspacesHelper.ParseVSCodeUri.GetWorkspaceEnvironment(unescapeUri);
if (typeWorkspace.WorkspaceEnvironment.HasValue)
return null;
}
var rfc3986Uri = Rfc3986Uri.Parse(Uri.UnescapeDataString(uri));
if (rfc3986Uri is null)
{
var folderName = Path.GetFileName(unescapeUri);
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 DirectoryInfo(unescapeUri);
DirectoryInfo dirInfo = new(path);
folderName = dirInfo.Name.TrimEnd(':');
}
@@ -40,17 +59,13 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
{
Path = uri,
WorkspaceType = isWorkspace ? WorkspaceType.WorkspaceFile : WorkspaceType.ProjectFolder,
RelativePath = typeWorkspace.Path,
RelativePath = path,
FolderName = folderName,
ExtraInfo = typeWorkspace.MachineName,
WorkspaceEnvironment = typeWorkspace.WorkspaceEnvironment.Value,
ExtraInfo = machineName,
WorkspaceEnvironment = workspaceEnv ?? default,
VSCodeInstance = vscodeInstance,
};
}
}
return null;
}
public List<VSCodeWorkspace> Workspaces
{
@@ -100,7 +115,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
{
foreach (var workspaceUri in vscodeStorageFile.OpenedPathsList.Workspaces3)
{
var workspace = ParseVSCodeUri(workspaceUri, vscodeInstance);
var workspace = ParseVSCodeUriAndAuthority(workspaceUri, null, vscodeInstance);
if (workspace != null)
{
storageFileResults.Add(workspace);
@@ -121,7 +136,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
uri = entry.Workspace.ConfigPath;
}
var workspace = ParseVSCodeUri(uri, vscodeInstance, isWorkspaceFile);
var workspace = ParseVSCodeUriAndAuthority(uri, entry.RemoteAuthority, vscodeInstance, isWorkspaceFile);
if (workspace != null)
{
storageFileResults.Add(workspace);
@@ -174,7 +189,7 @@ namespace Community.PowerToys.Run.Plugin.VSCodeWorkspaces.WorkspacesHelper
uri = entry.Workspace.ConfigPath;
}
var workspace = ParseVSCodeUri(uri, vscodeInstance, isWorkspaceFile);
var workspace = ParseVSCodeUriAndAuthority(uri, entry.RemoteAuthority, vscodeInstance, isWorkspaceFile);
if (workspace != null)
{
dbFileResults.Add(workspace);