Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested procs/dispatches #13

Closed
davidnorthetal opened this issue Dec 18, 2017 · 13 comments
Closed

Nested procs/dispatches #13

davidnorthetal opened this issue Dec 18, 2017 · 13 comments

Comments

@davidnorthetal
Copy link

As title states, don't think it's possible yet.

Something like:

myapp someproc someotherprocfoo --verbose
myapp someproc someotherprocbar --quiet

myapp someproc
usage: myapp someproc [someotherprocfoo | someotherprocbar]

Yay/Nay? - Can you give an inkling how much work this would be?

Thanks for your input.

@c-blake
Copy link
Owner

c-blake commented Dec 18, 2017

I think it would not be so hard to add a dispatchMultiMulti if you only have 2 levels of stuff dispatched by name/non-options as per your example. I'm not sure how hard it would be to do a more "recursive"/arbitrary nesting dispatchMulti. That seems much more likely to get blocked/complicated by Nim macro limitations. dispatchMulti is much simpler than dispatchGen if you want to take a try at a dispatchMultiMulti (or whatever name) and send a PR.

Personally, I have never encountered even a 2-level case as you describe. Your example even has a shared root someproc, though I assume that was just for brevity not because you have "1.5" levels, so to speak. I read a manifesto once somewhere asserting that recursive completeness along these lines was some benchmark of quality in CLI parser space, but that seemed like a bit of a stretch. (Also, I believe that was more about multiple wrappable sections with -- type separators, not multiple keyword-oriented dispatchers, but I may be misremembering.)

@davidnorthetal
Copy link
Author

davidnorthetal commented Dec 18, 2017

thanks I'll look into dispatchMultiMulti - for the 2-level case, try git remote [TAB]
I agree that 2-level case probably covers most cases.

@c-blake
Copy link
Owner

c-blake commented Dec 18, 2017

Cool. Just in case this didn't already occur to you and obviously depending on your exact use case, you may also get some mileage out of just separating your dispatchGen dispatcher generation from your dispatch_someproc as in my test/SemiAutoMulti.nim example/test program. Help message generation there is still automatic (just invoking the dispatcher with a special cmdline to emit the help with a prefix to indent it. In any case, either that program or the output of nim -d:printMultiDisp test/FullyAutoMulti.nim may be helpful in your attempts at a 2-level one.

@c-blake
Copy link
Owner

c-blake commented Dec 18, 2017

One last thought - it might be possible to make dispatchMulti smart enough to handle (possibly only one-level) nested array arguments as in:

  dispatchMulti([ demo, help = { "verb": "on=chatty, off=quiet" } ],
                [ "remote",
                    [ add, help = { "mirror": "do not use separate remotes } ],
                    [ prune, help = { "dryRun" : "only list what would be done" } ] ],
                [ show, short = { "gamma": 'z' } ])

You would just need to test if the first argument is a string (or proc, but a string test is probably easier) and then do the right thing there.

@xmonader
Copy link

This is a pretty needed feature,

for example:

docker container --help                                                                                                        1 ↵  ahmed@ahmedheaven

Usage:  docker container COMMAND

Manage containers

Options:


Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  inspect     Display detailed information on one or more containers
  kill        Kill one or more running containers
  logs        Fetch the logs of a container
  ls          List containers
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  prune       Remove all stopped containers
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  run         Run a command in a new container
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker container COMMAND --help' for more information on a command.
  …/container_cmd     development    docker container list --help                                                                                                     ✔  ahmed@ahmedheaven

Usage:  docker container ls [OPTIONS]

List containers

Aliases:
  ls, ps, list

Options:
  -a, --all             Show all containers (default shows just running)
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print containers using a Go template
  -n, --last int        Show n last created containers (includes all states) (default -1)
  -l, --latest          Show the latest created container (includes all states)
      --no-trunc        Don't truncate output
  -q, --quiet           Only display numeric IDs
  -s, --size            Display total file sizes

@c-blake
Copy link
Owner

c-blake commented Sep 20, 2018

As mentioned above, I am open to reviewing a PR for a dispatchMultiMulti or expanded dispatchMulti if you want to try, but my own interest in this feature is probably too limited to motivate me to do it.

@xmonader
Copy link

I understand, I'll try to pick it up on my free time, as a work around I was trying to dispatch manually

e.g:

proc containers(args:seq[string]=@[ ] ): 
  let subcommand = args[0]
  if subcommand == "list":
     listContainers(args[1..^1]) 

but that didn't work because of options validation, any idea how to get around that?

@c-blake
Copy link
Owner

c-blake commented Sep 20, 2018

dispatch is a very thin wrapper around dispatchGen. You probably want to use dispatchGen on all the sub-sub commands first and then write some wrapper/dispatching logic like test/SemiAutoMulti.nim.

@c-blake
Copy link
Owner

c-blake commented Jan 6, 2019

Github really is too hair-trigger about auto-closing issues.

@c-blake c-blake reopened this Jan 6, 2019
@c-blake
Copy link
Owner

c-blake commented Jan 10, 2019

So, just an update for @xmonader & @davidnorthetal . Things are pretty close to being workable. There is now a test/SemiMultMult.nim that actually does work for correct-entry dispatching and correct entry helps. (Some of the spell check/suggesting is a bit wonky which is probably fixable with some more care on that test program.) It's obviously very manual to write, but working at any level is some progress.

What I am hoping to do is get something like test/MultiMulti.nim working. That will allow arbitrary nesting and be pretty easy to use. The CLI author will just have to declare the sub-(sub-sub-..) commands in a "bottom up" fashion, but otherwise the structure of the code will be similar to the structure of the command. This kind of interface seems only slightly harder to use and much more do-able than other ideas raised in this thread. All that is needed is to factor dispatchMulti into dispatchMultiGen and dispatchMulti and that the branch-multi-calls are similar enough to the leaf calls to all be compatible. I did most of that already.

Had this approach occurred to me earlier I would have suggested one of you two look into that. (There may be a little more work to get mergeParams working right - I am thinking maybe dispatchMulti should use everything after the string in a [string, ...] expression as input to the dispatchGen for that multi-command branch. Then at least the CLI author could manually set mergeNames at each multi-command entry point. Maybe that can be automatic. Not sure.) Anyway, it's really much closer to working if I get hit by a bus or don't get around to it or something.

@c-blake
Copy link
Owner

c-blake commented Jan 16, 2019

Ok. Latest commit of cligen.nim and test/MultiMulti.nim works and isn't so bad to use. See test/MultiMulti.nim.

It would be nice to be more automatic, but it's way better than test/SemiMultMult.nim.

Current weirdnesses - the mergeNames operates in some flattened namespace (like $MULTIMULTI_DEMO) and one or two indented help modes does not quite work, but all the basics besides those work. It might well work well enough for your purposes.

@c-blake
Copy link
Owner

c-blake commented Jan 16, 2019

I even got test/MultMultMult.nim working.

@c-blake
Copy link
Owner

c-blake commented Jan 16, 2019

I am going to go ahead and close this issue. I'm sure it's not 100% how it should be, but any follow-on issues should be much more specific than the general feature which works now.

@c-blake c-blake closed this as completed Jan 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants