The defmain Reference Manual

Table of Contents

Next: , Previous: , Up: (dir)   [Contents][Index]

The defmain Reference Manual

This is the defmain Reference Manual, version 0.11.0, generated automatically by Declt version 3.0 "Montgomery Scott" on Wed Oct 13 10:41:51 2021 GMT+0.


Next: , Previous: , Up: Top   [Contents][Index]

1 Introduction

DEFMAIN - intuitive command line options parser for Common Lisp

Table of Contents

[in package DEFMAIN with nicknames DEFMAIN/DEFMAIN]

1 DEFMAIN ASDF System Details

2 Reasoning

Library net.didierverna.clon very powerful, but too complicated to use in simple cases. This library provides a wrapper which will suite your needs in 80% cases.

Compare this code, which uses DEFMAIN macro:

(defmain (main) ((debug "Show traceback instead of short message."
                        :flag t)
                 (log   "Filename to write log to.")
                 (token "GitHub personal access token."
                        :env-var "TOKEN")
                 &rest repositories)
  "Utility to analyze github forks."

   ;; Making real work
  (loop for reporitory in repositories
        do (analyze repository
                    :log log
                    :debug debug
                    :token token)))

With code providing the same functionality, but using raw net.didierverna.clon system:

(net.didierverna.clon:defsynopsis (:postfix "REPOSITORY")
  (text :contents "This utility builds a report about all non-merged commits for any github repository. Just give some repository name like \"antirez/redis\" as an argument and pipe stdout to some file.")
  (flag :short-name "h" :long-name "help"
        :description "Print this help and exit.")
  (flag :short-name "v" :long-name "version"
        :description "Print version number and exit.")
  (flag :long-name "debug"
        :description "Show traceback instead of short message.")
  (stropt :short-name "l" :long-name "log"
          :description "Filename to write log to.")
  (stropt :short-name "t" :long-name "token"
          :env-var "TOKEN"
          :description "GitHub personal access token."))

(defun main (&rest argv)
  (declare (ignorable argv))
  (net.didierverna.clon:make-context :cmdline (cons "12forks" argv))
  (when (net.didierverna.clon:getopt :long-name "help")
    (net.didierverna.clon:help)
    (net.didierverna.clon:exit))

  ;; Making real work
  (loop for reporitory in (remainder)
        do (analyze repository
                    :log (net.didierverna.clon:getopt :long-name "log")
                    :debug (net.didierverna.clon:getopt :long-name "debug")
                    :token (net.didierverna.clon:getopt :long-name "token"))))

3 Installation

This system is available as part of the https://ultralisp.org distribution. Follow instruction on the site to setup the distribution, and then install DEFMAIN system using Quicklisp client:

(ql:quickload :defmain)

4 Usage

The main entry point for defining the main function for your program is the DEFMAIN macro:

4.1 Subcommands

Also, you might want to build a more complex command-line interface with subcommands.

In this case, you need to use DEFMAIN macro to define the main entry-point, and then to define additional subcommands using DEFCOMMAND macro:

4.2 Helpers

When writing more complex logic, these helpers could be useful:

5 Roadmap

Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread"
RUNNING {10005285B3}>:

Options #<LISPOBJ {1002705593}> and #<STROPT {1002705C03}>:
indentical short name "s".

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING
{10005285B3}>
0: (`SB-DEBUG::DEBUGGER-DISABLED-HOOK` #<SIMPLE-ERROR "Options ~A and
~A: indentical short name ~S." {100277D8F3}> #<unused argument>
:QUIT T)
1: (`SB-DEBUG::RUN-HOOK` SB-EXT:*INVOKE-DEBUGGER-HOOK* #<SIMPLE-ERROR
"Options ~A and ~A: indentical short name ~S." {100277D8F3}>)
2: (INVOKE-DEBUGGER #<SIMPLE-ERROR "Options ~A and ~A: indentical short name ~S." {100277D8F3}>)
3: (ERROR "Options ~A and ~A: indentical short name ~S."
#<NET.DIDIERVERNA.CLON::LISPOBJ {1002705593}>
#<NET.DIDIERVERNA.CLON: :STROPT {1002705C03}> "s")
4: ((:METHOD NET.DIDIERVERNA.CLON::CHECK-NAME-CLASH
(NET.DIDIERVERNA.CLON::OPTION NET.DIDIERVERNA.CLON::OPTION))
#<NET.DIDIERVERNA.CLON::LISPOBJ {1002705593}>
#<NET.DIDIERVERNA.CLON::STROPT {1002705C03}>) [fast-method]
5: ((:METHOD INITIALIZE-INSTANCE :AFTER
(NET.DIDIERVERNA.CLON::CONTAINER)) #<NET.DIDIERVERNA.CLON::SYNOPSIS
{100270C013}>) [fast-method]

[generated by 40ANTS-DOC]

Next: , Previous: , Up: Top   [Contents][Index]

2 Systems

The main system appears first, followed by any subsystem dependency.


Next: , Previous: , Up: Systems   [Contents][Index]

2.1 defmain

Author

Alexander Artemenko

Home Page

https://40ants.com/defmain

Source Control

(:git "https://github.com/40ants/defmain")

Bug Tracker

https://github.com/40ants/defmain/issues

License

BSD

Description

A wrapper around net.didierverna.clon which makes command line arguments parsing easier.

Version

0.11.0

Dependency

defmain/defmain (system)

Source

defmain.asd (file)


Previous: , Up: Systems   [Contents][Index]

2.2 defmain/defmain

Author

Alexander Artemenko

Home Page

https://40ants.com/defmain

Source Control

(:git "https://github.com/40ants/defmain")

Bug Tracker

https://github.com/40ants/defmain/issues

License

BSD

Dependencies
Source

defmain.asd (file)

Component

file-type.lisp (file)


Next: , Previous: , Up: Top   [Contents][Index]

3 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

3.1 Lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

3.1.1 defmain.asd

Location

/home/quickref/quicklisp/dists/quicklisp/software/defmain-20210630-git/defmain.asd

Systems

Previous: , Up: Lisp files   [Contents][Index]

3.1.2 defmain/defmain/file-type.lisp

Parent

defmain/defmain (system)

Location

defmain.lisp

Packages

defmain

Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

4 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

4.1 defmain

Source

file-type.lisp (file)

Nickname

defmain/defmain

Use List

common-lisp

Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

5 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

5.1 Exported definitions


Next: , Previous: , Up: Exported definitions   [Contents][Index]

5.1.1 Special variables

Special Variable: @helpers
Package

defmain

Source

file-type.lisp (file)

Special Variable: @index
Package

defmain

Source

file-type.lisp (file)

Special Variable: @installation
Package

defmain

Source

file-type.lisp (file)

Special Variable: @reasoning
Package

defmain

Source

file-type.lisp (file)

Special Variable: @roadmap
Package

defmain

Source

file-type.lisp (file)

Special Variable: @subcommands
Package

defmain

Source

file-type.lisp (file)

Special Variable: @usage
Package

defmain

Source

file-type.lisp (file)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

5.1.2 Macros

Macro: defcommand (PARENT NAME) (&rest ARGS) &body BODY

This macro is similar to DEFMAIN macro in terms of arguments and body processing.

The only difference is that instead of the single name you have to provide a
list of two names:

- First element should be the name of the parent function.
It can be either a main entry-point or other subcommand.
- Second element is a symbol to name the subcommand.

Here is an example with of a program with two subcommands.
Pay attention to the ‘MAIN‘ function’s argument list.
It ends with a special symbol &SUBCOMMAND. It should be
provided to let macro know there will be some subcommands
defined later.

“‘
(defmain (main) ((verbose "More detail in the output") &subcommand)
...)

(defcommand (main upload) ((upstream "Repository name")
(force "Rewrite changes in case of conflict"
:flag t))
...)

(defcommand (main sync) ()
"Yet another subcommand."
...)
“‘

All arguments, specified for the ‘MAIN‘ function also bound for all it’s subcommands. On command-line these arguments should preceed the subcommand’s name

By default, main command run’s specified subcommand and exits, but you can use
it as a decorator, to execute some common code before and after as subcommand.

To run subcommand, execute SUBCOMMAND function:

“‘
(defmain (main) ((verbose "More detail in the output"))
(format t "Before subcommand.~%")
(defmain:subcommand)
(format t "After subcommand.~%"))
“‘

Package

defmain

Source

file-type.lisp (file)

Macro: defmain (NAME &key PROGRAM-NAME) (&rest ARGS) &body BODY

This macro let you to define a main function for a command-line program.

Usually the NAME argument will be just MAIN. This name will be bound
to a function which will process arguments and execute the BODY.

ARGS should contain an arguments definition. Each definition is a list of the form:

(NAME DESCRIPTION &KEY FLAG ENV-VAR SHORT DEFAULT)

Argument’s NAME should be a symbol. It names a variable which will be bound during the BODY execution. Also, this name is lowercased and used to form a ‘–long‘ command line argument.

The lowercased first letter of the NAME is used as a short version of the argument, like ‘-l‘. But sometimes you might encounter duplication errors when having
a few arguments starting from the same letter. In this case provide SHORT option, to override the letter, used for the short option.

For example, here we have a conflict:

“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output"))
...)
“‘

But we can tell DEFMAIN to use ‘-V‘ option for verbose, instead of ‘-v‘

“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short "V")) ...)
“‘

