dnaeon / clingon

Command-line options parser system for Common Lisp
Other
122 stars 7 forks source link

Documentation about extending and adding aliases to pre-existing commands? #4

Closed 4lph4-Ph4un closed 1 year ago

4lph4-Ph4un commented 1 year ago

Hi!

I was wondering how one would add an alias to a pre-existing command? Or for example if I would like to add an option of calling --help with -h, how would that be done?

4lph4-Ph4un commented 1 year ago

And while I'm at it. How would a developer make a handler call help after specific cases? Let's say after noticing a specific command is used with it's default value?

dnaeon commented 1 year ago

Hey @4lph4-Ph4un ,

I was wondering how one would add an alias to a pre-existing command?

Not sure I fully understand the question, so can you please provide an example of what you mean by pre-existing command? As in a command provided by a separate package or system, which you want to integrate in your own package?

Or for example if I would like to add an option of calling --help with -h, how would that be done?

The --help and --version flags are bit special, since every command inherits them. If you want to provide a different --help flag with a short-name you can bind the clingon:*default-help-flag* var to your own help option.

And while I'm at it. How would a developer make a handler call help after specific cases? Let's say after noticing a specific command is used with it's default value?

Can you please provide an example usage of this one as well, so I better understand what you mean?

Thanks, Marin

4lph4-Ph4un commented 1 year ago

The --help and --version flags are bit special, since every command inherits them. If you want to provide a different --help flag with a short-name you can bind the clingon:default-help-flag var to your own help option.

Actually this clarifies how I get what I want. So I can pretty much overwrite the the flag info with that. Essentially that's what I wanted. Just a way to adjust the default --help command so it functions like originally, BUT has the alternative for invoking it via -h-shorthand!

The second question is how one would make a handler to call the default --help-function on some condition.. like let's say that that I want the CLI-utility I print something first like: "Hi, it seemed you provided a strange flag for option -x, we managed to calculate stuff, BUT are you entirely sure this is what you wanted? Here's the help" prints help

I know that example is a bit silly, but I think I'd likely have some usecases where I'd rather give a warning like that along the usage-info, rather than give an error directly!

dnaeon commented 1 year ago

Actually this clarifies how I get what I want. So I can pretty much overwrite the the flag info with that. Essentially that's what I wanted. Just a way to adjust the default --help command so it functions like originally, BUT has the alternative for invoking it via -h-shorthand!

I've just pushed a commit, which exports the vars for default options, so you have easy access to them and bind them as needed.

"Hi, it seemed you provided a strange flag for option -x, we managed to calculate stuff, BUT are you entirely sure this is what you wanted? Here's the help"

I believe what you are looking for are the CLINGON:PRINT-USAGE and CLINGON:PRINT-USAGE-AND-EXIT functions.

Here's an example where I use it in the jingle-demo application to print the usage, if the user didn't specify a sub-command.

Let me know if you have other questions.

4lph4-Ph4un commented 1 year ago

Hey! That was fast! Huge thanks! I can work with these really well!

nshan651 commented 4 months ago

Hi, Lisp newbie here, would you mind providing an example of how to correctly bind clingon:*default-help-flag*?

I would also like to use "-h" as a shorthand alias for "--help". I've tried using setf like so:

  (setf clingon:*default-help-flag* (clingon:make-option :flag
               :description "Display usage information and exit"
               :long-name "help"
               :short-name #\h
           :key :clingon.help.flag))

which does seem to update the var as expected:

CL-USER> clingon:*default-help-flag*
#<OPTION-BOOLEAN-TRUE short=h long=help>

However, running my cli executable shows that only the :long-name for help is used, and the -h option is nowhere to be found.

Thank you!

dnaeon commented 4 months ago

Hey @nshan651 ,

I'll try to provide some example soon, but in the meantime could you please share the full code that you have so far?

nshan651 commented 4 months ago

