|
Making Console Applications: Prompts, Input Options, and Menus |
A console application talks to a person through the screen: it prints,
it asks, and it offers menus. The basics of asking are on
Asking the user for Information (INPUT) — this page is the reference for everything
around them: the three input statements, what a person may type at them,
every option they take, the menu system with its full set of % directives, fill-in screens, and the statements that finish a console program: message, delay, clear and print using.
Each section opens with the idea; click a Show me line for the details and examples, or Expand all.
input reads one or more values and stops at a comma or a
space, line input reads the whole line, and
key input reads a single keystroke without waiting for
Enter. All three take a prompt. A prompt written as a plain quoted string
gets a question mark appended,
while the explicit prompt option is shown exactly as written.
Output:
Output:
Three lessons in one run: the short form appended ? to
'Your name: ', the prompt form did not, and a
line input with no prompt shows nothing at all. Use the
prompt form whenever the exact text matters.
Output:
key input returns as soon as one key is pressed; the value is
that single character. It is the statement for "press any key" pauses and
single-letter choices.
| The person types | The program sees |
|---|---|
EXIT, or Ctrl+Z | _exit is true and the variable is empty. |
| Escape, or the Up arrow | _back is true and the variable is empty. |
HELP, or the Help button | _help is true. |
Output:
Test _help first, then _back and _exit:
more than one can be set by a single answer (when EXIT is the
default and the person asks for help, both _help and
_exit are true). The usual shape is a loop that leaves on
_exit:
That loop also shows a habit worth keeping: read into an ordinary variable,
check it, and only then store it in a table field — never
input straight into client(last_name).
Pressing Enter with nothing typed gives a numeric variable 0 and a string variable the empty string:
Output:
An unquoted answer to input loses its leading and trailing
spaces and cannot hold a comma. An answer typed in quotes keeps its spaces
and its commas; the quotes themselves are removed:
Output:
input fills a list of variables from comma-separated answers.
They can all be typed on one line, or one per line with a comma at the end
of each line that has more to come:
Output:
More answers than variables is the exception toomanyinp
(8003, Too many input items); too few, when the input has run
out, is toofewinp (8002, Too few input items).
line input takes a list too, but never splits an answer: it
asks once for each variable, and a comma is just part of the text.
Output:
| Key | What it does |
|---|---|
| Left arrow, Right arrow (or Ctrl+D, Ctrl+F) | Move within the answer. What is typed goes in at the cursor; the text after it moves along. |
| Ctrl+B | Jumps to the start of the answer; pressed again, to its end. |
| Ctrl+E | Moves to the end of the answer. (At the console's >>> prompt, Ctrl+E opens the emoji list instead, and End goes to the end of the line.) |
| Backspace, Delete, Ctrl+H | Delete the character to the left of the cursor. |
| Ctrl+J | Deletes the word to the left of the cursor. |
| Ctrl+U | Deletes everything to the left of the cursor — the whole answer when the cursor is at its end. |
| Ctrl+V | Pastes the clipboard at the cursor. |
| Tab | Moves to the next input field, or ends the input. |
| Enter | Ends the input — from anywhere in the line, not only its end. |
| Down arrow, Home, End, Insert, Page Up, Page Down, F1 to F12 | End the input with the answer as typed; _terminator$ names the key: DOWN, HOME, END, INS, PREV, NEXT, F1 ... (At the console's >>> prompt, F1 opens the help instead.) |
Ctrl+A, Ctrl+C and Ctrl+T belong to the console: Select All, Copy and Copy All Text. They work on the text of the screen, so the answer never sees them. Escape, the Up arrow and Ctrl+Z end the input too (see the table of words and keys that are not an answer, above).
key input does not echo the key and does not start a new line
— the print after it does that. It takes the same
options as input, and it sets _exit,
_back and _help the same way. The key that ended
an input is in _terminator$: RETURN for Enter, and
a control key as CTRL/G.
Output:
Options follow the prompt, comma-separated, and the list ends with a colon
before the variables: line input 'Prompt', option, option: var.
They control where the prompt appears, how long the program waits, what is
accepted, and what happens at the end of input.
| Option | Argument | What it does |
|---|---|---|
prompt | string | The prompt, shown exactly as written (no question mark added). |
default | string | Text already in the field when the prompt appears; the person can accept it with Enter or type over it. For a menu, the path of the item to highlight (section 3). |
length | number | The width of the input field on the screen. |
valid | string | A validation rule the answer must pass before it is accepted; a failing answer is refused and the prompt repeats. Rule words include integer, number, digits, letters, date, required, ucase, lcase, minlength n, maxlength n, pattern, yes/no, and the date layouts ymd, mdy, dmy. |
timeout | number | Seconds to wait for an answer before the statement gives up. |
elapsed | numeric variable | Receives the seconds the person took to answer (a real gets hundredths, an integer is rounded). |
eof | boolean variable | Set to true when there is no more input (a closed pipe, Ctrl+Z) instead of raising an error. |
at | row, column | Where the prompt appears on the screen, 1-origin. |
area | top, left, bottom, right | A rectangle for multi-line text entry. |
erase | — | Erases the input area first. |
attributes | string | Display attributes for the field, such as 'bold' or 'reverse'. |
menu | string | The menu definition — the whole of section 3 onward. |
screen | string | A fill-in form definition: several fields on one screen. |
dialogbox | string | A dialog box definition; implies line input. |
id | string | An identifier for the field, used by screen forms. |
The options a program most often reaches for are timeout with
elapsed, and eof:
Output:
Output:
Without eof, reading past the end of input is an error;
with it, the variable comes back empty and the flag says why. That is the
idiom for a program that reads until its input runs out.
at places the prompt anywhere on the screen. This is the
screen image captured while the program waited, with the prompt at row 5,
column 10:
Output:
length 20 limits the answer to twenty characters and draws
the field as twenty underscores after the prompt, so the person can see
how much room there is.default 'CA' puts CA in the field; Enter
accepts it, typing replaces it.attributes takes a list in a string —
bold, blink, reverse, separated
by commas.erase clears the input line before the prompt appears and
clears it again once the answer is in, so a prompt placed with
at leaves nothing behind:
input 'Enter a 2nd name', at 4, 1, erase: name_2$.
The rules are the ones the valid() function takes, so a rule
list can be tried out on its own. Several rules are separated by
semicolons, and the answer must pass them all:
Output:
When the time runs out the statement raises the exception
inptmo (8401, Timeout on input). The number may
carry a fraction — timeout 4.5. Catch it to carry on
with a default:
line input area top, left, bottom, right: text$ turns a
rectangle of the screen into a small text editor: the text wraps from line
to line as it is typed, the four arrow keys move through it, characters can
be inserted and deleted, and a bell sounds at the edge of the area or when
the text is full.
Escape in the top-left position abandons the input; the Help button leaves
it with _help set. Trailing spaces and line breaks are removed
from the result, and wrap$() re-wraps it to any width:
Output:
The first item is highlighted when the menu opens. %bar drew
the rule, and the > marks tropical as a
submenu — choosing it opens the second menu:
Choosing papaya closes both menus and the program continues:
apples becomes APPLES); a quoted item keeps
its case exactly — "Apples".text = value shows the text and returns the value:Output:
text = { items } is a submenu, nested as deeply as you
like. A submenu with no %title of its own is titled with
the item's text, as TROPICAL was above."Control Panel" = "ctrl" returns ctrl, while
"Notepad" = notepad returns NOTEPAD.%bar "*" draws the rule with the text you give instead of
dashes, and %heading with no text draws a blank line and a
dashed rule:
That last capture is what a menu looks like when the program runs with
/headless and its answers come from a file: the items are
numbered, and the answer is the number (or the item's text). It is how a
console application is tested unattended.
_string$ receives the path of the choice through the
levels: #3;#2 means the third item of the top menu, then
the second item of its submenu. Rules and headings are not counted._exit to true
— a console application should test that before trusting the
result:default option names the item to highlight when the
menu opens, by its path — the same form _string$
returns: default '#2' highlights the second choosable
item, default '#3;#2' opens the third item's submenu on
its second item. Keeping the last _string$ and passing it
back as the default reopens a menu on the person's previous choice.
A default that is not a path raises the illnum
exception.timeout and elapsed work with a menu exactly
as with a prompt._exit.
A directive is a word starting with %, written among the
items. There are twenty-four; they fall into three groups — where and
how the menu is laid out, what appears in it besides the items, and how it
behaves. Here is a menu using several at once, captured while it waited:
%at 3,5 put the top-left corner at row 3, column 5;
%split started the second column; each %heading
labelled its column; %invalid peas shows an item that cannot be
chosen — the path #1 counts only choosable items.
| Directive | Meaning |
|---|---|
%at row, col | Position of the menu; either may be center, as in %at center, center. |
%split | Start a new column here. |
%columns n | Split the items evenly into n columns. |
%items n | At most n items per column before a new column starts. |
%size n | Rows visible in the current column (at least 2); more items scroll. |
%width n | Minimum width of the current column. |
%maxwidth n | Maximum width of the whole menu (at least 5). |
%vbar | A vertical bar after the current column. |
%autovbar on|off | Automatic bars between columns (on by default). |
%lockstep on|off | Columns scroll together (on by default). |
%left | Entries flush left in their column. |
%border on|off | Draw the frame (on by default). |
%menubar | A horizontal menu bar with pull-down submenus, one row per column. |
| Directive | Meaning |
|---|---|
%title "text" | The title. |
%message "text" | A message shown while the menu is up. |
%bar, %bar 'text' | A rule across the column, plain or carrying text. |
%heading "text" | A labelled separator, in the heading colour; with no text, a blank line and a dashed rule. |
%invalid item | The next item is shown but cannot be chosen. |
| Directive | Meaning |
|---|---|
%multi | Choose several items — section 5. |
%replace | A submenu that replaces its parent instead of opening beside it; its Back item returns. |
%autodisplay on|off | Submenus open as soon as their item is highlighted (on by default). |
%nomouseover | No highlighting under the mouse pointer. Top-level menu only. |
%inactive | The menu is shown as a normal window that others may overlap. Top-level only. |
%attached | The menu minimizes and restores with the console window. Top-level only. |
Invalid input menu format. When the reason is known it is in
_string$ — see the %multi rule below.
Each picture is the screen captured while the menu waited, with the part of
the menu string that made the difference. Six directives have no picture
because they change behaviour rather than appearance: %message
(a status line while the menu is up), %autodisplay,
%lockstep, %nomouseover, %inactive and
%attached. %title is on every picture, and
%heading, %invalid and %split are in
the Layout example above.
Output:
The parent, then the screen after choosing reports: the
submenu is where the parent was, not beside it. Its Back item returns.
%multi turns the menu into a checklist with Done, Back and
Exit buttons. Space toggles an item; Done returns every checked item, one
per line.
The checked items come back separated by line breaks, so
pieces() counts them and piece$() takes them one at
a time. The rule: a %multi menu cannot contain submenus. The
menu string is refused when it is parsed, and the exception says why:
Output:
input screen draws a field to fill in instead of a bare prompt.
The string holds any text to show, and between < and
> the format of the field: optional format options,
a colon, then the format characters — one for each position
the person may type. The field is shown as underscores that disappear as it
is filled; the punctuation of the format is shown but not returned.
Output:
The person saw Soc. sec.: ___-__-____, typed nine digits into
it, and the program received the number without the dashes.
| Character | What may be typed there |
|---|---|
# | A digit (and, without the digits option, a minus sign or a decimal point). |
@ | Any printable character. |
^ | A letter, turned into upper case as it is typed. |
. | The decimal point of a number: in <###.####> the digits typed before the point are right-justified to it, and the fraction is zero-filled when the field is complete (typing .59 gives .5900). |
| any other | Shown as it is. The first > ends the field, so a field's text cannot hold one. |
Options come first, separated by commas, and end with a colon:
<aj, digits: ###-####>.
| Option | What it does |
|---|---|
ucase, lcase | Every letter typed becomes upper case, or lower case. |
noecho | What is typed is not shown — a password field: <noecho:Password? @@@@@>. |
digits | Digits only — not even the minus sign and decimal point that # allows. |
letters | Letters only. |
aj | Auto-jump: as soon as the field is full the cursor moves to the next field. |
req | Required: the field cannot be left empty. |
at row, column | Where the field appears on the screen; either may be center, as in <at center, center: ...>. |
noback | Escape does not go back to the previous field from this one. |
valid "rules" | Validation rules for this field — the same words as the valid option and a dialog box's valid= (required, integer, number, allow lo to hi, length n, minlength n ...), separated by semicolons: <valid "required; integer; allow 1 to 120": Age ###>. The field is not accepted until the answer passes, so no loop around the statement is needed. |
attributes "words" | Display attributes for this one field, the words of the statement's own attributes option (bold, blink, reverse, underline, a colour), comma-separated: <attributes "bold, reverse": Code @@@@>. They replace the statement's. |
call routine_name | A routine of yours that runs each time the field is left, with the field's text in _string$ — the dialog box's call= for a screen field. message error: 'why' inside it rejects the answer and the field is asked again; a quiet return accepts it. A valid rule on the same field runs first, so the routine sees only an answer the rules passed: <at 7, 10, call check_zip: Zip #####>. |
elapsed and timeout are the statement's options, as for a prompt: input screen scr$, timeout 30, elapsed took: a$.
Under /headless (see A Guide for an AI when Vibe Coding) a form is printed instead of drawn
— the text before the first field on its own line, then one line a field with the format characters
shown as underscores and a default in brackets — and each answer is read from the input, one line a
field; an empty line keeps the default. A field's valid rules, req and its
call routine apply there too: a refused answer prints (not valid -- try again),
(required -- try again) or the routine's own message, (zip 00000 is not a place -- try
again), and the field's line again.
That is how a program with fill-in fields is tested unattended.
Under /headless the answers come from the input; in the window
they can come from the program itself. set window: typeahead text$
puts keystrokes into the window's type-ahead buffer, and the next
input, input screen, menu or dialog box takes them
as if a person had typed them — chr$(9) is Tab to the next
field, chr$(13) is Enter. ask window: typeahead left$
reads what is still waiting, and set window: typeahead '' empties
the buffer. That is how every kind of input statement is tested without a
person at the keyboard.
An error clears the buffer. When an answer is refused — a
valid rule fails, a required field is left empty, a
call routine says message error: — whatever was
typed behind it is thrown away, on purpose: a canned stream of keys must not
cascade through an error into the wrong field. The prompt then waits for a
person (or its timeout), so a test types one accepted answer per
field, and pins a refusal through a short timeout, as below.
When a rule word cannot say it — a zip code looked up in a table, an end date
that must follow a start date — put call routine_name on the field.
The routine runs the moment the field is left, before the person moves on, with
the field's text in _string$; to refuse the answer it says
message error, and the field is asked again with the message shown.
No loop around the statement, and the check stays next to the field it checks:
The Age field's valid "integer" runs before check_age, so the
routine never sees abc. A call that names no routine raises
nodispatch when the field is left.
Put several <...> fields in the string and list a variable
for each. Tab moves to the next field, Escape goes back to the previous
one, and Enter — pressed in the last field — completes the form;
until then every answer can still be changed. A default for a
form is one value per field, separated by line feeds.
A %text block holds a form one field a line (see String handling);
every field carries its own at, so the line ends between them are
never drawn. A default for the same form is one value a field, joined with
line feeds:
For anything larger than this — labels, checkboxes, dropdowns, buttons — use a dialog box (Dialog Boxes: Forms, Fields, and Native File Pickers).
Three small statements finish a console application: message
talks to the person without disturbing the screen, delay waits,
and clear wipes the screen or a rectangle of it.
message writes in the status bar at the bottom of the window, in
dark blue, where the window's mode (Running, REPL)
is usually shown, and the mode comes back when the message's time is up (the
window keeps a scrollable history of messages, and the title bar shows the
latest). Nothing the program has printed is touched and nothing pops up. It
takes a list like print, with one difference: a comma puts a
single space between two items and a semicolon puts nothing.
shows number is 123456789. A message stays for at least three
seconds. Two options change how it is delivered:
message error: 'Is this really your age?' — an error:
shown in red in the status bar with a low tone (for anyone who may not
see the red), and anything the person had typed ahead is thrown away, so
a stray Enter cannot answer the next question.message delay: text$ — the program waits while the
message is read: about three seconds, and a little longer for a longer
message.
With nobody at a window a message is a line of text: a program run with
/headless writes -- text (?? text for
an error) on its error output, and a compile (/validate,
/build) writes %message text into its build report
as $info | -- text.
delay 4.5 pauses for that many seconds (fractions allowed, to
about a tenth of a second). delay with no number shows
Press the ENTER key to continue and waits for Enter or a mouse
click; Ctrl+Z, Escape and Help are answered there too, and set
_exit, _back and _help. Under
/headless a delay does not wait at all.
clear wipes the whole console, messages included.
clear area wipes one rectangle, given as two opposite corners
— top row, left column, bottom row, right column — on a screen
that is 30 rows by 100 columns unless you have changed it. Attributes
(bold, blink, reverse, separated by
commas) go before a colon, and box draws a frame around the
area:
This is the screen while that program waited, and under it the part of the
screen's attribute map that holds the box (# marks the frame):
clear area reverse: 5, 10, 11, 60 fills the same rectangle in
reverse video instead; text printed into it afterwards shows in the normal
way.
print using prints values through a mask, and a mask may start
with a directive in braces that rearranges the value first — a date, a
telephone number, a time or a postal code straight from the form it is
stored in. A ? after the directive prints the result as it is;
a mask of # characters after it lays the result out. (The same
directives work in format$().)
Output:
| Directive | The value | The result |
|---|---|---|
{date [layout]} | A date as YYMMDD or CCYYMMDD. | The date in the layout named — YMD, CYMD, MDY, MDCY, DMY, DMCY, DMONY, DMONCY, MONTHDY, MONTHDCY — and MDCY when none is named. |
{rotate n} | Any text. | The last n characters moved to the front: a number stored as 5552527800 prints with its area code first. |
{time} | A time as HHMM, HH:MM, HHMMSS or HH:MM:SS. | A 12-hour time with AM or PM. |
{zipcode} | A 5-, 6- or 9-character postal code. | The code in its usual form: five digits as they are, six characters split three and three, nine digits split five and four. |
In a mask, ~ makes the next character literal — that is how
the space and the dash got into 800 555-2527.
When one question is not enough and you want a whole form at once —
several fields, a checkbox or two, a dropdown — reach for a
dialog box: a native window driven by the same
line input family, which also opens the native file and folder
pickers. See Dialog Boxes: Forms, Fields, and Native File Pickers and its companion reference
Dialog Box Reference: Every Tag and Attribute.
input stops at a comma or space, line input
takes the whole line, key input takes one keystroke.? appended; the
prompt option shows the text exactly as written.: — timeout with elapsed,
eof, at, default,
valid, length, area.text = value,
text = { submenu }, and % directives for
title, position, columns and behaviour._string$,
and _exit when the person pressed Ctrl+Z; Escape returns
an empty result.%multi returns every checked item, one per line, and
cannot contain submenus.Invalid input menu format,
with the reason in _string$ when it is known.EXIT or Ctrl+Z sets _exit, Escape or Up sets
_back, HELP sets _help; test
_help first. A quoted answer keeps its spaces and commas.input screen draws fill-in fields: # digit,
@ any character, ^ upper-case letter, with options
such as digits, ucase, noecho,
aj and req before a colon.message writes on the message line (error: and
delay: change how), delay waits, clear
and clear area [box] wipe the screen or a rectangle of it.print using directives {date}, {rotate n},
{time} and {zipcode} reshape a stored value as it prints.|
Hide Description
|
|
|
Enter or modify the code below, and then click on RUN |
|
Looking for the full power of Sheerpower?
Check out the Sheerpower website. Free to download. Free to use. |