Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.ComponentModel.Composition;

namespace GitHub.Exports
Expand All @@ -11,24 +12,32 @@ namespace GitHub.Exports
/// This attribute is used to mark exports that mustn't be loaded into Blend.
/// See: https://github.com/github/VisualStudio/pull/1055
/// </remarks>
[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "Extended by ExportForVisualStudioProcessAttribute")]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public sealed class ExportForProcessAttribute : ExportAttribute
public class ExportForProcessAttribute : ExportAttribute
{
// Unique name for exports that have been disabled
const string DisabledContractName = "GitHub.Disabled";

/// <summary>
/// Define an export that is only exposed in a specific named process.
/// </summary>
/// <param name="contractType">The contract type to expose.</param>
/// <param name="processName">Name of the process to expose export from (e.g. 'devenv').</param>
public ExportForProcessAttribute(Type contractType, string processName) : base(ExportForProcess(contractType, processName))
/// <param name="contractType">The contract type to expose.</param>
public ExportForProcessAttribute(string processName, Type contractType = null) :
base(ContractNameForProcess(processName), contractType)
{
ProcessName = processName;
}

static Type ExportForProcess(Type contractType, string processName)
static string ContractNameForProcess(string processName)
{
return Process.GetCurrentProcess().ProcessName == processName ? contractType : null;
var enabled = IsProcess(processName);
return enabled ? null : DisabledContractName;
}

public static bool IsProcess(string processName) => Process.GetCurrentProcess().ProcessName == processName;

/// <summary>
/// The process name export will be exposed in.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;

namespace GitHub.Exports
{
/// <summary>
/// Only expose export when executing in Visual Studio (devenv) process.
/// </summary>
/// <remarks>
/// This attribute is used to mark exports that mustn't be loaded into Blend.
/// See: https://github.com/github/VisualStudio/pull/1055
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public sealed class ExportForVisualStudioProcessAttribute : ExportForProcessAttribute
{
const string VisualStudioProcessName = "devenv";

/// <summary>
/// Define an export that is only exposed in a Visual Studio (devenv) process.
/// </summary>
/// <param name="contractType">The contract type to expose.</param>
public ExportForVisualStudioProcessAttribute(Type contractType = null) :
base(VisualStudioProcessName, contractType)
{
}

public static bool IsVisualStudioProcess() => IsProcess(VisualStudioProcessName);
}
}
3 changes: 2 additions & 1 deletion src/GitHub.Exports/GitHub.Exports.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@
<Compile Include="Commands\IGoToSolutionOrPullRequestFileCommand.cs" />
<Compile Include="Commands\IVsCommand.cs" />
<Compile Include="Commands\IVsCommandBase.cs" />
<Compile Include="Exports\ExportForProcess.cs" />
<Compile Include="Exports\ExportForVisualStudioProcessAttribute.cs" />
<Compile Include="Exports\ExportForProcessAttribute.cs" />
<Compile Include="Extensions\ConnectionManagerExtensions.cs" />
<Compile Include="GitHubLogicException.cs" />
<Compile Include="Models\CommitMessage.cs" />
Expand Down
11 changes: 11 additions & 0 deletions src/GitHub.InlineReviews/InlineReviewsPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using System.Threading;
using GitHub.Exports;
using GitHub.Logging;
using github.202132.xyzmands;
using GitHub.Services.Vssdk.Commands;
using GitHub.VisualStudio;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
using Serilog;
using Task = System.Threading.Tasks.Task;

namespace GitHub.InlineReviews
Expand All @@ -18,6 +21,8 @@ namespace GitHub.InlineReviews
[ProvideMenuResource("Menus.ctmenu", 1)]
public class InlineReviewsPackage : AsyncPackage
{
static readonly ILogger log = LogManager.ForContext<InlineReviewsPackage>();

protected override async Task InitializeAsync(
CancellationToken cancellationToken,
IProgress<ServiceProgressData> progress)
Expand All @@ -33,6 +38,12 @@ protected override async Task InitializeAsync(

async Task InitializeMenus()
{
if (!ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
log.Warning("Don't initialize menus for non-Visual Studio process");
return;
}

var componentModel = (IComponentModel)(await GetServiceAsync(typeof(SComponentModel)));
var exports = componentModel.DefaultExportProvider;
var commands = new IVsCommandBase[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void NotifyActiveRepo()

void UpdateActiveRepo()
{
// NOTE: gitService will be null in Expression Blend or Safe Mode
// NOTE: gitService might be null in Blend or Safe Mode
var repo = gitService?.ActiveRepositories.FirstOrDefault();

if (!Equals(repo, ActiveRepo))
Expand Down
9 changes: 9 additions & 0 deletions src/GitHub.VisualStudio.UI/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/GitHub.VisualStudio.UI/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@
<data name="Options_EnableTraceLoggingText" xml:space="preserve">
<value>Enable Trace Logging</value>
</data>
<data name="BlendDialogText" xml:space="preserve">
<value>The GitHub extension is not available inside Blend</value>
</data>
<data name="Options_ForkButtonLabel" xml:space="preserve">
<value>Show Fork button in Team Explorer</value>
</data>
Expand Down
37 changes: 37 additions & 0 deletions src/GitHub.VisualStudio/Commands/ShowMessageBoxCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using GitHub.Services.Vssdk.Commands;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Task = System.Threading.Tasks.Task;

namespace GitHub.VisualStudio.Commands
{
/// <summary>
/// Show an info message dialog when a command is executed.
/// </summary>
public class ShowMessageBoxCommand : VsCommand
{
readonly IServiceProvider serviceProvider;
readonly string message;

public ShowMessageBoxCommand(Guid commandSet, int commandId,
IServiceProvider serviceProvider, string message) : base(commandSet, commandId)
{
this.serviceProvider = serviceProvider;
this.message = message;
}

public override Task Execute()
{
ShowInfoMessage(message);
return Task.CompletedTask;
}

void ShowInfoMessage(string infoMessage)
{
ErrorHandler.ThrowOnFailure(VsShellUtilities.ShowMessageBox(serviceProvider, infoMessage, null,
OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST));
}
}
}
13 changes: 12 additions & 1 deletion src/GitHub.VisualStudio/GitContextPackage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using GitHub.Exports;
using GitHub.Logging;
using GitHub.Services;
using Microsoft.VisualStudio.Shell;
using Serilog;
using Task = System.Threading.Tasks.Task;

namespace GitHub.VisualStudio
Expand All @@ -17,8 +20,16 @@ namespace GitHub.VisualStudio
[ProvideAutoLoad(Guids.GitSccProviderId, PackageAutoLoadFlags.BackgroundLoad)]
public class GitContextPackage : AsyncPackage
{
static readonly ILogger log = LogManager.ForContext<GitContextPackage>();

protected async override Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
if (!ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
log.Warning("Don't activate 'UIContext_Git' for non-Visual Studio process");
return;
}

var gitExt = (IVSGitExt)await GetServiceAsync(typeof(IVSGitExt));
var context = UIContext.FromUIContextGuid(new Guid(Guids.UIContext_Git));
RefreshContext(context, gitExt);
Expand Down
1 change: 1 addition & 0 deletions src/GitHub.VisualStudio/GitHub.VisualStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
<Compile Include="AssemblyResolverPackage.cs" />
<Compile Include="Commands\BlameLinkCommand.cs" />
<Compile Include="Commands\CreateGistCommand.cs" />
<Compile Include="Commands\ShowMessageBoxCommand.cs" />
<Compile Include="Commands\LinkCommandBase.cs" />
<Compile Include="Commands\CopyLinkCommand.cs" />
<Compile Include="Commands\OpenLinkCommand.cs" />
Expand Down
57 changes: 34 additions & 23 deletions src/GitHub.VisualStudio/GitHubPackage.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Windows;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel.Design;
Expand All @@ -12,6 +11,7 @@
using GitHub.Logging;
using GitHub.Services;
using GitHub.Settings;
using GitHub.VisualStudio.Commands;
using GitHub.Services.Vssdk.Commands;
using GitHub.ViewModels.GitHubPane;
using GitHub.VisualStudio.Settings;
Expand Down Expand Up @@ -74,21 +74,35 @@ void LogVersionInformation()

async Task InitializeMenus()
{
var componentModel = (IComponentModel)(await GetServiceAsync(typeof(SComponentModel)));
var exports = componentModel.DefaultExportProvider;
var commands = new IVsCommandBase[]
IVsCommandBase[] commands;
if (ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
exports.GetExportedValue<IAddConnectionCommand>(),
exports.GetExportedValue<IBlameLinkCommand>(),
exports.GetExportedValue<ICopyLinkCommand>(),
exports.GetExportedValue<ICreateGistCommand>(),
exports.GetExportedValue<IOpenLinkCommand>(),
exports.GetExportedValue<IOpenPullRequestsCommand>(),
exports.GetExportedValue<IShowCurrentPullRequestCommand>(),
exports.GetExportedValue<IShowGitHubPaneCommand>(),
exports.GetExportedValue<IGoToSolutionOrPullRequestFileCommand>(),
exports.GetExportedValue<ISyncSubmodulesCommand>()
};
var componentModel = (IComponentModel)(await GetServiceAsync(typeof(SComponentModel)));
var exports = componentModel.DefaultExportProvider;
commands = new IVsCommandBase[]
{
exports.GetExportedValue<IAddConnectionCommand>(),
exports.GetExportedValue<IBlameLinkCommand>(),
exports.GetExportedValue<ICopyLinkCommand>(),
exports.GetExportedValue<ICreateGistCommand>(),
exports.GetExportedValue<IOpenLinkCommand>(),
exports.GetExportedValue<IOpenPullRequestsCommand>(),
exports.GetExportedValue<IShowCurrentPullRequestCommand>(),
exports.GetExportedValue<IShowGitHubPaneCommand>(),
exports.GetExportedValue<IGoToSolutionOrPullRequestFileCommand>(),
exports.GetExportedValue<ISyncSubmodulesCommand>()
};
}
else
{
// Show info message box when executed in non-Visual Studio process
var message = Resources.BlendDialogText;
commands = new IVsCommandBase[]
{
new ShowMessageBoxCommand(AddConnectionCommand.CommandSet, AddConnectionCommand.CommandId, this, message),
new ShowMessageBoxCommand(ShowGitHubPaneCommand.CommandSet, ShowGitHubPaneCommand.CommandId, this, message)
};
}

await JoinableTaskFactory.SwitchToMainThreadAsync();
var menuService = (IMenuCommandService)(await GetServiceAsync(typeof(IMenuCommandService)));
Expand All @@ -109,9 +123,6 @@ async Task EnsurePackageLoaded(Guid packageGuid)
[PartCreationPolicy(CreationPolicy.Shared)]
public class ServiceProviderExports
{
// Only export services for the Visual Studio process (they don't work in Expression Blend).
const string ProcessName = "devenv";

readonly IServiceProvider serviceProvider;

[ImportingConstructor]
Expand All @@ -120,19 +131,19 @@ public ServiceProviderExports([Import(typeof(SVsServiceProvider))] IServiceProvi
this.serviceProvider = serviceProvider;
}

[ExportForProcess(typeof(ILoginManager), ProcessName)]
[ExportForVisualStudioProcess]
public ILoginManager LoginManager => GetService<ILoginManager>();

[ExportForProcess(typeof(IGitHubServiceProvider), ProcessName)]
[ExportForVisualStudioProcess]
public IGitHubServiceProvider GitHubServiceProvider => GetService<IGitHubServiceProvider>();

[ExportForProcess(typeof(IUsageTracker), ProcessName)]
[ExportForVisualStudioProcess]
public IUsageTracker UsageTracker => GetService<IUsageTracker>();

[ExportForProcess(typeof(IVSGitExt), ProcessName)]
[ExportForVisualStudioProcess]
public IVSGitExt VSGitExt => GetService<IVSGitExt>();

[ExportForProcess(typeof(IPackageSettings), ProcessName)]
[ExportForVisualStudioProcess]
public IPackageSettings PackageSettings => GetService<IPackageSettings>();

T GetService<T>() => (T)serviceProvider.GetService(typeof(T));
Expand Down
38 changes: 32 additions & 6 deletions src/GitHub.VisualStudio/Settings/OptionsPage.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using GitHub.Settings;
using GitHub.VisualStudio.UI;
using Microsoft.VisualStudio.Shell;
using System;
using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows;
using GitHub.Exports;
using GitHub.Logging;
using GitHub.Settings;
using GitHub.VisualStudio.UI;
using Microsoft.VisualStudio.Shell;
using Serilog;

namespace GitHub.VisualStudio
{
Expand All @@ -13,16 +17,32 @@ namespace GitHub.VisualStudio
[Guid("68C87C7B-0212-4256-BB6D-6A6BB847A3A7")]
public class OptionsPage : UIElementDialogPage
{
static readonly ILogger log = LogManager.ForContext<OptionsPage>();

OptionsControl child;
IPackageSettings packageSettings;

protected override UIElement Child
{
get { return child ?? (child = new OptionsControl()); }
get
{
if (!ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
return new Grid(); // Show blank page
}

return child ?? (child = new OptionsControl());
}
}

protected override void OnActivate(CancelEventArgs e)
{
if (!ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
log.Warning("Don't activate options for non-Visual Studio process");
return;
}

base.OnActivate(e);
packageSettings = Services.DefaultExportProvider.GetExportedValue<IPackageSettings>();
LoadSettings();
Expand All @@ -47,6 +67,12 @@ void SaveSettings()

protected override void OnApply(PageApplyEventArgs args)
{
if (!ExportForVisualStudioProcessAttribute.IsVisualStudioProcess())
{
log.Warning("Don't apply options for non-Visual Studio process");
return;
}

if (args.ApplyBehavior == ApplyKind.Apply)
{
SaveSettings();
Expand Down