Skip to content

Commit 1d00987

Browse files
authored
feature: add support for Visual Studio as external tool (#648)
* feature: support Visual Studio external tool on Windows * feature: when opening in Visual Studio, try to locate solution file
1 parent fba84c8 commit 1d00987

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ This app supports open repository in external tools listed in the table below.
127127
| JetBrains Fleet | YES | YES | YES | FLEET |
128128
| Sublime Text | YES | YES | YES | SUBLIME_TEXT |
129129
| Zed | NO | YES | YES | ZED |
130+
| Visual Studio | YES | YES | YES | VISUALSTUDIO |
130131

131132
> [!NOTE]
132133
> 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.

src/Models/ExternalTool.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Linq;
56
using System.Text.Json;
67
using System.Text.Json.Serialization;
78

@@ -16,12 +17,14 @@ public class ExternalTool
1617
public string Executable { get; private set; }
1718
public string OpenCmdArgs { get; private set; }
1819
public Bitmap IconImage { get; private set; } = null;
20+
public Func<string, string> ArgTransform { get; private set; }
1921

20-
public ExternalTool(string name, string icon, string executable, string openCmdArgs)
22+
public ExternalTool(string name, string icon, string executable, string openCmdArgs, Func<string, string> argsTransform)
2123
{
2224
Name = name;
2325
Executable = executable;
2426
OpenCmdArgs = openCmdArgs;
27+
ArgTransform = argsTransform ?? ((s) => s);
2528

2629
try
2730
{
@@ -37,11 +40,16 @@ public ExternalTool(string name, string icon, string executable, string openCmdA
3740

3841
public void Open(string repo)
3942
{
43+
string arguments = string.Format(OpenCmdArgs, repo);
44+
45+
if (ArgTransform != null)
46+
arguments = ArgTransform.Invoke(arguments);
47+
4048
Process.Start(new ProcessStartInfo()
4149
{
4250
WorkingDirectory = repo,
4351
FileName = Executable,
44-
Arguments = string.Format(OpenCmdArgs, repo),
52+
Arguments = arguments,
4553
UseShellExecute = false,
4654
});
4755
}
@@ -110,17 +118,17 @@ public ExternalToolsFinder()
110118
_customPaths = new ExternalToolPaths();
111119
}
112120

113-
public void TryAdd(string name, string icon, string args, string key, Func<string> finder)
121+
public void TryAdd(string name, string icon, string args, string key, Func<string> finder, Func<string, string> argsTransform = null)
114122
{
115123
if (_customPaths.Tools.TryGetValue(key, out var customPath) && File.Exists(customPath))
116124
{
117-
Founded.Add(new ExternalTool(name, icon, customPath, args));
125+
Founded.Add(new ExternalTool(name, icon, customPath, args, argsTransform));
118126
}
119127
else
120128
{
121129
var path = finder();
122130
if (!string.IsNullOrEmpty(path) && File.Exists(path))
123-
Founded.Add(new ExternalTool(name, icon, path, args));
131+
Founded.Add(new ExternalTool(name, icon, path, args, argsTransform));
124132
}
125133
}
126134

@@ -154,6 +162,25 @@ public void Zed(Func<string> platformFinder)
154162
TryAdd("Zed", "zed", "\"{0}\"", "ZED", platformFinder);
155163
}
156164

165+
public void VisualStudio(Func<string> platformFinder)
166+
{
167+
TryAdd("Visual Studio", "vs", "\"{0}\"", "VISUALSTUDIO", platformFinder, VisualStudioTryFindSolution);
168+
}
169+
170+
private static string VisualStudioTryFindSolution(string path)
171+
{
172+
try
173+
{
174+
if (Directory.GetFiles(path.Trim('\"'), "*.sln", SearchOption.AllDirectories).FirstOrDefault() is string solutionPath)
175+
return Path.GetFullPath(solutionPath);
176+
}
177+
catch
178+
{
179+
// do nothing
180+
}
181+
return path;
182+
}
183+
157184
public void FindJetBrainsFromToolbox(Func<string> platformFinder)
158185
{
159186
var exclude = new List<string> { "fleet", "dotmemory", "dottrace", "resharper-u", "androidstudio" };
@@ -171,7 +198,8 @@ public void FindJetBrainsFromToolbox(Func<string> platformFinder)
171198
$"{tool.DisplayName} {tool.DisplayVersion}",
172199
supported_icons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB",
173200
Path.Combine(tool.InstallLocation, tool.LaunchCommand),
174-
"\"{0}\""));
201+
"\"{0}\"",
202+
null));
175203
}
176204
}
177205
}

src/Native/Windows.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ public string FindTerminal(Models.ShellOrTerminal shell)
134134
finder.Fleet(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\Programs\\Fleet\\Fleet.exe");
135135
finder.FindJetBrainsFromToolbox(() => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\JetBrains\\Toolbox");
136136
finder.SublimeText(FindSublimeText);
137+
finder.VisualStudio(FindVisualStudio);
137138
return finder.Founded;
138139
}
139140

@@ -313,6 +314,25 @@ private string FindSublimeText()
313314

314315
return string.Empty;
315316
}
317+
318+
private string FindVisualStudio()
319+
{
320+
var localMachine = Microsoft.Win32.RegistryKey.OpenBaseKey(
321+
Microsoft.Win32.RegistryHive.LocalMachine,
322+
Microsoft.Win32.RegistryView.Registry64);
323+
324+
// Get default class for VisualStudio.Launcher.sln - the handler for *.sln files
325+
if (localMachine.OpenSubKey(@"SOFTWARE\Classes\VisualStudio.Launcher.sln\CLSID") is Microsoft.Win32.RegistryKey launcher)
326+
{
327+
// Get actual path to the executable
328+
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)
329+
{
330+
return localServer32!.Trim('\"');
331+
}
332+
}
333+
334+
return string.Empty;
335+
}
316336
#endregion
317337

318338
private void OpenFolderAndSelectFile(string folderPath)

0 commit comments

Comments
 (0)