# `Expresso.Presenter.Interpreter`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/presenter/interpreter.ex#L1)

Runs the program of the presenter on a state

This module is the reference interpreter that
`docs/research/elixir-presenter-report.md` describes in its section "The
interpreter". Each function is pure: it takes a state and an event, and it
returns the next state. Thus the tests of the presenter behavior need no
browser.

`run/3` does the first three steps that the interpreter in the browser does:

  1. It finds the first mode whose condition the state matches.
  2. It finds the commands of the event in that mode.
  3. It applies the commands to the state, one after the other.

The result holds the new state and the built-in functions to call, such as
`:open_speaker`. `prevented?/3` tells if the browser must not use the event:
that is true when the state changes or a built-in function runs. A key that
changes nothing goes to the browser, so the arrow keys still scroll the pages
of the handout view.

A change of the step gives each field of the option `reset` of the
presenter its first value. Thus the key `d`, which turns off the dimming of
code, holds only for the step where the presenter pressed it.

The fragment of the address and the messages between the two windows do not
go through the modes. They go to a slide and a step of the deck directly.

# `event`

```elixir
@type event() ::
  {:key, String.t()}
  | {:click, :left_third | :right}
  | {:click, :left_third | :right, [term()] | nil}
  | {:swipe, :left | :right}
  | {:hash, String.t()}
  | {:message, %{slide: integer(), step: integer(), fields: map()}}
```

An event

A click can hold the commands of the element under it, such as a page of the
overview. A message holds the slide and the step of the other window, and
its fields of the option `sync`, such as the black screen. The script
already made sure of their types.

# `state`

```elixir
@type state() :: %{required(atom()) =&gt; term()}
```

The state of the presenter. `Expresso.Presenter.Definition` declares the fields.

# `transition`

```elixir
@type transition() :: %{kind: String.t(), direction: :forward | :back}
```

The kind and the direction of a transition

# `entry`

```elixir
@spec entry(Expresso.Presenter.Program.t(), state()) ::
  {pos_integer(), pos_integer()} | nil
```

Return the slide and the step of the current state, or nil for a deck with no slide

# `hash`

```elixir
@spec hash(Expresso.Presenter.Program.t(), state()) :: String.t()
```

Return the fragment of the address for a state, such as `#4.2`

For a deck with no slide, the function returns `#1.1`.

# `initial`

```elixir
@spec initial(Expresso.Presenter.Program.t(), map()) :: state()
```

Return the first state of a program, with some fields replaced

The script replaces the view for the speaker view, `progress` from the deck
and `every` from the address.

# `prevented?`

```elixir
@spec prevented?(state(), state(), [atom()]) :: boolean()
```

Tell if the browser must not use an event

The result is true when the state changed or the event called a built-in
function.

# `run`

```elixir
@spec run(Expresso.Presenter.Program.t(), state(), event()) :: {state(), [atom()]}
```

Apply one event to a state

Returns the new state and the built-in functions that the event calls, in
sequence.

# `transition`

```elixir
@spec transition(Expresso.Presenter.Program.t(), state(), state()) ::
  transition() | nil
```

Return the transition between two states, or nil

Only a move to a different slide in the present view has a transition. A
black screen, the overview, the menu and the list of keys cover the slide, so
a move from them or to them has no transition. In the two directions, the
kind comes from the slide with the higher number. The kind `"none"` has no
transition.

---

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