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

Commit 3df7b6c

Browse files
committed
Merge pull request #184 from austin94/feature/link-to-vs
2 parents ed5711b + d4d7762 commit 3df7b6c

File tree

6 files changed

+120
-17
lines changed

6 files changed

+120
-17
lines changed

src/GitHub.Exports/Extensions/SimpleRepositoryModelExtensions.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
2+
using System.Globalization;
23
using System.Linq;
34
using System.IO;
45
using GitHub.Models;
56
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
67
using GitHub.Services;
8+
using GitHub.VisualStudio;
79

810
namespace GitHub.Extensions
911
{
@@ -30,5 +32,46 @@ public static bool MightContainSolution(this ISimpleRepositoryModel repository)
3032
.Any(x => ((x.Attributes.HasFlag(FileAttributes.Directory) || x.Attributes.HasFlag(FileAttributes.Normal)) &&
3133
!x.Name.StartsWith(".", StringComparison.Ordinal) && !x.Name.StartsWith("readme", StringComparison.OrdinalIgnoreCase)));
3234
}
35+
36+
public static string CurrentSha(this ISimpleRepositoryModel repository)
37+
{
38+
if (repository == null)
39+
return null;
40+
41+
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;
47+
}
48+
49+
public static string BrowserUrl(this ISimpleRepositoryModel repository, IActiveDocument activeDocument)
50+
{
51+
if (repository == null || activeDocument == null)
52+
return null;
53+
54+
var currentCommitSha = repository.CurrentSha();
55+
var currentCloneUrl = repository.CloneUrl;
56+
var localPath = repository.LocalPath;
57+
var lineTag = "L" + activeDocument.AnchorLine;
58+
59+
if (string.IsNullOrEmpty(currentCommitSha) || string.IsNullOrEmpty(currentCloneUrl) ||
60+
string.IsNullOrEmpty(localPath))
61+
return null;
62+
63+
if (activeDocument.AnchorLine != activeDocument.EndLine)
64+
{
65+
lineTag += "-L" + activeDocument.EndLine;
66+
}
67+
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;
75+
}
3376
}
3477
}

src/GitHub.Exports/Services/IActiveDocument.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
public interface IActiveDocument
44
{
55
string Name { get; }
6-
int Line { get; }
6+
int AnchorLine { get; }
7+
int AnchorColumn { get; }
8+
int EndLine { get; }
9+
int EndColumn { get; }
710
}
811
}

src/GitHub.VisualStudio/GitHub.VisualStudio.vsct

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,21 @@
122122

123123
<Button guid="guidContextMenuSet" id="getLinkCommand" priority="0x0100" type="Button">
124124
<Parent guid="guidContextMenuSet" id="idContextMenuGroup"/>
125+
<CommandFlag>DefaultInvisible</CommandFlag>
126+
<CommandFlag>DynamicVisibility</CommandFlag>
125127
<Strings>
126-
<ButtonText>Get Link</ButtonText>
128+
<ButtonText>Open in Browser</ButtonText>
127129
</Strings>
128130
</Button>
129131

132+
<Button guid="guidContextMenuSet" id="copyLinkCommand" priority="0x0101" type="Button">
133+
<Parent guid="guidContextMenuSet" id="idContextMenuGroup"/>
134+
<CommandFlag>DefaultInvisible</CommandFlag>
135+
<CommandFlag>DynamicVisibility</CommandFlag>
136+
<Strings>
137+
<ButtonText>Copy Link to Clipboard</ButtonText>
138+
</Strings>
139+
</Button>
130140
</Buttons>
131141

132142
</Commands>
@@ -187,6 +197,7 @@
187197
<GuidSymbol name="guidContextMenuSet" value="{31057D08-8C3C-4C5B-9F91-8682EA08EC27}">
188198
<IDSymbol name="idContextMenuGroup" value="0x1010" />
189199
<IDSymbol name="getLinkCommand" value="0x100" />
200+
<IDSymbol name="copyLinkCommand" value="0x101"/>
190201
</GuidSymbol>
191202

192203
<GuidSymbol name="GUID_XAML_EDITOR" value="{4C87B692-1202-46AA-B64C-EF01FAEC53DA}">

src/GitHub.VisualStudio/GitHubPackage.cs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
2+
using System.Globalization;
23
using System.Runtime.InteropServices;
34
using GitHub.Extensions;
5+
using GitHub.Models;
46
using GitHub.Services;
57
using GitHub.UI;
68
using GitHub.VisualStudio.Base;
@@ -60,18 +62,54 @@ protected override void Initialize()
6062
var windowFrame = (IVsWindowFrame)window.Frame;
6163
ErrorHandler.ThrowOnFailure(windowFrame.Show());
6264
});
65+
ServiceProvider.AddDynamicMenuItem(GuidList.guidContextMenuSet, PkgCmdIDList.getLinkCommand,
66+
IsValidGithubRepo,
67+
OpenRepoInBrowser);
68+
ServiceProvider.AddDynamicMenuItem(GuidList.guidContextMenuSet, PkgCmdIDList.copyLinkCommand,
69+
IsValidGithubRepo,
70+
CopyRepoLinkToClipboard);
6371

