Skip to content

Commit

Permalink
Created wrappers for Visual Studio's font and color classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
reduckted committed Feb 9, 2023
1 parent 4230c40 commit fd46d05
Show file tree
Hide file tree
Showing 21 changed files with 1,735 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using Microsoft.VisualStudio.Shell;

namespace Community.VisualStudio.Toolkit
{
/// <summary>
/// Registers font and color definitions in Visual Studio.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ProvideFontsAndColorsAttribute : ProvideServiceAttributeBase
{
/// <summary>
/// Initializes a new instance of the <see cref="ProvideFontsAndColorsAttribute"/> class.
/// The <paramref name="providerType"/> will also be provided as a service.
/// </summary>
/// <param name="providerType">The type of the <see cref="BaseFontAndColorProvider"/> implementation to provide.</param>
public ProvideFontsAndColorsAttribute(Type providerType)
: base(providerType, "Services")
{
ProviderType = providerType;
}

/// <summary>
/// The <see cref="BaseFontAndColorProvider"/> implementation to provide.
/// </summary>
public Type ProviderType { get; }

/// <inheritdoc/>
public override void Register(RegistrationContext context)
{
if (context is not null)
{
foreach (Type categoryType in BaseFontAndColorProvider.GetCategoryTypes(ProviderType))
{
using (Key key = context.CreateKey($"FontAndColors\\{categoryType.FullName}"))
{
key.SetValue("Category", categoryType.GUID.ToString("B"));
key.SetValue("Package", ProviderType.GUID.ToString("B"));
}
}
}

base.Register(context);
}

/// <inheritdoc/>
public override void Unregister(RegistrationContext context)
{
if (context is not null)
{
foreach (Type categoryType in BaseFontAndColorProvider.GetCategoryTypes(ProviderType))
{
context.RemoveKey($"FontAndColors\\{categoryType.FullName}");
}
}

base.Unregister(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// This is a copy of the attribute of the same name from .NET 5+ to allow it to be used in .NET Framework.
/// https://github.com/dotnet/runtime/blob/47071da67320985a10f4b70f50f894ab411f4994/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L137
/// </summary>
internal class MemberNotNullAttribute : Attribute
{
public MemberNotNullAttribute(string member) => Members = new[] { member };
public MemberNotNullAttribute(params string[] members) => Members = members;
public string[] Members { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,15 @@ public static class AsyncPackageExtensions
/// <returns>A collection of the command instances</returns>
public static async Task<IEnumerable<object>> RegisterCommandsAsync(this AsyncPackage package, params Assembly[] assemblies)
{
List<Assembly> assembliesList = assemblies.ToList();
Assembly packageAssembly = package.GetType().Assembly;
if (!assembliesList.Contains(packageAssembly))
assembliesList.Add(packageAssembly);

Type baseCommandType = typeof(BaseCommand<>);
IEnumerable<Type> commandTypes = assembliesList.SelectMany(x => x.GetTypes())
IEnumerable<Type> commandTypes = IncludePackageAssembly(assemblies, package).SelectMany(x => x.GetTypes())
.Where(x =>
!x.IsAbstract
&& x.IsAssignableToGenericType(baseCommandType)
&& x.GetCustomAttribute<CommandAttribute>() != null);

List<object> commands = new();
foreach (Type? commandType in commandTypes)
foreach (Type commandType in commandTypes)
{
MethodInfo initializeAsyncMethod = commandType.GetMethod(
nameof(BaseCommand<object>.InitializeAsync),
Expand All @@ -56,18 +51,13 @@ public static async Task<IEnumerable<object>> RegisterCommandsAsync(this AsyncPa
/// <returns></returns>
public static void RegisterToolWindows(this AsyncPackage package, params Assembly[] assemblies)
{
List<Assembly> assembliesList = assemblies.ToList();
Assembly packageAssembly = package.GetType().Assembly;
if (!assembliesList.Contains(packageAssembly))
assembliesList.Add(packageAssembly);

Type baseToolWindowType = typeof(BaseToolWindow<>);
IEnumerable<Type> toolWindowTypes = assembliesList.SelectMany(x => x.GetTypes())
IEnumerable<Type> toolWindowTypes = IncludePackageAssembly(assemblies, package).SelectMany(x => x.GetTypes())
.Where(x =>
!x.IsAbstract
&& x.IsAssignableToGenericType(baseToolWindowType));

foreach (Type? toolWindowtype in toolWindowTypes)
foreach (Type toolWindowtype in toolWindowTypes)
{
MethodInfo initializeMethod = toolWindowtype.GetMethod(
"Initialize",
Expand All @@ -76,5 +66,38 @@ public static void RegisterToolWindows(this AsyncPackage package, params Assembl
initializeMethod.Invoke(null, new object[] { package });
}
}

/// <summary>
/// Finds, creates and registers <see cref="BaseFontAndColorProvider"/> implementations.
/// </summary>
/// <param name="package">The package to register the provider in.</param>
/// <param name="assemblies">Additional assemblies to scan. The assembly that <paramref name="package"/> is in will always be scanned.</param>
/// <returns>A task.</returns>
public static async Task RegisterFontAndColorProvidersAsync(this AsyncPackage package, params Assembly[] assemblies)
{
Type baseProviderType = typeof(BaseFontAndColorProvider);
IEnumerable<Type> providerTypes = IncludePackageAssembly(assemblies, package)
.SelectMany(x => x.GetTypes())
.Where(x => !x.IsAbstract && baseProviderType.IsAssignableFrom(x));

foreach (Type providerType in providerTypes)
{
ConstructorInfo? ctor = providerType.GetConstructor(Type.EmptyTypes)
?? throw new InvalidOperationException($"The type '{providerType.Name}' must have a parameterless constructor.");
BaseFontAndColorProvider provider = (BaseFontAndColorProvider)ctor.Invoke(Array.Empty<object>());
await provider.InitializeAsync(package);
}
}

private static IReadOnlyList<Assembly> IncludePackageAssembly(IEnumerable<Assembly> assemblies, AsyncPackage package)
{
List<Assembly> list = assemblies.ToList();
Assembly packageAssembly = package.GetType().Assembly;
if (!list.Contains(packageAssembly))
{
list.Add(packageAssembly);
}
return list;
}
}
}
Loading

0 comments on commit fd46d05

Please sign in to comment.