Also, we can pass NIL, to turn off short version for VERBOSE argument:

“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short NIL)) ...)
“‘

If some of your options are boolean, then give it a ‘:FLAG t‘ option,
and a variable will become ‘T‘ if user provided this flag on the command-line.

Also, you might want to specify a DEFAULT value for the argument or provide
an environment variable name using ENV-VAR. The value will be take from the environment variable unless it was provided by the user on the command-line.

Arguments list of DEFMAIN macro might end with ‘&REST SOME-VAR‘. In this case, all unprocessed command line arguments will be collected into the SOME-VAR list.

By default program name, shown in the ‘–help‘, will be the same as the name
of the function or taken as a third part of the ROS.SCRIPT.THIRD-PART package name, if you are using Roswell. However, you can override it providing the PROGRAM-NAME argument.

Package

defmain

Source

file-type.lisp (file)


Previous: , Up: Exported definitions   [Contents][Index]

5.1.3 Functions

Function: get-subcommand-name ()

Returns a string with current subcommand’s name.

It should be called from the function defined with DEFMAIN macro.

Package

defmain

Source

file-type.lisp (file)

Function: print-commands-help ()

Outputs information about supported subcommands.

It should be called from the function defined with DEFMAIN macro.

Package

defmain

Source

file-type.lisp (file)

Function: print-help ()

Outputs to stdout a help about command line utility.

Package

defmain

Source

file-type.lisp (file)

Function: subcommand ()

Executes the current subcommand. It is called automatically at the end of the main body unless you call it manually.

It can be called from the function defined with DEFMAIN macro.

Package

defmain

Source

file-type.lisp (file)


Previous: , Up: Definitions   [Contents][Index]

5.2 Internal definitions


Next: , Previous: , Up: Internal definitions   [Contents][Index]

5.2.1 Functions

Function: %call-command PARENT PARENT-ARGUMENTS COMMAND-AND-ARGS
Package

defmain

Source

file-type.lisp (file)

Function: %is-need-to-catch-errors ARGS

Checks if option :catch-errors t was given to the defmacro. If not given, then it is True by default.

Package

defmain

Source

file-type.lisp (file)

Function: %print-commands-help MAIN-SYMBOL &key STREAM

Outputs to stdout a help about command line utility.

Package

defmain

Source

file-type.lisp (file)

Function: add-help-fields ARGS
Package

defmain

Source

file-type.lisp (file)

Function: extract-parent-args ARGS

Searches in the list of macro arguments a sequence like:

&parent-args (foo bar)

and returns (foo bar).

Package

defmain

Source

file-type.lisp (file)

Function: get-positional-args DEFMAIN-ARGS
Package

defmain

Source

file-type.lisp (file)

Function: get-program-name SYMBOL
Package

defmain

Source

file-type.lisp (file)

Function: get-rest-arg LIST

