22
33using System . Collections . Generic ;
44using System . CommandLine ;
5+ using System . CommandLine . Help ;
6+ using System . CommandLine . Invocation ;
57using System . CommandLine . Parsing ;
8+ using System . IO ;
69using System . Linq ;
710using System . Net . Sockets ;
811
@@ -15,9 +18,30 @@ namespace BizHawk.Client.Common
1518 /// <summary>Parses command-line flags into a <see cref="ParsedCLIFlags"/> struct.</summary>
1619 public static class ArgParser
1720 {
21+ private sealed class HelpSedAction ( HelpAction stockAction ) : SynchronousCommandLineAction
22+ {
23+ public override int Invoke ( ParseResult parseResult )
24+ {
25+ var outerOutput = parseResult . InvocationConfiguration . Output ;
26+ using StringWriter innerOutput = new ( ) ;
27+ parseResult . InvocationConfiguration . Output = innerOutput ;
28+ var result = stockAction . Invoke ( parseResult ) ;
29+ var dollarZero = OSTailoredCode . IsUnixHost
30+ #if true
31+ ? "./EmuHawkMono.sh"
32+ #else //TODO for .NET Core: see https://github.com/dotnet/runtime/issues/101837
33+ ? Environment . GetCommandLineArgs ( ) [ 0 ] . SubstringAfterLast ( '/' )
34+ #endif
35+ : Environment . GetCommandLineArgs ( ) [ 0 ] . SubstringAfterLast ( '\\ ' ) ;
36+ outerOutput. Write ( innerOutput . ToString ( ) . Replace ( "EmuHawk" , dollarZero )
37+ . Replace ( "[<rom>...] [options]" , "[option...] [rom]" ) ) ;
38+ return result ;
39+ }
40+ }
41+
1842 private static readonly Argument < string [ ] > ArgumentRomFilePath = new ( "rom" )
1943 {
20- Description = "path; if specified, the file will be loaded the same way as it would be from `File` > `Open...`; this argument can and should be given LAST despite what it says at the top of --help " ,
44+ Description = "path; if specified, the file will be loaded the same way as it would be from `File` > `Open...`" ,
2145 } ;
2246
2347 private static readonly Option < string ? > OptionAVDumpAudioSync = new ( "--audiosync" )
@@ -134,6 +158,8 @@ private static RootCommand GetRootCommand()
134158 ( string . IsNullOrEmpty ( VersionInfo . CustomBuildString ) ? "EmuHawk" : VersionInfo . CustomBuildString )
135159 } , a multi-system emulator frontend\n { VersionInfo . GetEmuVersion ( ) } ") ;
136160 root . Options . RemoveAll ( option => option is VersionOption ) ; // we have our own version command
161+ var helpOption = root . Options . OfType < HelpOption > ( ) . First ( ) ;
162+ helpOption . Action = new HelpSedAction ( ( HelpAction ) helpOption . Action ! ) ;
137163
138164 // `--help` uses this order, so keep alphabetised by flag
139165 root . Add ( /* --audiosync */ OptionAVDumpAudioSync ) ;
@@ -280,6 +306,13 @@ private static void EnsureConsole()
280306 return null ;
281307 }
282308
309+ internal static void RunHelpActionForUnitTest ( TextWriter output )
310+ {
311+ var result = CommandLineParser . Parse ( GetRootCommand ( ) , [ "--help" ] ) ;
312+ result . InvocationConfiguration . Output = output ;
313+ result . Invoke ( ) ;
314+ }
315+
283316 public sealed class ArgParserException : Exception
284317 {
285318 public ArgParserException ( string message ) : base ( message ) { }
0 commit comments