Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# / .NET - System.CommandLine: Making the command line case insensitive

This exists as an issues but it hasn't yet been resolved - System.CommandLine: Consider optional case insensitive parsing #133

How can we make it case insensitive?

like image 929
Tom Avatar asked Feb 21 '26 01:02

Tom


1 Answers

You can achieve thus in about 60 lines of code by writing generic Middleware processor, as ScottArbeit showed here: Scotts Comment and Scotts example code in f#.

Here is a small example in c# which perfectly works: You can call the compiled App and all parameters are working as expected: --version, --VerSion, -v and -V

public class Program {

   private static readonly bool CaseInsensitive = true; // Enable case-insensitive parsing

   static async Task<int> Main(string[] args) {

      var rootCommand2 = new RootCommand("Sample app for System.CommandLine");

      // Create the CommandLineBuilder with and add the Middleware
      var builder = new CommandLineBuilder(rootCommand2)
                    // Set option verb & shortcut
                   .UseVersionOption("--version", "-v")
                   .AddMiddleware(CaseInsensitiveMiddleware, MiddlewareOrder.ExceptionHandler)
                   .UseDefaults();

      var parser = builder.Build();
      return await parser.InvokeAsync(args);
   }

   public static void CaseInsensitiveMiddleware(InvocationContext context) {
      if (!CaseInsensitive) return;

      var commandOptions = context.ParseResult.CommandResult.Command.Options
                                  .Concat(context.ParseResult.RootCommandResult.Command.Options);

      var allAliases = commandOptions.SelectMany(option => option.Aliases);

      string[] GetCorrectTokenCase(string[] tokens) {
         var newTokens = new List<string>(tokens.Length);

         for (int i = 0; i < tokens.Length; i++) {
            var token = tokens[i];

            var matchingAlias = allAliases.FirstOrDefault
               (alias =>
                   alias.Equals(token, StringComparison.InvariantCultureIgnoreCase));

            if (matchingAlias != null) {
               newTokens.Add(matchingAlias);
               continue;
            }

            if (i > 0) {
               var previousToken = tokens[i - 1];

               var matchingOption = commandOptions.FirstOrDefault
                  (option =>
                      option.Aliases.Contains(previousToken, StringComparer.InvariantCultureIgnoreCase));

               if (matchingOption != null) {
                  var completions = matchingOption.GetCompletions()
                                                  .Select(completion => completion.InsertText)
                                                  .ToArray();

                  if (completions.Length > 0) {
                     var matchingCompletion = completions.FirstOrDefault
                        (completion =>
                            token.Equals(completion, StringComparison.InvariantCultureIgnoreCase));
                     newTokens.Add(matchingCompletion ?? token);
                  }
                  else {
                     newTokens.Add(token);
                  }
               }
               else {
                  newTokens.Add(token);
               }
            }
            else {
               newTokens.Add(token);
            }
         }

         return newTokens.ToArray();
      }

      var      tokens = context.ParseResult.Tokens.Select(token => token.Value).ToArray();
      string[] newTokens;

      if (tokens.Length == 0) {
         newTokens = Array.Empty<string>();
      }
      else if (tokens.Length == 1) {
         newTokens = new[] { tokens[0].ToLowerInvariant() };
      }
      else {
         if (tokens[0].StartsWith("-")) {
            newTokens = tokens;
         }
         else {
            newTokens = new[] { tokens[0].ToLowerInvariant(), tokens[1].ToLowerInvariant() }
                       .Concat(GetCorrectTokenCase(tokens.Skip(2).ToArray()))
                       .ToArray();
         }
      }

      context.ParseResult = context.Parser.Parse(newTokens);
   }
}
like image 116
Tom Avatar answered Feb 22 '26 15:02

Tom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!