# `Expresso.Element.Code`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/element/code.ex#L1)

An element that shows source code

The `code` entity takes the name of the language as its optional first
argument. The `text` option holds the source, or the `src` option gives the
path of a file that holds it. `Expresso.Highlight` makes the markup of each
line at render time, and it names the languages.

The `src` option takes a path that is relative to the working directory of
the command or to the `root` option of the deck, as for an image. The `lines` option takes a range of the lines
of the file, such as `3086..3095`, and the element then shows only those
lines. It can also take a start text and an end text, such as
`[from: "def start(", to: "
  end"]`. The excerpt then starts at the line
of the start text and ends at the line of the end text, so a change above
the excerpt does not move it. `to: :block` in place of an end text ends
the excerpt at the end of the block that the start line opens. `build/1` reads the file through
`Expresso.DeckFile`, so the watch
mode renders the deck again after a change to the file. The element takes
`text` or `src`, and not both.

Each line has a number. The first line of the text is line 1. With `src`,
the number of a line is its number in the file, so the first line of
`lines: 3086..3095` is line 3086. The `line_numbers` option shows the
number in front of each line.

The `reveal` option shows the lines in groups, one group at each step. It
takes a list of line numbers and of ranges, such as `[1..3, 4..8, 10]`.
`build/1` makes one `Expresso.Element.Lines` child for each item, with the
specification `[from: :next]`, and the transformer then gives each group
its steps as it does for the items of a list. A line that is in no group
shows at each step. A hidden line keeps its space, so the block does not
move when a group shows. A line number that the element does not show gives
an error, because such a group shows nothing.

A group of `reveal` or `highlight` can also be texts, such as
`[from: "let hit", to: "return hit;"]`, in the form of the `lines` option.
The group then runs from the line of the start text to the line of the end
text, inside the text of the element. A group with only `from` is the line
of the start text. A group with `to: :block` runs to the end of the block
that the start line opens, as `block_end/2` finds it. The `relative` option counts the numbers of the groups
from the first line of the element, so 1 is the first line of an excerpt.
`resolve/2` turns each group into line numbers before the other checks.

The `dim` option gives each group the state `dim` from the first step of a
later group. A line that is in no group does not dim. `docs/overlays.md`
gives the rules.

The `highlight` option takes groups of lines in the same form as `reveal`.
Each line shows at each step, and each group is in focus at its own step:
the lines of the group get the state `highlight`, and each other line gets
the state `dim`. `build/1` gives each group an `on` entity with `:next`, so
the transformer gives the groups one step each from the counter of the
slide. Each line in no group goes into one more group with no `on` entity.
`spotlight/1` then gives each group the state `dim` at the steps of the
other groups, before the render.

A group of `highlight` can also be `[each: "count"]`, each token of the
highlighter with the text `count`. Its `Expresso.Element.Lines` child has
`each` and no line numbers. At the step of the group, each line dims, and
the tokens with the text show in full color with a bar under them. A token
group does not dim at the steps of the other groups, because its tokens
dim with their lines. `reveal` takes no such group, because a hidden token
leaves a hole in its line.

The `whole_first` option gives the code element one step before its first
group, as a `pause` in front of it does. At that step, no group is in focus,
so the whole code shows in full color. `Expresso.Overlay.Expand` reads the
option with `lead/1`.

# `t`

```elixir
@type t() :: %Expresso.Element.Code{
  __spark_metadata__: term(),
  at: term(),
  class: term(),
  dim: term(),
  easing: term(),
  effect: term(),
  el: term(),
  elements: term(),
  first: term(),
  highlight: term(),
  lang: term(),
  line_numbers: term(),
  lines: term(),
  morph: term(),
  on: term(),
  relative: term(),
  reveal: term(),
  signature: term(),
  speed: term(),
  src: term(),
  steps: term(),
  text: term(),
  trailing_comments: term(),
  whole_first: term(),
  window: term(),
  window_title: term(),
  wrap: term()
}
```

The struct of a code element

# `block_end`

```elixir
@spec block_end(String.t(), non_neg_integer()) :: non_neg_integer()
```

Return the position of the first byte of the last line of the block that the line at a position opens

The block holds each later line with more indent than the start line, and
blank lines between them. The first later line with the same indent or
less ends the block. That line is the last line of the block when it
starts with `}`, `]`, `)` or `end`, as in most languages. Otherwise the
last line of the block is the last line with more indent, as in Python. A
start line with no line of more indent after it is a block of one line, so
the block does not take the closing line of a block around it.

    iex> code = "if (a) {\n  if (b) {\n    c();\n  }\n}\nd();\n"
    iex> Expresso.Element.Code.block_end(code, 0)
    33
    iex> Expresso.Element.Code.block_end(code, 9)
    29
    iex> Expresso.Element.Code.block_end("def f():\n    a\n\n    b\nc\n", 0)
    16
    iex> Expresso.Element.Code.block_end("a\nb\n", 0)
    0

