Expresso.CommandLine (expresso v0.1.0)

Copy Markdown View Source

Reads and runs the command line of mix expresso and of the binary

The two commands take the same arguments:

<input> [output] [--watch [--port <port>] | --check[=<level>] [--size <size>]...]
        [--help | -h] [--version] [--install-check-tools]

parse/1 reads the arguments, and run/3 runs them. The mix task and the binary both call run/3, so the two commands agree.

Summary

Functions

Read the arguments of a command line

Run a command line, and return its exit status

Return the usage text of a command with the name program

Return the text for --version: the name and the version of Expresso

Functions

parse(args)

@spec parse([String.t()]) ::
  :help
  | :version
  | :install_check_tools
  | {:paths, String.t() | nil, String.t() | nil}
  | {:watch, String.t(), String.t() | nil, :inet.port_number()}
  | {:check, Expresso.Check.level(), String.t(), String.t() | nil,
     [Expresso.Check.size()]}
  | {:error, String.t()}

Read the arguments of a command line

The function returns the first of these results that applies:

  • :help for --help or -h in any position.
  • :version for --version in any position.
  • :install_check_tools for --install-check-tools alone. With another argument, the option is an error.
  • {:error, message} for an unknown option, a third path, a bad --port or a bad level of --check. Each argument that starts with - is an option, except - alone. --port without --watch is an error too, and so is --check with --watch. An output path that names the input file is an error in each mode, because the HTML would replace the deck. A link to the input file is such a path too.
  • {:check, level, input, output, sizes} for --check. The level is :basic for --check, :layout for --check=layout, :a11y for --check=a11y and :browser for --check=browser. The check needs an input, and it writes its report to the standard output, so - is an error for the output. sizes holds a tuple {width, height} for each --size 1280x720 or --size=1280x720, in sequence, and it is [] without the option. --size needs a browser level.
  • {:watch, input, output, port} for --watch. The port comes from --port 4200 or --port=4200, and it is 4100 without that option. The watch mode needs an input file, and it does not write to the standard output, so - is an error for either path.
  • {:paths, input, output} otherwise. A missing path is nil, and - gives the standard input or the standard output.

A path that starts with - needs a directory in front of it, such as ./-deck.exs.

iex> Expresso.CommandLine.parse(["deck.exs", "deck.html"])
{:paths, "deck.exs", "deck.html"}

iex> Expresso.CommandLine.parse(["deck.exs", "--watch"])
{:watch, "deck.exs", nil, 4100}

iex> Expresso.CommandLine.parse(["deck.exs", "deck.html", "--watch", "--port", "4200"])
{:watch, "deck.exs", "deck.html", 4200}

iex> Expresso.CommandLine.parse(["deck.exs", "--check=layout"])
{:check, :layout, "deck.exs", nil, []}

iex> Expresso.CommandLine.parse(["deck.exs", "--check=layout", "--size", "1280x720"])
{:check, :layout, "deck.exs", nil, [{1280, 720}]}

iex> Expresso.CommandLine.parse(["deck.exs", "-h"])
:help

iex> Expresso.CommandLine.parse(["--version"])
:version

iex> Expresso.CommandLine.parse(["--install-check-tools"])
:install_check_tools

iex> Expresso.CommandLine.parse(["--verbose"])
{:error, "Unknown option: --verbose"}

iex> Expresso.CommandLine.parse(["deck.exs", "deck.html", "notes.html"])
{:error, "Unexpected argument: notes.html"}

run(args, program, help)

@spec run([String.t()], String.t(), String.t()) :: 0 | 1

Run a command line, and return its exit status

Mix.Tasks.Expresso and Expresso.BurritoEntryPoint both call this function. program is the name of the command in the usage text, and help is the text for --help. For each result of parse/1:

  • :help writes help to the standard output. The exit status is 0.
  • :version writes the version to the standard output. The exit status is 0.
  • :install_check_tools calls Expresso.Check.Tools.install/2. The exit status is 1 for an error, and 0 otherwise.
  • {:error, message} writes the message and the usage text to the standard error. The exit status is 1.
  • {:paths, nil, _} writes the usage text to the standard error. The exit status is 1.
  • {:paths, input, output} calls Expresso.main/2, which writes each error message. The exit status is 1 for an error, and 0 otherwise. A standard output that closed, as for | head, is not an error.
  • {:watch, input, output, port} calls Expresso.Watch.run/3. That function returns only for an error, so the exit status is 1.
  • {:check, level, input, output, sizes} calls Expresso.Check.run/4. The exit status is 1 for a problem or an error, and 0 otherwise.

The function does not catch an exception from the deck. The binary catches it and writes the message, and Mix writes it for the mix task.

usage(program)

@spec usage(String.t()) :: String.t()

Return the usage text of a command with the name program

iex> Expresso.CommandLine.usage("mix expresso")
"Usage: mix expresso <input> [output]"

version()

@spec version() :: String.t()

Return the text for --version: the name and the version of Expresso