peace 0.0.15

zero stress automation
Documentation
# Presentation

For human readable output, it is desirable for consumers as well as the framework to be able to:

* Output arbitrary types.
* Have them formatted by the output implementation.
* Not require the output implementation to know the specific type that is being output.

The `OutputWrite` trait was written to handle different output formats – human-readable vs CI logging vs structured text – but not how to *present* the output.

Peace should provide two traits:

* `OutputWrite`: Maps between the information and the output format, e.g. human readable vs parseable.

    Examples:

    - **CLI output:** Writes progress as log messages (CI), or progress bar (interactive), or nothing (when piped).
    - **Web output:** Write JSON.
    - **Native application:** Update a UI component.

* `Presentable`: Maps between the information and the presentation format, e.g. present this as an ID, short text, long text, a list, etcetera.

    Examples:

    - **CLI output:** Colour text with ANSI colour codes.
    - **Web output:** Create and style web elements.
    - **Native application:** Create and style UI components.


## Current State

The `OutputWrite` trait has methods for:

* writing progress: setting up state, updating progress, and ending.
* writing states (current, goal, diff, etc.)
* writing error

These methods are specific to `State`s, and if we add methods per type, it doesn't allow any arbitrary type to be formatted and written.


## Goal State

To be usable with arbitrary information, `OutputWrite` should have methods to output different *kinds* of information. These information *kinds* are based on the purpose of the information, not on how they should be grouped or presented.


### Information Kinds

* **Progress:** Information about the execution of automation.
* **Outcome:** Information that the automation is purposed to produce.
* **Notes:** Meta information about the outcome or progress -- informatives, warnings.

    These can be used to refine the automation.

For each information kind, `OutputWrite` should be able to:

* Write one or many of that information kind
* Reason over the parameters of that information, and potentially pass it to a formatter.

For structured output, all information should be serializable.


### Presentation / Formatting

For human readable output to be *understandable*, the `OutputWrite` implementation should improve clarity by adding styling or reducing information overload. For this to work with arbitrary types, the `OutputWrite` needs additional hints to determine how to format the information.

Examples:

* An object may be presented as a list, and the type needs to define which fields that list is built from.
* When presenting a list of named items, the type needs to define both the name and the description, which allows the names to be styled differently to the descriptions.
* When presenting a large object, the density of information can be reduced through collapsible sections, and more detail displayed when the sections are expanded.


#### Implementation

To achieve this, we can:

* Define a `peace::fmt::Presentable` trait, analogous to `std::fmt::Display`
* Define a `peace::fmt::Presenter` trait, analogous to `std::fmt::Formatter`
* `Presenter` has methods to format:

    - short text descriptions
    - long text descriptions (e.g. always split at `\n`s)
    - names, e.g. always bold
    - lists of `Presentable`s
    - groups, e.g. always collapsible, or presenter may choose to not display if level of detail is too high

* Implementors will `impl Presentable for MyType`. This can be made easier with a derive macro.
* Update `OutputWrite` to take in `&dyn Presentable` instead of concrete types, and the `OutputWrite` implementation can decide whether or not to delegate to `Presenter` for presentation information. e.g. a serializing output write may not need to.

**Note:** Structured output that is read by humans (e.g. prettified YAML or JSON) is not a `peace::fmt::Presentable` concern, but an `OutputWrite` parameter, as it is a standard format serialization parameter, not formatting hints that the output endpoint needs.


Instead of using `&str`s for what is presented, we could add type safety to:

* Enforce certain constraints, e.g. short descriptions must be one line, less than 200 characters
* For human readable output, instead of `std::fmt::Display`, types implement `peace::fmt::Presentable` trait where a `peace::fmt::Presenter` is passed in.

The type safety can be opt-in, e.g. allow `&str`s, but if using the type-safe wrappers, you get compilation errors when the constraints are not met.


#### Recursion

If the `Presentable` trait is recursive like `Debug`, then we need to make sure implementors understand that a "name" will always be styled as a name, unless one creates a wrapping type that does not delegate to the name's underlying `Presentable` implementation (just like `Debug`).