The ffx
subtool interface has the concept of a Writer
that manages IO between
the tool and the user. This interface distinguishes between human and
machine users so that we can use our tools in other tooling more effectively.
We currently implement two kinds of writers:
SimpleWriter
: Errors if the program is run with--machine json
and can only output strings.MachineWriter
: adapts it output to match whether the--machine json
argument is passed, outputting only JSON on stdout if it is and outputting user-readable strings if not.
How to specify your Writer
type
In the legacy plugin interface you could add a writer
argument to your plugin
definition using an #[ffx(writer = OutputType)]
attribute on the writer
argument, and that would cause some generation of schema information from
the type you specified.
In this subtool interface, you specify this as an associated type on
the FfxMain
trait for your tool, and the machine type is a generic
argument to the MachineWriter
type. If your tool doesn't implement machine
output, it should use SimpleWriter
instead of something like
MachineWriter<String>
to avoid having people depend on your unstructured
output.
Using the Writer
For the most part, you can use the writer as you would any implementation of
std::io::Write
, and it's fine to just use writeln!()
or similar built-in
macros against it for any unstructured string output.
All writers also implement some convenience functions for basic writing needs
like print
and line
. These functions will all only produce output if the
command wasn't run in machine mode. Otherwise they will be ignored.
All writers also implement item
, which will either print the object
given in machine mode, or use its Display
implementation to output it in
non-machine mode as text.
If you're using a machine writer, you also get a few more methods to help with outputting structured output:
machine
: Only print the given object in machine mode.machine_many
: Print the given objects in machine mode.machine_or
: If in machine mode, print the object. Otherwise print the textual information in the other argument (implementingDisplay
).machine_or_else
: If in machine mode, print the object. Otherwise print the textual information resulting from the function in the other argument.