Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit b36c02c

Browse files
committed
Move open/copy link to MEF menus and cleanup
1 parent 72828e2 commit b36c02c

File tree

7 files changed

+180
-74
lines changed

7 files changed

+180
-74
lines changed

src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
77
using GitHub.Services;
88
using GitHub.VisualStudio;
9+
using GitHub.Primitives;
10+
using System.Text;
11+
using System.Diagnostics;
912

1013
namespace GitHub.Extensions
1114
{
@@ -35,43 +38,55 @@ public static bool MightContainSolution(this ISimpleRepositoryModel repository)
3538

3639
public static string CurrentSha(this ISimpleRepositoryModel repository)
3740
{
38-
if (repository == null)
39-
return null;
40-
4141
var repo = GitService.GitServiceHelper.GetRepo(repository.LocalPath);
42-
43-
if (repo == null)
44-
return null;
45-
46-
return !repo.Commits.Any() ? null : repo.Commits.ElementAt(0).Sha;
42+
return repo.Commits.FirstOrDefault()?.Sha;
4743
}
4844

49-
public static string BrowserUrl(this ISimpleRepositoryModel repository, IActiveDocument activeDocument)
45+
public static Uri GenerateUrl(this ISimpleRepositoryModel repository, string path = null,
46+
int startLine = -1, int endLine = -1)
5047
{
51-
if (repository == null || activeDocument == null)
48+
var cloneUrl = repository.CloneUrl;
49+
if (cloneUrl == null)
5250
return null;
5351

54-
var currentCommitSha = repository.CurrentSha();
55-
var currentCloneUrl = repository.CloneUrl;
56-
var localPath = repository.LocalPath;
57-
var lineTag = "L" + activeDocument.AnchorLine;
52+
if (path != null && Path.IsPathRooted(path))
53+
{
54+
// if the path root doesn't match the repository local path, then ignore it
55+
if (repository.LocalPath == null ||
56+
!path.StartsWith(repository.LocalPath, StringComparison.OrdinalIgnoreCase))
57+
{
58+
Debug.Assert(false, String.Format(CultureInfo.CurrentCulture, "GenerateUrl: path {0} doesn't match repository {1}", path, repository.LocalPath));
59+
path = null;
60+
}
61+
else
62+
path = path.Substring(repository.LocalPath.Length + 1);
63+
}
64+
65+
var commitSha = repository.CurrentSha();
66+
var uri = GenerateUrl(cloneUrl.ToRepositoryUrl().AbsoluteUri, commitSha, path, startLine, endLine);
67+
return new UriString(uri).ToUri();
68+
}
5869

59-
if (string.IsNullOrEmpty(currentCommitSha) || string.IsNullOrEmpty(currentCloneUrl) ||
60-
string.IsNullOrEmpty(localPath))
61-
return null;
70+
static string GenerateUrl(string basePath, string sha, string path, int startLine = -1, int endLine = -1)
71+
{
72+
var sb = new StringBuilder(basePath);
73+
if (sha == null)
74+
return sb.ToString();
6275

63-
if (activeDocument.AnchorLine != activeDocument.EndLine)
76+
if (String.IsNullOrEmpty(path))
6477
{
65-
lineTag += "-L" + activeDocument.EndLine;
78+
sb.AppendFormat("/commit/{0}", sha);
79+
return sb.ToString();
6680
}
6781

68-
var outputUri = string.Format(CultureInfo.CurrentCulture, "{0}/blob/{1}{2}#{3}",
69-
currentCloneUrl,
70-
currentCommitSha,
71-
activeDocument.Name.Replace(localPath, "").Replace("\\", "/"),
72-
lineTag);
73-
74-
return outputUri;
82+
sb.AppendFormat("/blob/{0}/{1}", sha, path.Replace(@"\", "/"));
83+
if (startLine < 0)
84+
return sb.ToString();
85+
sb.AppendFormat("#L{0}", startLine);
86+
if (endLine < 0)
87+
return sb.ToString();
88+
sb.AppendFormat("-L{0}", endLine);
89+
return sb.ToString();
7590
}
7691
}
7792
}

src/GitHub.VisualStudio/Base/MenuBase.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
using System;
2+
using System.Globalization;
3+
using GitHub.Extensions;
4+
using GitHub.Models;
5+
using GitHub.Services;
26

37
namespace GitHub.VisualStudio
48
{
@@ -7,6 +11,8 @@ public abstract class MenuBase
711
readonly IServiceProvider serviceProvider;
812
protected IServiceProvider ServiceProvider { get { return serviceProvider; } }
913

14+
protected ISimpleRepositoryModel ActiveRepo { get; private set; }
15+
1016
protected MenuBase()
1117
{
1218
}
@@ -15,5 +21,30 @@ protected MenuBase(IServiceProvider serviceProvider)
1521
{
1622
this.serviceProvider = serviceProvider;
1723
}
24+
25+
void RefreshRepo()
26+
{
27+
ActiveRepo = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo;
28+
29+
if (ActiveRepo == null)
30+
{
31+
var vsservices = ServiceProvider.GetExportedValue<IVSServices>();
32+
string path = vsservices?.GetActiveRepoPath() ?? String.Empty;
33+
try
34+
{
35+
ActiveRepo = !String.IsNullOrEmpty(path) ? new SimpleRepositoryModel(path) : null;
36+
}
37+
catch (Exception ex)
38+
{
39+
VsOutputLogger.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0}: Error loading the repository from '{1}'. {2}", GetType(), path, ex));
40+
}
41+
}
42+
}
43+
44+
protected bool IsGitHubRepo()
45+
{
46+
RefreshRepo();
47+
return ActiveRepo?.CloneUrl?.RepositoryName != null;
48+
}
1849
}
1950
}