Takes a lambda list and returns a symbol, naming &rest argument, or nil.

Package

defmain

Source

file-type.lisp (file)

Function: get-short-description COMMAND-SYMBOL
Package

defmain

Source

file-type.lisp (file)

Function: get-value-if-symbol VALUE

If value is a bound symbol, then returns its bound value. For all other cases just returns a value itself.

Package

defmain

Source

file-type.lisp (file)

Function: is-has-subcommand ARGS

Returns t if there is &subcommand symbol in the list.

Package

defmain

Source

file-type.lisp (file)

Function: make-binding NAME &rest ARGS
Package

defmain

Source

file-type.lisp (file)

Function: make-bindings DEFMAIN-ARGS

Returns a list of forms for "let" form.
Variable args contains a list of arguments given to defmain, like:

((debug :documentation "Show traceback instead of short message.") (log :documentation "Filename to write log to.")
&rest repository)

For this input, output will be a list like:

((debug (net.didierverna.clon:getopt :long-name "debug"))
(log (net.didierverna.clon:getopt :long-name "log")))

Package

defmain

Source

file-type.lisp (file)

Function: make-field-description NAME DOCUMENTATION &key ENV-VAR FLAG SHORT DEFAULT

Returns a single fields description. Name argument is a symbol. Function returns a list.

Package

defmain

Source

file-type.lisp (file)

Function: make-long-name SYMBOL
Package

defmain

Source

file-type.lisp (file)

Function: make-positional-bindings DEFMAIN-ARGS

Returns a list of forms for "let" form.
It is like make-bindings, but only returns bindings for positional arguments. The should be separate because applied after the –help option was checked.

Package

defmain

Source

file-type.lisp (file)

Function: make-postfix-string POSITIONAL-ARGS REST-ARG
Package

defmain

Source

file-type.lisp (file)

Function: make-short-name SYMBOL
Package

defmain

Source

file-type.lisp (file)

Function: make-synopsis-args DEFMAIN-ARGS

Checks if there is &rest or &subcommand part in defmain’s args and outputs it either as

(:postfix "REPOSITORY") list

or as

(:postfix "SUBCOMMAND") list.

Package

defmain

Source

file-type.lisp (file)

Function: make-synopsis-fields DEFMAIN-ARGS

Returns fields description for net.didierverna.clon:defsynopsis.

Package

defmain

Source

file-type.lisp (file)

Function: map-fields FUNCTION DEFMAIN-ARGS

Maps given function to all given args. Args should be in the format of defmain arguments.

Returns a list of results from each function call.

Package

defmain

Source

file-type.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

5.2.2 Generic functions

Generic Function: get-argument-name CONDITION
Package

defmain

Methods
Method: get-argument-name (CONDITION argument-is-required-error)
Source

file-type.lisp (file)

Generic Function: get-command OBJECT
Package

defmain

Methods
Method: get-command (COOL-SYNOPSIS cool-synopsis)

A symbol of a function created by defmain macro. Used to extract information about the name of the current command and a name of subcommands.

Source

file-type.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

5.2.3 Conditions

Condition: argument-is-required-error ()
Package

defmain

Source

file-type.lisp (file)

Direct superclasses

error (condition)

Direct methods

get-argument-name (method)

Direct slots
Slot: argument-name
Initargs

:name

Readers

get-argument-name (generic function)


Previous: , Up: Internal definitions   [Contents][Index]

5.2.4 Classes

Class: cool-synopsis ()
Package

defmain

Source

file-type.lisp (file)

Direct superclasses

synopsis (class)

Direct methods
Direct slots
Slot: command

A symbol of a function created by defmain macro. Used to extract information about the name of the current command and a name of subcommands.

Initargs

:command

Readers

get-command (generic function)


Previous: , Up: Top   [Contents][Index]

Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts

Jump to:   D   F   L  
Index Entry  Section

D
defmain.asd: The defmain․asd file
defmain/defmain/file-type.lisp: The defmain/defmain/file-type․lisp file

F
File, Lisp, defmain.asd: The defmain․asd file
File, Lisp, defmain/defmain/file-type.lisp: The defmain/defmain/file-type․lisp file

