Command Line Subcommands in Nim

Here’s the translation of the Go code to Nim, along with explanations in Markdown format suitable for Hugo:

Some command-line tools have many subcommands, each with its own set of flags. For example, git add and git commit are two different subcommands of the git tool. Nim’s parseopt module lets us easily define simple subcommands that have their own flags.

import os, parseopt

proc main() =
  # We declare subcommands and their flags using a case statement
  # within the parsing loop
  var p = initOptParser(commandLineParams())
  var cmd = ""

  for kind, key, val in p.getopt():
    case kind
    of cmdArgument:
      if cmd == "":
        cmd = key
      else:
        case cmd
        of "foo":
          echo "tail argument for foo: ", key
        of "bar":
          echo "tail argument for bar: ", key
        else:
          echo "Unknown command"
          quit(1)
    of cmdLongOption, cmdShortOption:
      case cmd
      of "foo":
        case key
        of "enable":
          echo "foo enable: ", val
        of "name":
          echo "foo name: ", val
        else:
          echo "Unknown option for foo: ", key
      of "bar":
        case key
        of "level":
          echo "bar level: ", val
        else:
          echo "Unknown option for bar: ", key
      else:
        echo "Unknown command"
        quit(1)
    of cmdEnd: assert(false) # cannot happen

  if cmd == "":
    echo "expected 'foo' or 'bar' subcommands"
    quit(1)

  case cmd
  of "foo":
    echo "subcommand 'foo'"
  of "bar":
    echo "subcommand 'bar'"
  else:
    echo "expected 'foo' or 'bar' subcommands"
    quit(1)

when isMainModule:
  main()

To run the program, save it as command_line_subcommands.nim and use the Nim compiler:

$ nim c -r command_line_subcommands.nim

First, invoke the foo subcommand:

$ ./command_line_subcommands foo --enable=true --name=joe a1 a2
subcommand 'foo'
foo enable: true
foo name: joe
tail argument for foo: a1
tail argument for foo: a2

Now try bar:

$ ./command_line_subcommands bar --level=8 a1
subcommand 'bar'
bar level: 8
tail argument for bar: a1

But bar won’t accept foo’s flags:

$ ./command_line_subcommands bar --enable a1
Unknown option for bar: enable

In Nim, we use the parseopt module to handle command-line arguments and flags. The structure is a bit different from Go, as we parse all options in a single loop and use a case statement to handle different subcommands and their specific flags.

This example demonstrates how to create a command-line tool with subcommands in Nim. Each subcommand can have its own set of flags and handle its own logic.