Thanks so much for the quick response! So for the most relevant bit, I'm following the 3-part options/handler/command workflow as suggested by the documentation:

(defun cli/options ()
  "Returns a list of options for cli command."
  (list
   (clingon:make-option
    :string
    :description "A csv file containing rank choice ballots."
    :short-name #\f
    :long-name "file"
    :key :filename)
   (clingon:make-option
    :string
    :description "Name to greet"
    :short-name #\n
    :long-name "name"
    :env-vars '("USER") 
    :initial-value "lisper"
    :key :name)))

(defun cli/handler (cmd)
  "Handler function for top-level cli command."
  (let ((free-args (clingon:command-arguments cmd))
    (filename (clingon:getopt cmd :filename))
    (name (clingon:getopt cmd :name)))
    (let ((ballots (cl-csv:read-csv (parse-namestring filename)))
      (candidates (remove-duplicates (reduce #'append ballots :key #'identity)
                     :test #'string=)))
      (format t "~A~%" candidates))))

(defun cli/command ()
  "Command-line entrypoint."
  (clingon:make-command
   :name "rcv"
   :description "Ranked choice voting."
   :version "0.1"
   :authors '("nshan651 <public@nshan651.com")
   :license "GPL-3.0"
   :options (cli/options)
   :handler #'cli/handler))

(defun main ()
  "Program entrypoint."
  (setf clingon:*default-help-flag* (clingon:make-option :flag
               :description "Display usage information and exit"
               :long-name "help"
               :short-name #\h
           :key :clingon.help.flag))

   (clingon:run (cli/command)))

So upon attempting to update clingon:*default-help-flag* with the previous setf command (which I just threw in my main function before calling clingon:run).

The variable appears to be updated to include a short and a long option in every function context after the main call, but it doesn't seem to get added to the usage printout or the options list.

I didn't attempt to add anything addition to the handler, since I figure --help and --version should already be handled internally.

My full source code is here. Thank you again for your help!

dnaeon commented 4 months ago

Hey @nshan651 ,

The clingon:*default-help-flag* is actually added to the clingon:*default-options* parameter and added to each command by the (defmethod initialize-instance :after ((command command) &key) method.

So, what you need is to actually set (or bind) clingon:*default-options* to your list of options, e.g.

CL-USER> (let* ((my-help-flag
                  (clingon:make-option :flag
                                       :description "display usage information and exit"
                                       :long-name "help"
                                       :short-name #\h
                                       :key :clingon.help.flag))
                (clingon:*default-options* (list clingon:*default-version-flag*
                                                 clingon:*default-bash-completions-flag*
                                                 my-help-flag)))
           (clingon:make-command
            :name "rcv"
            :description "Ranked choice voting."
            :version "0.1"
            :authors '("nshan651 <public@nshan651.com")
            :license "GPL-3.0"
            :options nil
            :handler nil))
#<CLINGON.COMMAND:COMMAND name=rcv options=3 sub-commands=0>

And then checking the options of this command returns us the new --help flag.

CL-USER> (clingon:command-options *)
(#<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=h long=help>
 #<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=NIL long=bash-completions>
 #<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=NIL long=version>)

If you want to set this once you would do something like this.

CL-USER> (defparameter *my-help-flag*
           (clingon:make-option :flag
                                :description "display usage information and exit"
                                :long-name "help"
                                :short-name #\h
                                :key :clingon.help.flag)
           "My custom help flag")
*MY-HELP-FLAG*
CL-USER> (setf clingon:*default-options*
               (list clingon:*default-version-flag*
                     clingon:*default-bash-completions-flag*
                     *my-help-flag*))
(#<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=NIL long=version>
 #<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=NIL long=bash-completions>
 #<CLINGON.OPTIONS:OPTION-BOOLEAN-TRUE short=h long=help>)

Now every newly created command will use your custom set of default options.

Let me know how it goes, thanks!

nshan651 commented 4 months ago

This is exactly what I was looking for, thank you so much!