# `Drafter.Session.Context`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/session/context.ex#L1)

Resolves the per-session services a process is operating on behalf of.

A Drafter session owns a compositor, an event manager, a screen manager and so
on. The association between a process and its session's instances is held in
the process dictionary, so it must be copied explicitly whenever work moves to
another process: use `capture/0` in the originating process and `adopt/1` in
the new one.

Resolution falls back to a globally registered process of the same name, so a
widget can be rendered outside any session.

A session also carries the environment of the terminal it is attached to, read
with `terminal_env/0`. For a session served over ssh or telnet that is the
connecting client's environment, which is not the environment of the host the
program runs on; `terminal_env/0` falls back to the host's when no session set
one.

# `role`

```elixir
@type role() ::
  :event_manager
  | :compositor
  | :theme_manager
  | :screen_manager
  | :event_handler
  | :skin_manager
```

# `adopt`

```elixir
@spec adopt(%{required(atom()) =&gt; pid()} | keyword()) :: :ok
```

Adopt a context captured by `capture/0`.

# `capture`

```elixir
@spec capture() :: %{required(atom()) =&gt; pid()}
```

Snapshot the calling process's context, for handing to another process.

# `cell_size`

```elixir
@spec cell_size() :: {pos_integer(), pos_integer()} | nil
```

The terminal's cell size as `{width, height}` in pixels, or `nil` when it has not
answered — because the app did not ask with `cell_size: true`, or the terminal does
not report it.

# `fetch!`

```elixir
@spec fetch!(role()) :: pid() | atom()
```

Like `get/1`, but raises with the role named rather than returning `nil`.

# `get`

```elixir
@spec get(role()) :: pid() | atom() | nil
```

The process serving `role` for the calling session.

Prefers the session's own instance, then a globally registered process of the
same name, and finally `nil`.

# `key_release?`

```elixir
@spec key_release?() :: boolean()
```

Whether this session's terminal reports key releases.

`true` only after the terminal has answered the query a `key_release: true` app
sends at startup; `false` before that, for an app that did not opt in, and for a
terminal that never answers.

# `keys`

```elixir
@spec keys() :: [atom()]
```

The process-dictionary keys a session context occupies.

# `put_cell_size`

```elixir
@spec put_cell_size({pos_integer(), pos_integer()}) :: :ok
```

Record the terminal's cell size in pixels, from its `{:cell_size, size}` report.

# `put_key_release`

```elixir
@spec put_key_release(boolean()) :: :ok
```

Record whether the terminal will report key releases.

The app loop calls this when `{:key_release_support, supported?}` arrives, before
handing the event to the app.

# `put_terminal_env`

```elixir
@spec put_terminal_env(%{required(String.t()) =&gt; String.t()}) :: :ok
```

Record the environment of the terminal this session is attached to.

`env` is a map of environment variable name to string value, as
`System.get_env/0` returns. Carried to other processes by `capture/0` and
`adopt/1` like any other part of the context.

# `put_terminal_protocol`

```elixir
@spec put_terminal_protocol(atom() | nil) :: :ok
```

Record the graphics protocol the terminal answered a probe with.

`protocol` is `:kitty`, `:iterm2` or `:sixel`, or `nil` for a terminal that
named none. Recording `nil` is not the same as recording nothing: a terminal
that was asked and answered with no graphics is settled, and
`terminal_protocol/0` reports `{:ok, nil}` for it, where a terminal that was
never asked reports `:unprobed`.

# `roles`

```elixir
@spec roles() :: [role()]
```

Every role a session context carries.

# `terminal_env`

```elixir
@spec terminal_env() :: %{required(String.t()) =&gt; String.t()}
```

The environment of the terminal this session is attached to.

The session's own environment when one was recorded with `put_terminal_env/1`,
and the host process's environment otherwise. A session that recorded an empty
map gets that empty map, not the host's environment.

# `terminal_protocol`

```elixir
@spec terminal_protocol() :: {:ok, atom() | nil} | :unprobed
```

The probed graphics protocol, or `:unprobed` when the terminal was never asked.

A caller that gets `:unprobed` should fall back to detecting from
`terminal_env/0`.

---

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