Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/Models/ExternalTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ public class ExternalTool
public string ExecFile { get; }
public Bitmap IconImage { get; }

public ExternalTool(string name, string icon, string execFile, Func<string, string> execArgsGenerator = null)
public ExternalTool(string name, string icon, string execFile, Func<string, string> execArgsGenerator = null, Func<string, List<string>> subOptionsFinder = null)
{
Name = name;
ExecFile = execFile;
_execArgsGenerator = execArgsGenerator ?? (path => path.Quoted());
_subOptionsFinder = subOptionsFinder;

try
{
Expand Down Expand Up @@ -48,7 +49,16 @@ public void Open(string path)
});
}

public List<string> FindSubOptions(string path)
{
if (_subOptionsFinder == null)
return null;

return _subOptionsFinder.Invoke(path);
}

private Func<string, string> _execArgsGenerator = null;
private Func<string, List<string>> _subOptionsFinder = null;
}

public class VisualStudioInstance
Expand Down Expand Up @@ -130,20 +140,20 @@ public ExternalToolsFinder()
_customization ??= new ExternalToolCustomization();
}

public void TryAdd(string name, string icon, Func<string> finder, Func<string, string> execArgsGenerator = null)
public void TryAdd(string name, string icon, Func<string> finder, Func<string, string> execArgsGenerator = null, Func<string, List<string>> subOptionsFinder = null)
{
if (_customization.Excludes.Contains(name))
return;

if (_customization.Tools.TryGetValue(name, out var customPath) && File.Exists(customPath))
{
Tools.Add(new ExternalTool(name, icon, customPath, execArgsGenerator));
Tools.Add(new ExternalTool(name, icon, customPath, execArgsGenerator, subOptionsFinder));
}
else
{
var path = finder();
if (!string.IsNullOrEmpty(path) && File.Exists(path))
Tools.Add(new ExternalTool(name, icon, path, execArgsGenerator));
Tools.Add(new ExternalTool(name, icon, path, execArgsGenerator, subOptionsFinder));
}
}

Expand Down
44 changes: 20 additions & 24 deletions src/Native/Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ private void FindVisualStudio(Models.ExternalToolsFinder finder)
{
var exec = instance.ProductPath;
var icon = instance.IsPrerelease ? "vs-preview" : "vs";
finder.TryAdd(instance.DisplayName, icon, () => exec, GenerateCommandlineArgsForVisualStudio);
finder.TryAdd(instance.DisplayName, icon, () => exec, GenerateCommandlineArgsForVisualStudio, FindVisualStudioSolutions);
}
}
}
Expand Down Expand Up @@ -446,37 +446,33 @@ private void OpenFolderAndSelectFile(string folderPath)

private string GenerateCommandlineArgsForVisualStudio(string path)
{
if (Directory.Exists(path))
{
var sln = FindVSSolutionFile(new DirectoryInfo(path), 4);
return string.IsNullOrEmpty(sln) ? path.Quoted() : sln.Quoted();
}

return path.Quoted();
var solutions = FindVisualStudioSolutions(path);
return solutions.Count > 0 ? solutions[0].Quoted() : path.Quoted();
}

private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)
public List<string> FindVisualStudioSolutions(string path)
{
var files = dir.GetFiles();
foreach (var f in files)
var solutions = new List<string>();
if (!Directory.Exists(path))
return solutions;

void Search(DirectoryInfo dir, int depth)
{
if (f.Name.EndsWith(".slnx", StringComparison.OrdinalIgnoreCase) ||
f.Name.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
return f.FullName;
}
if (depth < 0)
return;

if (leftDepth <= 0)
return null;
foreach (var file in dir.GetFiles("*.sln"))
solutions.Add(file.FullName);

var subDirs = dir.GetDirectories();
foreach (var subDir in subDirs)
{
var first = FindVSSolutionFile(subDir, leftDepth - 1);
if (!string.IsNullOrEmpty(first))
return first;
foreach (var file in dir.GetFiles("*.slnx"))
solutions.Add(file.FullName);

foreach (var subDir in dir.GetDirectories())
Search(subDir, depth - 1);
}
Search(new DirectoryInfo(path), 4);

return null;
return solutions;
}
}
}
33 changes: 28 additions & 5 deletions src/Views/RepositoryToolbar.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.IO;

using Avalonia.Controls;
using Avalonia.Input;
Expand Down Expand Up @@ -61,13 +62,35 @@ private void OpenWithExternalTools(object sender, RoutedEventArgs ev)
var item = new MenuItem();
item.Header = App.Text("Repository.OpenIn", dupTool.Name);
item.Icon = new Image { Width = 16, Height = 16, Source = dupTool.IconImage };
item.Click += (_, e) =>

var subOptions = dupTool.FindSubOptions(fullpath);
if (subOptions != null && subOptions.Count > 1)
{
dupTool.Open(fullpath);
e.Handled = true;
};
foreach (var subOption in subOptions)
{
var subItem = new MenuItem();
subItem.Header = Path.GetFileName(subOption);
subItem.Click += (_, e) =>
{
dupTool.Open(subOption);
e.Handled = true;
};

item.Items.Add(subItem);
}

menu.Items.Add(item);
}
else
{
item.Click += (_, e) =>
{
dupTool.Open(fullpath);
e.Handled = true;
};

menu.Items.Add(item);
menu.Items.Add(item);
}
}
}

Expand Down