Scriber.Console (Scriber v0.1.2)

Copy Markdown View Source

The maintenance console: a shell-like prompt over one stratum's directory, in Elixir.

No shell is spawned and no pseudoterminal is opened. Every command is implemented here, against the files Scriber.Lattice.prepare/2 wrote.

Commands

ls [path]              list a directory, marking subdirectories with /
cat <file>...          print files
grep <text> <file>...  print lines containing text
probe <target>         manifest, seal, all; gate (the code fragments in hand); stratum
unseal <code>          test a code against the seal
forge [thing]          list what shards buy, or buy one
forge sell <weapon>    sell a weapon back for half
clear                  empty the transcript
help                   list these commands

Paths are resolved relative to the console's :cwd and are not sandboxed to it. probe gate is accepted but does not report the gate's state; that is read by walking into the gate in the game.

State

The console owns :input (the prompt buffer) and :lines (the transcript, newest first, capped). submit/3 is the whole interface — a line in, an updated console and game out. unseal writes a marker file through Scriber.Lattice.unseal/2; forge changes the game and touches no file, and records the transaction as an action in :pending, which take_pending/1 hands over for the world that holds the game to apply.

Example

console = Scriber.Console.new(Scriber.Lattice.stratum_dir(seed, 1), 1)
{console, game} = Scriber.Console.submit(%{console | input: "probe seal"}, game, seed: seed)

Summary

Functions

Remove the last character from the prompt buffer. A no-op on an empty prompt.

A console rooted at cwd, labelled for stratum stratum, with its banner already in the transcript.

Run whatever is in the prompt buffer, returning {console, game}.

The forge actions run since the last call, oldest first, and the console with none pending; a world takes them as input.

Everything printed so far as {text, tone} pairs, oldest first.

Append char to the prompt buffer. Appends whatever it is given, unvalidated.

Types

t()

@type t() :: %Scriber.Console{
  cwd: Path.t(),
  input: String.t(),
  lines: [{String.t(), atom()}],
  pending: [atom()],
  stratum: pos_integer()
}

Functions

backspace(console)

@spec backspace(t()) :: t()

Remove the last character from the prompt buffer. A no-op on an empty prompt.

new(cwd, stratum)

@spec new(Path.t(), pos_integer()) :: t()

A console rooted at cwd, labelled for stratum stratum, with its banner already in the transcript.

cwd should be the directory Scriber.Lattice.prepare/2 returned. stratum is the depth the console belongs to and is the depth unseal acts on, so it must match cwd.

submit(console, game, opts \\ [])

@spec submit(t(), Scriber.Game.t(), keyword()) :: {t(), Scriber.Game.t()}

Run whatever is in the prompt buffer, returning {console, game}.

The line is trimmed, echoed to the transcript, and split on whitespace. An empty line is echoed and nothing else runs. An unrecognised command prints an error rather than raising, as does any command whose files cannot be read.

The returned console always has an empty :input. game is returned changed only by forge; every other command returns it untouched.

Options

  • :seed — the run's seed. Required by unseal, which raises KeyError without it. Other commands ignore it.

take_pending(console)

@spec take_pending(t()) :: {[atom()], t()}

The forge actions run since the last call, oldest first, and the console with none pending; a world takes them as input.

transcript(console)

@spec transcript(t()) :: [{String.t(), atom()}]

Everything printed so far as {text, tone} pairs, oldest first.

Tones are :system, :prompt, :good, :bad, :dim and :plain, for the caller to colour. The transcript is capped, so the oldest lines of a long session are absent.

type(console, char)

@spec type(t(), String.t()) :: t()

Append char to the prompt buffer. Appends whatever it is given, unvalidated.