64-
ServiceProvider.AddTopLevelMenuItem(GuidList.guidContextMenuSet, PkgCmdIDList.getLinkCommand, (s, e) =>
65-
{
66-
var ap = ServiceProvider.GetExportedValue<IActiveDocument>();
67-
var name = ap.Name;
68-
var line = ap.Line;
69-
System.Windows.Forms.MessageBox.Show(name + " : " + line);
70-
71-
});
7272
base.Initialize();
7373
}
7474

75+
private void CopyRepoLinkToClipboard()
76+
{
77+
if (!IsValidGithubRepo()) return;
78+
79+
var activeDocument = ServiceProvider.GetExportedValue<IActiveDocument>();
80+
var activeRepo = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo;
81+
var outputUri = activeRepo?.BrowserUrl(activeDocument);
82+
83+
if (string.IsNullOrEmpty(outputUri)) return;
84+
85+
System.Windows.Clipboard.SetText(outputUri);
86+
}
87+
88+
private bool IsValidGithubRepo()
89+
{
90+
var cloneUrl = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo?.CloneUrl;
91+
92+
if (string.IsNullOrEmpty(cloneUrl))
93+
return false;
94+
95+
return cloneUrl.Host == "github.com";
96+
}
97+
98+
private void OpenRepoInBrowser()
99+
{
100+
if (!IsValidGithubRepo()) return;
101+
102+
var activeDocument = ServiceProvider.GetExportedValue<IActiveDocument>();
103+
var activeRepo = ServiceProvider.GetExportedValue<ITeamExplorerServiceHolder>().ActiveRepo;
104+
105+
var outputUri = activeRepo?.BrowserUrl(activeDocument);
106+
107+
if (string.IsNullOrEmpty(outputUri)) return;
108+
109+
var vsBrowserProvider = ServiceProvider.GetExportedValue<IVisualStudioBrowser>();
110+
vsBrowserProvider.OpenUrl(new Uri(outputUri));
111+
}
112+
75113
void StartFlow(UIControllerFlow controllerFlow)
76114
{
77115
var uiProvider = ServiceProvider.GetExportedValue<IUIProvider>();

src/GitHub.VisualStudio/PkgCmdID.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ static class PkgCmdIDList
1212
public const int refreshCommand = 0x302;
1313
public const int pullRequestCommand = 0x310;
1414
public const int getLinkCommand = 0x100;
15+
public const int copyLinkCommand = 0x101;
1516
};
1617
}

src/GitHub.VisualStudio/Services/ActiveDocument.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,32 @@ namespace GitHub.VisualStudio
1212
class ActiveDocument : IActiveDocument
1313
{
1414
public string Name { get; private set; }
15-
public int Line { get; private set; }
16-
public int Column { get; private set; }
15+
public string ShortName { get; private set; }
16+
public int AnchorLine { get; private set; }
17+
public int AnchorColumn { get; private set; }
18+
public int EndLine { get; private set; }
19+
public int EndColumn { get; private set; }
1720

1821
[ImportingConstructor]
1922
public ActiveDocument([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider)
2023
{
21-
Line = Column = -1;
24+
AnchorLine = AnchorColumn = EndLine = EndColumn = -1;
2225
Name = Services.Dte2?.ActiveDocument?.FullName;
26+
ShortName = Services.Dte2?.ActiveDocument?.Name;
27+
2328
var textManager = serviceProvider.GetService(typeof(SVsTextManager)) as IVsTextManager;
2429
Debug.Assert(textManager != null, "No SVsTextManager service available");
2530
if (textManager == null)
2631
return;
2732
IVsTextView view;
28-
int line, col;
33+
int anchorLine, anchorCol, endLine, endCol;
2934
if (ErrorHandler.Succeeded(textManager.GetActiveView(0, null, out view)) &&
30-
ErrorHandler.Succeeded(view.GetCaretPos(out line, out col)))
35+
ErrorHandler.Succeeded(view.GetSelection(out anchorLine, out anchorCol, out endLine, out endCol)))
3136
{
32-
Line = line;
33-
Column = col;
37+
AnchorLine = anchorLine + 1;
38+
AnchorColumn = anchorCol + 1;
39+
EndLine = endLine + 1;
40+
EndColumn = endCol + 1;
3441
}
3542
}
3643
}

0 commit comments

Comments
 (0)