From cb9687f859165855b585a29f835cea5381f71f8d Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 5 Oct 2025 10:02:41 -0400 Subject: [PATCH] Make help output smarter --- SabreTools.CommandLine/CommandSet.cs | 84 +++++++++------------- SabreTools.CommandLine/Inputs/UserInput.cs | 2 +- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/SabreTools.CommandLine/CommandSet.cs b/SabreTools.CommandLine/CommandSet.cs index 39cdffa..edeee59 100644 --- a/SabreTools.CommandLine/CommandSet.cs +++ b/SabreTools.CommandLine/CommandSet.cs @@ -153,9 +153,9 @@ namespace SabreTools.CommandLine // Now append all available top-level flags output.Add("Available options:"); - foreach (string feature in _inputs.Keys) + foreach (var input in _inputs.Values) { - var outputs = _inputs[feature]?.Output(pre: 2, midpoint: 30); + var outputs = input.Output(pre: 2, midpoint: 30); if (outputs != null) output.AddRange(outputs); } @@ -182,9 +182,9 @@ namespace SabreTools.CommandLine // Now append all available flags recursively output.Add("Available options:"); - foreach (string feature in _inputs.Keys) + foreach (var input in _inputs.Values) { - var outputs = _inputs[feature]?.OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: true); + var outputs = input.OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: true); if (outputs != null) output.AddRange(outputs); } @@ -204,67 +204,51 @@ namespace SabreTools.CommandLine /// True if the long description should be formatted and output, false otherwise public void OutputFeatureHelp(string? featureName, bool includeLongDescription = false) { - // Start building the output list - List output = []; - - // If the feature name is null, empty, or just consisting of `-` characters, just show everything - if (string.IsNullOrEmpty(featureName?.TrimStart('-'))) + // If the feature name is null, empty, or just consisting of leading characters + string trimmedName = featureName?.TrimStart('-', '/', '\\') ?? string.Empty; + if (trimmedName.Length == 0) { OutputGenericHelp(); return; } - // Now try to find the feature that has the name included - string? realname = null; + // If a top-level input is found + if (TopLevelFlag(featureName!)) + { + // Retrieve the input + featureName = GetInputName(featureName!); + var input = _inputs[featureName]; + + // Append the formatted text + List output = []; + output.Add($"Available options for {featureName}:"); + output.AddRange(input.OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: includeLongDescription)); + + // Now write out everything in a staged manner + WriteOutWithPauses(output); + } + + // Find all partial matches List startsWith = []; - foreach (string feature in _inputs.Keys) + foreach (var kvp in _inputs) { - // If we have a match to the feature name somehow - if (feature == featureName) - { - realname = feature; - break; - } - - // If we have an invalid feature - else if (!_inputs.ContainsKey(feature) || _inputs[feature] == null) - { - startsWith.Add(feature); - } - - // If we have a match within the flags - else if (_inputs[feature]!.ContainsFlag(featureName!)) - { - realname = feature; - break; - } - - // Otherwise, we want to get features with the same start - else if (_inputs[feature]!.StartsWith(featureName!.TrimStart('-')[0])) - { - startsWith.Add(feature); - } + if (kvp.Value.StartsWith(trimmedName[0])) + startsWith.Add(kvp.Key); } - // If we have a real name found, append all available subflags recursively - if (realname != null) - { - output.Add($"Available options for {realname}:"); - output.AddRange(_inputs[realname]!.OutputRecursive(0, pre: 2, midpoint: 30, includeLongDescription: includeLongDescription)); - } - - // If no name was found but we have possible matches, show them - else if (startsWith.Count > 0) + // If there are possible matches, append them + if (startsWith.Count > 0) { + List output = []; output.Add($"\"{featureName}\" not found. Did you mean:"); foreach (string possible in startsWith) { - output.AddRange(_inputs[possible]!.Output(pre: 2, midpoint: 30, includeLongDescription: includeLongDescription)); + output.AddRange(_inputs[possible].Output(pre: 2, midpoint: 30, includeLongDescription: includeLongDescription)); } - } - // Now write out everything in a staged manner - WriteOutWithPauses(output); + // Now write out everything in a staged manner + WriteOutWithPauses(output); + } } /// diff --git a/SabreTools.CommandLine/Inputs/UserInput.cs b/SabreTools.CommandLine/Inputs/UserInput.cs index 35d8c8d..a302070 100644 --- a/SabreTools.CommandLine/Inputs/UserInput.cs +++ b/SabreTools.CommandLine/Inputs/UserInput.cs @@ -100,7 +100,7 @@ namespace SabreTools.CommandLine.Inputs /// Character to check against /// True if the flag was found, false otherwise public bool StartsWith(char c) - => Flags.Exists(f => f.TrimStart('-').ToLowerInvariant()[0] == c); + => Flags.Exists(f => f.TrimStart('-', '/', '\\').ToLowerInvariant()[0] == c); #endregion