# `build`

```elixir
@spec build(t()) :: {:ok, t()} | {:error, String.t()}
```

Read the source, and make the groups of lines from the `reveal` option

`check/1` calls this function for an element with `text`, and
`Expresso.PathTransformer` calls it for an element with `src`, after it
joins the path to the `root` option of the deck. With `src`, the function reads
the file, puts the lines of the `lines` option into `text`, and puts the
number of the first line into `first`. A `lines` option with `from` and
`to` gives its range from the text of the file. Then it puts one
`Expresso.Element.Lines` child into `elements` for each item of the
`reveal` option, in order.

The function gives an error for:

  * an element with both `text` and `src`, or with neither,
  * a `lines` option without `src`,
  * a file that it cannot read, or a range that goes past the end of the
    file,
  * a start text that is not in the file or that is in it more than one
    time, and an end text that is not in the file after the start text,
  * a line number of `reveal` that the element does not show. Such a group
    shows nothing, and it takes one step of the slide, so the deck gets a
    step at which nothing changes,
  * a `whole_first` option without `highlight`,
  * an element with both `reveal` and `highlight`, a `highlight` with `dim`,
    a line number of `highlight` that the element does not show, and a line
    that is in two groups of `highlight`.

# `check`

```elixir
@spec check(t()) :: {:ok, t()} | {:error, String.t()}
```

Check the options of a code element, and build an element with `text`

The transform of the `code` entity calls this function after it makes the
struct, in the DSL and in `Expresso.Builder`. An element with `src` keeps
its file until `Expresso.PathTransformer` runs, because the `root` option
of the deck can change the path. The function checks each option that needs
no file, so the error of such an option comes from the entity.

# `get_assigns`

```elixir
@spec get_assigns(t()) :: map()
```

Make the assigns of the render function from the struct

The key `overlay` holds the attributes of the overlay contract, from
`Expresso.Overlay.Render.attributes/1`. The key `lines` holds one triple
for each line: the number of the line, the HTML of the line and the overlay
attributes of its group. The key `numbers` holds the width of the widest
number in characters, or `nil` for an element without the `line_numbers`
option.

# `lead`

```elixir
@spec lead(t()) :: 0 | 1
```

Return the number of steps that a code element takes before its groups

The `whole_first` option gives one step, and the counter of the slide then
goes one further before the first group takes its step.

# `lines`

```elixir
@spec lines(term()) ::
  {:ok, Range.t() | keyword(String.t() | :block)} | {:error, String.t()}
```

Make sure that a `lines` option is a range of line numbers, or a start text and an end text

This function is the custom type of the option. A range starts at 1 or
more, and it has a step of 1. A keyword list has the key `from`, the key
`to` or both, one time each, and each value is a text that is not empty.
The value of `to` can also be `:block`.

    iex> Expresso.Element.Code.lines(10..24)
    {:ok, 10..24}

    iex> Expresso.Element.Code.lines(from: "def start(", to: "end")
    {:ok, [from: "def start(", to: "end"]}

    iex> Expresso.Element.Code.lines(from: "def start(", to: :block)
    {:ok, [from: "def start(", to: :block]}

# `render`

```elixir
@spec render(map()) :: Phoenix.HTML.safe()
```

Make the HTML of a code element

Each line goes into a `span` element with the class `line`, and the line
break is inside the fragment of the line. With the `line_numbers` option,
the number of the line goes into a `span` element with the class
`line-number` at the start of the line. A screen reader does not read the
number, and a copy of the text does not take it. The `code` element sets
`--line-number-width`, so each number takes the width of the widest one.

# `reveal`

```elixir
@spec reveal(term()) :: {:ok, [pos_integer() | Range.t()]} | {:error, String.t()}
```

Make sure that a `reveal` option is a list of line numbers, ranges and texts

This function is the custom type of the options `reveal` and `highlight`.
Each item is a positive integer, a range with a step of 1, or a keyword list
with `from` and an optional `to`, each a text that is not empty, or
`to: :block`. An item can also be `[each: text]`, a token group, and
`build/1` refuses it in `reveal`.

    iex> Expresso.Element.Code.reveal([1..2, [from: "let hit", to: "return hit;"], 7])
    {:ok, [1..2, [from: "let hit", to: "return hit;"], 7]}

# `spotlight`

```elixir
@spec spotlight(Expresso.Deck.t()) :: Expresso.Deck.t()
```

Dim the lines of each code element that are not in focus

A code element with the `highlight` option has one group of lines for each
item of the option, and one more group for the lines in no item. The
transformer gives each group of an item its step, in the `on` entity with
the state `highlight`. This function gives each other group of the element
an `on` entity with the state `dim` at that step. The other lines then dim,
and the group in focus shows in full.

`Expresso.Renderer` calls this function before `Expresso.Overlay.Render.identify/1`,
because a group needs an identity for its `on` entities.

---

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