.. _library_command_line_options:

``command_line_options``
========================

This library provides command-line parsing predicates where command-line
options are defined as objects that import the ``command_line_option``
category. Predicates are also provided for generating help text.

Parsed options are returned by default as a list of ``Name(Value)``
terms. A parser option, ``output_functor(Functor)``, allows returning
options as ``Functor(Key, Value)`` terms instead.

Adapted with significant changes from the SWI-Prolog ``optparse``
library by Marcus Uneson. Most documentation, parsing options, and help
options retained from the original library. Command line options
specification changed to an object-based representation. Parsing
simplified, no longer using DCGs. Comprehensive set of tests added,
based on documentation examples. Full portability to all supported
backends.

API documentation
-----------------

Open the
`../../apis/library_index.html#command_line_options <../../apis/library_index.html#command_line_options>`__
file in a web browser.

Loading
-------

To load all entities in this library, load the ``loader.lgt`` utility
file:

::

   | ?- logtalk_load(command_line_options(loader)).

Testing
-------

To test this library predicates, load the ``tester.lgt`` file:

::

   | ?- logtalk_load(command_line_options(tester)).

Terminology
-----------

The terminology is partly borrowed from Python (see
http://docs.python.org/library/optparse.html#terminology). *Arguments*
are what you provide on the command line and for many Prolog systems
show up as a list of atoms ``Args`` in
``current_prolog_flag(argv, Args)``. They can be divided into:

- *Runtime arguments*, which control the Prolog runtime; conventionally
  terminated by ``--``.
- *Options*, which are key-value pairs (with a boolean value possibly
  implicit) intended to control your program.
- *Positional arguments*, which are what remains after all runtime
  arguments and options have been removed (with implicit arguments
  ``true``/``false`` for booleans filled in).

Positional arguments are used for mandatory arguments without sensible
defaults (e.g., input file names). Options offer flexibility by letting
you change a default setting. This library has no notion of mandatory or
required options.

Defining option objects
-----------------------

Define command-line options by creating objects that import the
``command_line_option`` category. Each object represents one
command-line option and overrides the predicates to specify its
properties.

Create an object that imports ``command_line_option`` and override the
following predicates:

- ``key/1``: The key used to identify this option in the result. This
  predicate must be overridden.

- ``short_flags/1``: List of single-character short flags (e.g., ``[v]``
  for ``-v``). Default: ``[]``.

- ``long_flags/1``: List of long flags (e.g., ``[verbose]`` for
  ``--verbose``). Default: ``[]``.

- ``type/1``: Option value type. One of ``boolean``, ``atom``,
  ``integer``, ``float``, or ``term``. Default: ``term``.

- ``default/1``: Default value. Optional.

- ``meta/1``: Metasyntactic variable name for help text. Default:
  ``''``.

- ``help/1``: Help text (atom or list of atoms for pre-broken lines).
  Default: ``''``.

Validating option definitions
-----------------------------

Option objects provide two predicates for validating their definitions:

- ``check/0``: Validates the option definition, throwing an error if
  invalid. The validation checks:

  - The ``key/1`` predicate is defined (not just using the default).
  - All short flags are single characters.
  - The type is a known type (supported by the ``type`` library).
  - If a default value is defined and the type is not ``term``, the
    default value matches the declared type.

- ``valid/0``: Succeeds deterministically if the option definition is
  valid, fails otherwise. This is useful when you want to check validity
  without handling exceptions.

The ``parse/4-5`` and ``help/2-3`` predicates automatically call
``check/0`` on all option objects before processing, ensuring invalid
definitions are caught early with clear error messages.

Example:

::

   | ?- verbose_option::check.
   yes

   | ?- verbose_option::valid.
   yes

Example option objects
----------------------

::

   :- object(verbose_option,
       imports(command_line_option)).

       key(verbose).
       short_flags([v]).
       long_flags([verbosity]).
       type(integer).
       default(2).
       meta('V').
       help('verbosity level, 1 <= V <= 3').

   :- end_object.


   :- object(mode_option,
       imports(command_line_option)).

       key(mode).
       short_flags([m]).
       long_flags([mode]).
       type(atom).
       default('SCAN').
       help(['data gathering mode, one of',
             '  SCAN: do this',
             '  READ: do that',
             '  MAKE: fabricate numbers',
             '  WAIT: do nothing']).

   :- end_object.


   :- object(cache_option,
       imports(command_line_option)).

       key(cache).
       short_flags([r]).
       long_flags(['rebuild-cache']).
       type(boolean).
       default(true).
       help('rebuild cache in each iteration').

   :- end_object.


   :- object(outfile_option,
       imports(command_line_option)).

       key(outfile).
       short_flags([o]).
       long_flags(['output-file']).
       type(atom).
       meta('FILE').
       help('write output to FILE').

   :- end_object.


   % Configuration parameter without command-line flags
   :- object(path_option,
       imports(command_line_option)).

       key(path).
       default('/some/file/path/').

   :- end_object.

Parsing command-line arguments
------------------------------

Use the ``command_line_options`` object ``parse/4-5`` predicates:

::

   | ?- command_line_options::parse(
            [verbose_option, mode_option, cache_option, outfile_option],
            ['-v', '5', '-m', 'READ', '-ooutput.txt', 'input.txt'],
            Options,
            PositionalArguments
        ).

   Options = [verbose(5), mode('READ'), cache(true), outfile('output.txt')],
   PositionalArguments = ['input.txt'].

Generating help text
--------------------

Use the ``command_line_options::help/2`` predicate for default
formatting:

::

   | ?- command_line_options::help([verbose_option, mode_option, cache_option], Help).

Or use ``command_line_options::help/3`` with custom help options:

::

   | ?- command_line_options::help([verbose_option, mode_option], Help, [line_width(100)]).

Help options
------------

The ``help/3`` predicate supports the following help options:

- ``line_width(Width)``: Maximum line width for help text. Default:
  ``80``.

- ``min_help_width(Width)``: Minimum width for help text column.
  Default: ``40``.

- ``break_long_flags(Boolean)``: If ``true``, break long flags across
  multiple lines. Default: ``false``.

- ``suppress_empty_meta(Boolean)``: If ``true`` (default), suppress
  empty metasyntactic variables in help output.

Parse options
-------------

The ``parse/5`` predicate supports the following parse options:

- ``output_functor(Functor)``: When defined, options are returned as
  ``Functor(Key, Value)`` terms instead of ``Key(Value)`` terms. No
  default.

- ``duplicated_flags(Keep)``: How to handle duplicate options. One of
  ``keepfirst``, ``keeplast``, ``keepall``. Default: ``keeplast``.

- ``allow_empty_flag_spec(Boolean)``: If ``true`` (default), options
  without flags are allowed (useful for configuration parameters). Set
  to ``false`` to raise errors on empty flags.

Notes and tips
--------------

- The default type is ``term``, which subsumes ``integer``, ``float``,
  and ``atom``. However, always specifying types is recommended for
  reliable parsing and clear error messages.

- ``-sbar`` is taken as ``-s bar``, not as ``-s -b -a -r`` (no
  clustering).

- ``-s=foo`` is disallowed.

- Duplicate flags default to ``keeplast`` (controllable via the
  ``duplicated_flags`` parse option).

- Unknown flags (not in the specification) will raise errors.
