Skip to content

Commit f5c3748

Browse files
committed
Intercept output of --help to correct the usage line
1 parent 0a9776e commit f5c3748

2 files changed

Lines changed: 47 additions & 1 deletion

File tree

src/BizHawk.Client.Common/ArgParser.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
using System.Collections.Generic;
44
using System.CommandLine;
5+
using System.CommandLine.Help;
6+
using System.CommandLine.Invocation;
57
using System.CommandLine.Parsing;
8+
using System.IO;
69
using System.Linq;
710
using 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) {}

src/BizHawk.Tests.Client.Common/ArgParserTests.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System.IO;
2+
using System.Linq;
3+
14
using BizHawk.Client.Common;
25

36
namespace BizHawk.Tests.Client.Common
@@ -11,6 +14,16 @@ public sealed class ArgParserTests
1114
public void TestConfigWithHelpOrVersion(params string[] args)
1215
=> Assert.AreEqual(0, ArgParser.ParseArguments(out _, args, fromUnitTest: true));
1316

17+
[TestMethod]
18+
public void TestHelpSaysPassFlagsFirst()
19+
{
20+
using StringWriter output = new();
21+
ArgParser.RunHelpActionForUnitTest(output);
22+
var outputLines = output.ToString().Split('\n');
23+
var usageLine = outputLines[outputLines.Index().First(tuple => tuple.Item.Contains("Usage:")).Index + 1].ToUpperInvariant();
24+
Assert.IsTrue(usageLine.IndexOf("OPTION") < usageLine.IndexOf("ROM"));
25+
}
26+
1427
[DataRow("rom.nes", "--nonexistent")]
1528
[DataRow("--nonexistent", "rom.nes")]
1629
[DataRow("--nonexistent", "--", "rom.nes")]

0 commit comments

Comments
 (0)