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 (); } }