terminal is where Shoddy's raw console words are written down:
Print to put a line on the screen, Input and
InputLine to read one back, InKey to catch a single
keystroke without waiting, and Args to see how the program was
started. This machine declares no words of its own. All five
are builtins — the engine dispatches them, running each itself. They are
callable from any program with no Include at all, and including
this file gives you nothing you did not already have. The page exists so that
a reader who goes looking for "how does a Shoddy program read a keystroke?"
finds the answer in a machine named for the question. Otherwise the reader
would need to already know that
the flat word reference exists.
Print is called Print because it printed. The
console the early timesharing systems (computers many people shared at once)
and the first BASICs talked to was a Teletype — typically the
Model 33, a typewriter-telegraph hybrid
hammering ten characters a second onto a roll of paper. The
programs of that era were shaped by it. Output came a line at a time,
because a line was what the carriage could do. Input came a line at a
time, because nothing existed until the operator pressed Return. The paper
gave way to glass and the glass to windows, but the contract never changed.
That is why it is still called a tty (short for teletype) in every
operating system, why lines remain the unit of console conversation, and why
the five words on this page are all a console program truly needs. Only
InKey is a child of the later, faster hardware: a single
keystroke, caught without waiting, is a thing a glass terminal can offer
and a ten-character-a-second printer never could.
Every builtin in the language lives in exactly two places that a reader can reach: section 10 of the spec, which is one long list grouped by rough category, and the compiler's own effects table, which is C#. Neither is reachable from the thing you were actually thinking about. If you want to know how to read a key, you do not think "I should consult the flat reference" — you think "keyboard", and you go looking for a machine. Most of the library answers that instinct, because the builtins a domain is built on are documented in the machine that owns the domain. The console words had no such machine, so they had nowhere to be found. This is that machine.
Nothing here is new and nothing here is a wrapper. If you want convenience
verbs on top of these — a prompt-and-validate loop, a menu reader — those
would be ordinary Defs and would belong in a program or a machine
that declares them. What is documented below is exactly what the runtime
gives you, described where you would go looking for it.
You need no Include for any of this. The words below are
already in scope in every Shoddy program.
Def Main()
Print("What is your name?")
Let who = Input("> ")
Print("Hello, " & who)
' a non-blocking poll, the shape a game loop wants
Let k = InKey()
If k <> "" Then
Print("you pressed something")
A few things worth remembering:
Print always adds a newline. There is no
write-without-newline builtin, so a line assembled out of several pieces is
built up with & and printed once. That matters most with
vt100's escape strings — the invisible character
bursts that move a cursor or set a colour: several stray line feeds in
the middle of a control sequence are harmless on most terminals, but they are
not guaranteed to be, so
Print(CursorPos(1, 1) & ClearEos() & Bold() & "HELLO")
is the shape to write.Input cannot tell end of stream from a blank
line. Both come back as "". A program reading a
redirected script can therefore reprompt on a blank line, or stop at EOF, but
not both — which is the whole reason InputLine exists. It answers
a two-element Array [atEof, text] and separates them.InKey never blocks and never echoes. It
answers "" when nothing is pending, which is what makes it usable
inside a frame loop. The arrow keys and PF1–PF4 arrive as their VT100
application-mode escape sequences, so EvalKey(InKey()) — with
vt100's decoder — is a working keyboard poll. See
pac-vt100.Main's side of a
program.One distinction is worth getting straight, because it decides which of two
machines you want. terminal is the raw console:
putting characters out, taking characters in. vt100
is the protocol spoken over it: the escape sequences that
move a cursor or set a colour, and the decoder that turns a raw arrow-key
sequence into a named key. Reading a keystroke is not a VT100 idea —
InKey is the same word on a terminal that has never heard of DEC.
Interpreting what comes back is entirely a VT100 idea. So the raw words are
here, EvalKey stays there, and neither machine includes the
other.
The four console words the runtime dispatches, plus
Args
None of these is a Def. The engine dispatches them —
runs them itself — and a
Def whose name is a builtin is refused. The same five are
documented word for word in machines/terminal.shoddy's own header
block. Stack effects — what each word takes and leaves — are the
ones the compiler's Effects.cs table declares.
| Word | Description |
|---|---|
| Print(s) | Write s to the screen, followed by a
newline. There is no write-without-newline builtin, so build a line up with
& and print it once. |
| Word | Description |
|---|---|
| Input(prompt) | Print the prompt, read one whole line, answer it
as a String. Numbers come back through Val — or better,
IsNumeric and then Val. End of stream and a blank
line both collapse to "". |
| InputLine(prompt) | The same read, answering a 2-element Array
[atEof, text]: element 1 a Boolean, True only at genuine end of
stream; element 2 the line, empty at EOF. It is a flat Array rather than a
record because a builtin cannot reach a Type — lifting it into a
sum type (a type with named alternative cases) is the caller's job, which is
what halifax does in
HxAskedOf. |
| InKey() | One pending keystroke, read without blocking and
without echo, or "" when none is pending. Arrow keys and PF1–PF4
arrive as their VT100 application-mode escape sequences, which is what
vt100's EvalKey decodes. |
| Word | Description |
|---|---|
| Args() | The arguments the program was started with, as a
List Of String. Also available in native hosts — not
terminal-exclusive. Unlike the four above, a console is not this
word's only home: a headless service or a program launched from a desktop has
arguments too, with no terminal involved anywhere. The spec classifies it as
core, and it is documented here because reading your own invocation is a
console-shaped thing to want. |
Nothing includes it, and nothing needs to. This machine declares no words,
so there is nothing to import; the five builtins it documents are in scope
everywhere already. The pages that lean on it are documentation rather than
code — vt100 points here for Print and
InKey rather than claiming them.
None, and it could not use one — a file that declares nothing has nothing to build. It includes no machine and no machine includes it.