L
Lisp File, defmain.asd: The defmain․asd file
Lisp File, defmain/defmain/file-type.lisp: The defmain/defmain/file-type․lisp file

Jump to:   D   F   L  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   %  
A   D   E   F   G   I   M   P   S  
Index Entry  Section

%
%call-command: Internal functions
%is-need-to-catch-errors: Internal functions
%print-commands-help: Internal functions

A
add-help-fields: Internal functions

D
defcommand: Exported macros
defmain: Exported macros

E
extract-parent-args: Internal functions

F
Function, %call-command: Internal functions
Function, %is-need-to-catch-errors: Internal functions
Function, %print-commands-help: Internal functions
Function, add-help-fields: Internal functions
Function, extract-parent-args: Internal functions
Function, get-positional-args: Internal functions
Function, get-program-name: Internal functions
Function, get-rest-arg: Internal functions
Function, get-short-description: Internal functions
Function, get-subcommand-name: Exported functions
Function, get-value-if-symbol: Internal functions
Function, is-has-subcommand: Internal functions
Function, make-binding: Internal functions
Function, make-bindings: Internal functions
Function, make-field-description: Internal functions
Function, make-long-name: Internal functions
Function, make-positional-bindings: Internal functions
Function, make-postfix-string: Internal functions
Function, make-short-name: Internal functions
Function, make-synopsis-args: Internal functions
Function, make-synopsis-fields: Internal functions
Function, map-fields: Internal functions
Function, print-commands-help: Exported functions
Function, print-help: Exported functions
Function, subcommand: Exported functions

G
Generic Function, get-argument-name: Internal generic functions
Generic Function, get-command: Internal generic functions
get-argument-name: Internal generic functions
get-argument-name: Internal generic functions
get-command: Internal generic functions
get-command: Internal generic functions
get-positional-args: Internal functions
get-program-name: Internal functions
get-rest-arg: Internal functions
get-short-description: Internal functions
get-subcommand-name: Exported functions
get-value-if-symbol: Internal functions

I
is-has-subcommand: Internal functions

M
Macro, defcommand: Exported macros
Macro, defmain: Exported macros
make-binding: Internal functions
make-bindings: Internal functions
make-field-description: Internal functions
make-long-name: Internal functions
make-positional-bindings: Internal functions
make-postfix-string: Internal functions
make-short-name: Internal functions
make-synopsis-args: Internal functions
make-synopsis-fields: Internal functions
map-fields: Internal functions
Method, get-argument-name: Internal generic functions
Method, get-command: Internal generic functions

P
print-commands-help: Exported functions
print-help: Exported functions

S
subcommand: Exported functions

Jump to:   %  
A   D   E   F   G   I   M   P   S  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.3 Variables

Jump to:   @  
A   C   S  
Index Entry  Section

@
@helpers: Exported special variables
@index: Exported special variables
@installation: Exported special variables
@reasoning: Exported special variables
@roadmap: Exported special variables
@subcommands: Exported special variables
@usage: Exported special variables

A
argument-name: Internal conditions

C
command: Internal classes

S
Slot, argument-name: Internal conditions
Slot, command: Internal classes
Special Variable, @helpers: Exported special variables
Special Variable, @index: Exported special variables
Special Variable, @installation: Exported special variables
Special Variable, @reasoning: Exported special variables
Special Variable, @roadmap: Exported special variables
Special Variable, @subcommands: Exported special variables
Special Variable, @usage: Exported special variables

Jump to:   @  
A   C   S  

Previous: , Up: Indexes   [Contents][Index]

A.4 Data types

Jump to:   A   C   D   P   S  
Index Entry  Section

A
argument-is-required-error: Internal conditions

C
Class, cool-synopsis: Internal classes
Condition, argument-is-required-error: Internal conditions
cool-synopsis: Internal classes

D
defmain: The defmain system
defmain: The defmain package
defmain/defmain: The defmain/defmain system

P
Package, defmain: The defmain package

S
System, defmain: The defmain system
System, defmain/defmain: The defmain/defmain system

Jump to:   A   C   D   P   S