src/GitHub.VisualStudio/GitHub.VisualStudio.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,11 @@
213213
<Compile Include="Converters\CountToVisibilityConverter.cs" />
214214
<Compile Include="Helpers\SharedDictionaryManager.cs" />
215215
<Compile Include="Helpers\ActiveDocumentSnapshot.cs" />
216+
<Compile Include="Menus\OpenLink.cs" />
217+
<Compile Include="Menus\LinkMenuBase.cs" />
216218
<Compile Include="Menus\ShowGitHubPane.cs" />
217219
<Compile Include="Menus\AddConnection.cs" />
220+
<Compile Include="Menus\CopyLink.cs" />
218221
<Compile Include="Base\MenuBase.cs" />
219222
<Compile Include="Menus\MenuProvider.cs" />
220223
<Compile Include="Properties\AssemblyInfo.cs" />

src/GitHub.VisualStudio/GitHubPackage.cs

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -46,63 +46,17 @@ public GitHubPackage(IServiceProvider serviceProvider)
4646
{
4747
}
4848

49-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
50-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
49+
5150
protected override void Initialize()
5251
{
5352
base.Initialize();
5453

55-
var menus = ServiceProvider.GetExportedValue<IMenuProvider>();
54+
var menus = ServiceProvider.GetExportedValue<IMenuProvider>();
5655
foreach (var menu in menus.Menus)
5756
ServiceProvider.AddTopLevelMenuItem(menu.Guid, menu.CmdId, (s, e) => menu.Activate());
5857

5958
foreach (var menu in menus.DynamicMenus)
6059
ServiceProvider.AddDynamicMenuItem(menu.Guid, menu.CmdId, menu.CanShow, menu.Activate);
61-
ServiceProvider.AddDynamicMenuItem(GuidList.guidContextMenuSet, PkgCmdIDList.getLinkCommand,
62-
IsValidGithubRepo,
63-
OpenRepoInBrowser);
64-
ServiceProvider.AddDynamicMenuItem(GuidList.guidContextMenuSet, PkgCmdIDList.copyLinkCommand,
65-
IsValidGithubRepo,
66-
CopyRepoLinkToClipboard);
67-
}
68-
69-
private void CopyRepoLinkToClipboard()
70-
{
71-
if (!IsValidGithubRepo()) return;
72-
73-
var activeDocument = ServiceProvider.GetExportedValue<IActiveDocument>();
74-
var activeRepo = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo;
75-
var outputUri = activeRepo?.BrowserUrl(activeDocument);
76-
77-
if (string.IsNullOrEmpty(outputUri)) return;
78-
79-
System.Windows.Clipboard.SetText(outputUri);
80-
}
81-
82-
private bool IsValidGithubRepo()
83-
{
84-
var cloneUrl = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo?.CloneUrl;
85-
86-
if (string.IsNullOrEmpty(cloneUrl))
87-
return false;
88-
89-
return cloneUrl.Host == "github.com";
90-
}
91-
92-
private void OpenRepoInBrowser()
93-
{
94-
if (!IsValidGithubRepo()) return;
95-
96-
var activeDocument = ServiceProvider.GetExportedValue<IActiveDocument>();
97-
var activeRepo = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo;
98-
99-
var outputUri = activeRepo?.BrowserUrl(activeDocument);
100-
101-
if (string.IsNullOrEmpty(outputUri)) return;
102-
103-
var vsBrowserProvider = ServiceProvider.GetExportedValue<IVisualStudioBrowser>();
104-
vsBrowserProvider.OpenUrl(new Uri(outputUri));
10560
}
106-
10761
}
10862
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Microsoft.VisualStudio.Shell;
2+
using System;
3+
using System.ComponentModel.Composition;
4+
using System.Windows;
5+
6+
namespace GitHub.VisualStudio.Menus
7+
{
8+
[Export(typeof(IDynamicMenuHandler))]
9+
[PartCreationPolicy(CreationPolicy.Shared)]
10+
public class CopyLink: LinkMenuBase, IDynamicMenuHandler
11+
{
12+
[ImportingConstructor]
13+
public CopyLink([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider)
14+
: base(serviceProvider)
15+
{
16+
}
17+
18+
public Guid Guid { get { return GuidList.guidContextMenuSet; } }
19+
public int CmdId { get { return PkgCmdIDList.copyLinkCommand; } }
20+
21+
public void Activate()
22+
{
23+
if (!IsGitHubRepo())
24+
return;
25+
26+
var link = GenerateLink();
27+
if (link == null)
28+
return;
29+
Clipboard.SetText(link.AbsoluteUri);
30+
}
31+
32+
public bool CanShow()
33+
{
34+
return IsGitHubRepo();
35+
}
36+
}
37+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using GitHub.Extensions;
2+
using GitHub.Models;
3+
using GitHub.Services;
4+
using Microsoft.VisualStudio.Shell;
5+
using System;
6+
using System.Globalization;
7+
8+
namespace GitHub.VisualStudio.Menus
9+
{
10+
public class LinkMenuBase: MenuBase
11+
{
12+
public LinkMenuBase(IServiceProvider serviceProvider)
13+
: base(serviceProvider)
14+
{
15+
}
16+
17+
protected Uri GenerateLink()
18+
{
19+
var repo = ActiveRepo;
20+
var activeDocument = ServiceProvider.GetExportedValue<IActiveDocumentSnapshot>();
21+
if (activeDocument == null)
22+
return null;
23+
return repo.GenerateUrl(activeDocument.Name, activeDocument.StartLine, activeDocument.EndLine);
24+
}
25+
}
26+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using GitHub.Extensions;
2+
using GitHub.Services;
3+
using Microsoft.VisualStudio.Shell;
4+
using System;
5+
using System.ComponentModel.Composition;
6+
using System.Windows;
7+
8+
namespace GitHub.VisualStudio.Menus
9+
{
10+
[Export(typeof(IDynamicMenuHandler))]
11+
[PartCreationPolicy(CreationPolicy.Shared)]
12+
public class OpenLink: LinkMenuBase, IDynamicMenuHandler
13+
{
14+
[ImportingConstructor]
15+
public OpenLink([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider)
16+
: base(serviceProvider)
17+
{
18+
}
19+
20+
public Guid Guid { get { return GuidList.guidContextMenuSet; } }
21+
public int CmdId { get { return PkgCmdIDList.openLinkCommand; } }
22+
23+
public void Activate()
24+
{
25+
if (!IsGitHubRepo())
26+
return;
27+
28+
var link = GenerateLink();
29+
if (link == null)
30+
return;
31+
var browser = ServiceProvider.GetExportedValue<IVisualStudioBrowser>();
32+
browser?.OpenUrl(link);
33+
}
34+
35+
public bool CanShow()
36+
{
37+
return IsGitHubRepo();
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)