diff --git a/README.md b/README.md index 44ed5917..6a688d99 100644 --- a/README.md +++ b/README.md @@ -119,15 +119,15 @@ For other AI service: This app supports open repository in external tools listed in the table below. -| Tool | Windows | macOS | Linux | KEY IN `external_editors.json` | -|-------------------------------|---------|-------|-------|--------------------------------| -| Visual Studio Code | YES | YES | YES | VSCODE | -| Visual Studio Code - Insiders | YES | YES | YES | VSCODE_INSIDERS | -| VSCodium | YES | YES | YES | VSCODIUM | -| JetBrains Fleet | YES | YES | YES | FLEET | -| Sublime Text | YES | YES | YES | SUBLIME_TEXT | -| Zed | NO | YES | YES | ZED | -| Visual Studio | YES | YES | YES | VISUALSTUDIO | +| Tool | Windows | macOS | Linux | +|-------------------------------|---------|-------|-------| +| Visual Studio Code | YES | YES | YES | +| Visual Studio Code - Insiders | YES | YES | YES | +| VSCodium | YES | YES | YES | +| Fleet | YES | YES | YES | +| Sublime Text | YES | YES | YES | +| Zed | NO | YES | YES | +| Visual Studio | YES | NO | NO | > [!NOTE] > This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app. @@ -135,7 +135,7 @@ This app supports open repository in external tools listed in the table below. ```json { "tools": { - "VSCODE": "D:\\VSCode\\Code.exe" + "Visual Studio Code": "D:\\VSCode\\Code.exe" } } ``` diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs index 960ebde6..103e91bc 100644 --- a/src/Models/ExternalTool.cs +++ b/src/Models/ExternalTool.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; @@ -14,17 +13,13 @@ namespace SourceGit.Models public class ExternalTool { public string Name { get; private set; } - public string Executable { get; private set; } - public string OpenCmdArgs { get; private set; } public Bitmap IconImage { get; private set; } = null; - public Func ArgTransform { get; private set; } - public ExternalTool(string name, string icon, string executable, string openCmdArgs, Func argsTransform) + public ExternalTool(string name, string icon, string execFile, Func execArgsGenerator = null) { Name = name; - Executable = executable; - OpenCmdArgs = openCmdArgs; - ArgTransform = argsTransform ?? ((s) => s); + _execFile = execFile; + _execArgsGenerator = execArgsGenerator ?? (repo => $"\"{repo}\""); try { @@ -40,19 +35,17 @@ namespace SourceGit.Models public void Open(string repo) { - string arguments = string.Format(OpenCmdArgs, repo); - - if (ArgTransform != null) - arguments = ArgTransform.Invoke(arguments); - Process.Start(new ProcessStartInfo() { WorkingDirectory = repo, - FileName = Executable, - Arguments = arguments, + FileName = _execFile, + Arguments = _execArgsGenerator.Invoke(repo), UseShellExecute = false, }); } + + private string _execFile = string.Empty; + private Func _execArgsGenerator = null; } public class JetBrainsState @@ -118,67 +111,48 @@ namespace SourceGit.Models _customPaths = new ExternalToolPaths(); } - public void TryAdd(string name, string icon, string args, string key, Func finder, Func argsTransform = null) + public void TryAdd(string name, string icon, Func finder, Func execArgsGenerator = null) { - if (_customPaths.Tools.TryGetValue(key, out var customPath) && File.Exists(customPath)) + if (_customPaths.Tools.TryGetValue(name, out var customPath) && File.Exists(customPath)) { - Founded.Add(new ExternalTool(name, icon, customPath, args, argsTransform)); + Founded.Add(new ExternalTool(name, icon, customPath, execArgsGenerator)); } else { var path = finder(); if (!string.IsNullOrEmpty(path) && File.Exists(path)) - Founded.Add(new ExternalTool(name, icon, path, args, argsTransform)); + Founded.Add(new ExternalTool(name, icon, path, execArgsGenerator)); } } public void VSCode(Func platformFinder) { - TryAdd("Visual Studio Code", "vscode", "\"{0}\"", "VSCODE", platformFinder); + TryAdd("Visual Studio Code", "vscode", platformFinder); } public void VSCodeInsiders(Func platformFinder) { - TryAdd("Visual Studio Code - Insiders", "vscode_insiders", "\"{0}\"", "VSCODE_INSIDERS", platformFinder); + TryAdd("Visual Studio Code - Insiders", "vscode_insiders", platformFinder); } public void VSCodium(Func platformFinder) { - TryAdd("VSCodium", "codium", "\"{0}\"", "VSCODIUM", platformFinder); + TryAdd("VSCodium", "codium", platformFinder); } public void Fleet(Func platformFinder) { - TryAdd("Fleet", "fleet", "\"{0}\"", "FLEET", platformFinder); + TryAdd("Fleet", "fleet", platformFinder); } public void SublimeText(Func platformFinder) { - TryAdd("Sublime Text", "sublime_text", "\"{0}\"", "SUBLIME_TEXT", platformFinder); + TryAdd("Sublime Text", "sublime_text", platformFinder); } public void Zed(Func platformFinder) { - TryAdd("Zed", "zed", "\"{0}\"", "ZED", platformFinder); - } - - public void VisualStudio(Func platformFinder) - { - TryAdd("Visual Studio", "vs", "\"{0}\"", "VISUALSTUDIO", platformFinder, VisualStudioTryFindSolution); - } - - private static string VisualStudioTryFindSolution(string path) - { - try - { - if (Directory.GetFiles(path.Trim('\"'), "*.sln", SearchOption.AllDirectories).FirstOrDefault() is string solutionPath) - return Path.GetFullPath(solutionPath); - } - catch - { - // do nothing - } - return path; + TryAdd("Zed", "zed", platformFinder); } public void FindJetBrainsFromToolbox(Func platformFinder) @@ -197,9 +171,7 @@ namespace SourceGit.Models Founded.Add(new ExternalTool( $"{tool.DisplayName} {tool.DisplayVersion}", supported_icons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB", - Path.Combine(tool.InstallLocation, tool.LaunchCommand), - "\"{0}\"", - null)); + Path.Combine(tool.InstallLocation, tool.LaunchCommand))); } } } diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs index 0563644c..a57d26d2 100644 --- a/src/Native/Windows.cs +++ b/src/Native/Windows.cs @@ -134,7 +134,7 @@ namespace SourceGit.Native finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe"); finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\JetBrains\\Toolbox"); finder.SublimeText(FindSublimeText); - finder.VisualStudio(FindVisualStudio); + finder.TryAdd("Visual Studio", "vs", FindVisualStudio, GenerateCommandlineArgsForVisualStudio); return finder.Founded; } @@ -325,7 +325,9 @@ namespace SourceGit.Native if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is Microsoft.Win32.RegistryKey launcher) { // Get actual path to the executable - if (launcher.GetValue(string.Empty) is string CLSID && localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv && devenv.GetValue(string.Empty) is string localServer32) + if (launcher.GetValue(string.Empty) is string CLSID && + localMachine.OpenSubKey(@$"SOFTWARE\Classes\CLSID\{CLSID}\LocalServer32") is Microsoft.Win32.RegistryKey devenv && + devenv.GetValue(string.Empty) is string localServer32) { return localServer32!.Trim('\"'); } @@ -348,5 +350,31 @@ namespace SourceGit.Native ILFree(pidl); } } + + private string GenerateCommandlineArgsForVisualStudio(string repo) + { + var sln = FindVSSolutionFile(repo, 4); + return string.IsNullOrEmpty(sln) ? $"\"{repo}\"" : $"\"{sln}\""; + } + + private string FindVSSolutionFile(string path, int leftDepth) + { + var found = Directory.GetFiles(path, "*.sln", SearchOption.TopDirectoryOnly); + if (found != null && found.Length > 0) + return Path.GetFullPath(found[0]); + + if (leftDepth <= 0) + return null; + + var subfolders = Directory.GetDirectories(path); + foreach (var subfolder in subfolders) + { + var first = FindVSSolutionFile(subfolder, leftDepth - 1); + if (!string.IsNullOrEmpty(first)) + return first; + } + + return null; + } } }