using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace Terminal.Gui.Examples;
///
/// Provides methods for discovering example applications by scanning assemblies for example metadata attributes.
///
public static class ExampleDiscovery
{
///
/// Discovers examples from the specified assembly file paths.
///
/// The paths to assembly files to scan for examples.
/// An enumerable of objects for each discovered example.
[RequiresUnreferencedCode ("Calls System.Reflection.Assembly.LoadFrom")]
[RequiresDynamicCode ("Calls System.Reflection.Assembly.LoadFrom")]
public static IEnumerable DiscoverFromFiles (params string [] assemblyPaths)
{
foreach (string path in assemblyPaths)
{
if (!File.Exists (path))
{
continue;
}
Assembly? asm = null;
try
{
asm = Assembly.LoadFrom (path);
}
catch
{
// Skip assemblies that can't be loaded
continue;
}
ExampleMetadataAttribute? metadata = asm.GetCustomAttribute ();
if (metadata is null)
{
continue;
}
ExampleInfo info = new ()
{
Name = metadata.Name,
Description = metadata.Description,
AssemblyPath = path,
Categories = asm.GetCustomAttributes ()
.Select (c => c.Category)
.ToList (),
DemoKeyStrokes = ParseDemoKeyStrokes (asm)
};
yield return info;
}
}
///
/// Discovers examples from assemblies in the specified directory.
///
/// The directory to search for assembly files.
/// The search pattern for assembly files (default is "*.dll").
/// The search option for traversing subdirectories.
/// An enumerable of objects for each discovered example.
[RequiresUnreferencedCode ("Calls System.Reflection.Assembly.LoadFrom")]
[RequiresDynamicCode ("Calls System.Reflection.Assembly.LoadFrom")]
public static IEnumerable DiscoverFromDirectory (
string directory,
string searchPattern = "*.dll",
SearchOption searchOption = SearchOption.AllDirectories
)
{
if (!Directory.Exists (directory))
{
return [];
}
string [] assemblyPaths = Directory.GetFiles (directory, searchPattern, searchOption);
return DiscoverFromFiles (assemblyPaths);
}
private static List ParseDemoKeyStrokes (Assembly assembly)
{
List sequences = new ();
foreach (ExampleDemoKeyStrokesAttribute attr in assembly.GetCustomAttributes ())
{
List keys = new ();
if (attr.KeyStrokes is { Length: > 0 })
{
keys.AddRange (attr.KeyStrokes);
}
if (!string.IsNullOrEmpty (attr.RepeatKey))
{
for (var i = 0; i < attr.RepeatCount; i++)
{
keys.Add (attr.RepeatKey);
}
}
if (keys.Count > 0)
{
sequences.Add (
new ()
{
KeyStrokes = keys.ToArray (),
Order = attr.Order
});
}
}
return sequences.OrderBy (s => s.Order).ToList ();
}
}