# `Expresso.Element.Diagram.Tool`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/element/diagram/tool.ex#L1)

Finds and runs the tool that draws a graph, such as Graphviz, or Node for
the MathML of a formula

Expresso and the binary of Burrito do not hold the tools. The function
`find/3` looks for the program of a tool on the `PATH`, and a variable of
the environment, such as `EXPRESSO_DOT`, gives a different path. A tool that
is not present stops the render with a message that names the tool and the
way to install it.

`System.cmd/3` cannot keep the standard error apart from the standard
output. Therefore the tool writes the SVG to a file in a private directory,
and the standard error goes into the standard output. A tool that fails
stops the render with that output, which holds the message of the tool,
such as a syntax error and its line. A tool that succeeds can also write a
warning, such as a color that it does not know. The render does not show
that warning, so a test does not write to the standard error.

# `subject`

```elixir
@type subject() :: Path.t() | {:subject, String.t()}
```

The thing that a tool draws, for a message: the path of a diagram, or
`{:subject, text}` with the words of the message, such as
`{:subject, "the formulas of the deck"}`

# `t`

```elixir
@type t() :: %{
  name: String.t(),
  program: String.t(),
  variable: String.t(),
  install: String.t()
}
```

A tool: its name for the user, its program and its variable of the environment

# `find`

```elixir
@spec find(t(), subject(), %{required(String.t()) =&gt; String.t()}) ::
  {:ok, Path.t()} | {:error, String.t()}
```

Find the program of a tool

The variable of the tool in `env` gives the path of the program. Without
the variable, the function looks for the program on the `PATH`. `src` is
the path of the source or a subject, for the message.

# `identity`

```elixir
@spec identity(t(), subject()) :: {Path.t(), integer(), non_neg_integer()} | nil
```

The identity of the program of a tool, for the key of a cache

The identity is the path of the program and the time and the size of its
file, so a new version of the tool gives a new identity. The function
returns `nil` for a tool that is not present.

# `run!`

```elixir
@spec run!(
  t(),
  subject(),
  (Path.t() -&gt; {[String.t()], [{String.t(), String.t()}]}),
  [{String.t(), binary()}],
  String.t()
) :: String.t()
```

Run a tool, and return the SVG that it writes

`command` is a function that takes the private directory of the run and
returns the arguments of the program and its variables of the environment.
The tool writes its result to `output` in that directory, `graph.svg` by
default, and the function returns the text of that file. `files` go into the
directory before the run, such as the files of a font. The function raises an
`ArgumentError` for a tool that is not present and for a tool that fails.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
