2023-04-16 Releasing Romulan 1.0.0 (first release) ═══════════════════════════════════════ I am hereby releasing the first version (1.0.0) of /Romulan/. The source is available on [Gitlab] and on [Github]. The primary site is, for the moment, Gitlab. /Romulan/ is a declarative interface for the Common Lisp command line parser /[clingon]/. /Romulan/ is currently /work in progress/. Defining an application with subcommands already works (see example below). For more planned development (= features that do not exist yet, but will some time in the future), see the section [Future development] in the [README]. [Gitlab] [Github] [clingon] [Future development] [README] Example ─────── As already mentioned above only subcommand interfaces (also called /git/ or /svn/ style) can currently be defined in /Romulan/. Those are interfaces where the command line looks like: ┌──── │ $ ./example-script-2 --user=Jim hello │ Hello, Jim! │ $ .//example-script-2 shout go for it │ GO FOR IT, rak1912! └──── The words /hello/ and /shout/ are called subcommands here. You will find the following /Romulan/ example in file [`example-script-2'] in the /Romulan/ source, a slightly larger example in [`example-script']. In /Romulan/ an interface with subcommands is declared with `commandline-subcommand-interface'. The declaration needs to contain at least a usage string (that is later used to construct help text) and the definition of global options: ┌──── │ (commandline-subcommand-interface romulan-test "shout some words or say hello" │ │ :usage "[-v] [-u ] [options ...]" │ :options (:user (:description "user to greet" │ :short-name #\u │ :env-vars ("USER")))) └──── Invoking the command without any options will display a help text that describes usage and global options from the definition above and lists the subcommands (all this courtesy of /clingon/, /Romulan/ just adds defaults and reformats the definitions in a slightly different format for /clingon/). ┌──── │ $ ./example-script-2 │ NAME: │ romulan-test - shout some words or say hello │ │ USAGE: │ romulan-test [-v] [-u ] [options ...] │ │ OPTIONS: │ --help display usage information and exit │ --version display version and exit │ -u, --user user to greet [env: $USER] │ │ COMMANDS: │ shout shouts back anything you write │ hello just says hello └──── Subcommands are defined with `define-subcommands' and look mostly like function definitions with additional arguments that specify usage, one-line help text and the subcommand options. ┌──── │ (define-subcommand hello (&key user) │ (:description "just says hello") │ │ (format t "Hello, ~A!~%" user)) │ │ (define-subcommand shout (words &key user) │ │ (:description "shouts back anything you write" │ :usage "[options ...] [arguments ...]" │ :varargs t) │ │ (format t "~{~A~^ ~}, ~A!~%" (mapcar #'string-upcase words) user)) └──── All subcommands are indeed procedures. The `&key' parameters of the lambda list correspond to options which will be automatically bound when invoking the subcommand. The positional parameters will be bound from the positional arguments of the POSIX argument vector. When all sub-commands are defined, `end-subcommand-interface' must be invoked. This actually builds the interfaces declared with `commandline-subcommand-interface'. ┌──── │ (end-subcommand-interface) └──── The command line interface thus defined is bound as a procedure to the symbol given to `commandline-subcommand-interface' and can be invoked as a procedure to process the command-line arguments and invoke the subcommands. ┌──── │ (romulan-test) └──── The subcommands are themselves procedures and can simply be called from Lisp (e.g. for testing) like any procedure: ┌──── │ (hello :user "Jim) │ Hello, Jim! └──── [`example-script-2'] [`example-script'] Comments ════════ Due to legal pitfalls in Europe there is no comment section in this blog at the moment (sorry), but you can discuss this article or comment on its content ⮕ [here on Mastodon]. [here on Mastodon]