Popup YouTube Video
Sheerpower Logo

Making Console Applications: Prompts, Input Options, and Menus


Making Console Applications

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.

The output shown here is a text approximation. Sheerpower renders these menus graphically, in your operating system's native style; the ASCII versions are only for display on this page.

1. Three Ways to Ask

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.

Show me: the three statements and the two prompt forms
input 'How many widgets': n input 'Width and height': w, h print 'n = '; n; ' area = '; w * h

Output:

How many widgets? 12 Width and height? 3, 4 n = 12 area = 12
line input 'Your name: ': n1$ line input prompt 'Your name: ': n2$ line input n3$ print n1$; '|'; n2$; '|'; n3$

Output:

Your name: ? Ada Your name: Grace Linus Ada|Grace|Linus

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.

print 'Continue (y/n)?' key input k$ print 'key = ['; k$; ']'

Output:

Continue (y/n)? y key = [y]

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.

Show me: what a person can type at a prompt — EXIT, HELP, quotes, several answers

Words and keys that are not an answer

The person typesThe 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.
input 'Your name': name$ print 'name ['; name$; '] exit '; _exit; ' back '; _back; ' help '; _help input 'Your name': name$ print 'name ['; name$; '] exit '; _exit; ' back '; _back; ' help '; _help input 'Your name': name$ print 'name ['; name$; '] exit '; _exit; ' back '; _back; ' help '; _help

Output:

Your name? exit name [] exit 1 back 0 help 0 Your name? help name [help] exit 0 back 0 help 1 Your name? Tony name [Tony] exit 0 back 0 help 0

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:

do input 'Last name': last_name$ if _exit then exit do if len(last_name$) < 2 then message error: 'Too short of a name' repeat do end if client(last_name) = last_name$ end do

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).

Enter alone

Pressing Enter with nothing typed gives a numeric variable 0 and a string variable the empty string:

input 'A number': count input 'A string': text$ print 'count '; count; ' text ['; text$; ']'

Output:

A number? A string? count 0 text []

Quoted answers

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:

input 'Enter your name': name1$ input 'Enter your name in quotes': name2$ input 'Enter your name in quotes with spaces': name3$ input 'Enter last name, comma, space, first name in quotes': name4$ print '['; name1$; ']' print '['; name2$; ']' print '['; name3$; ']' print '['; name4$; ']'

Output:

Enter your name? Tony Enter your name in quotes? 'Tony' Enter your name in quotes with spaces? ' Tony ' Enter last name, comma, space, first name in quotes? 'Smith, Tony' [Tony] [Tony] [ Tony ] [Smith, Tony]

Several variables in one statement

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:

input 'Enter 3 names separated by commas': name1$, name2$, name3$ print name1$; '|'; name2$; '|'; name3$ input 'Again, one per line': name1$, name2$, name3$ print name1$; '|'; name2$; '|'; name3$

Output:

Enter 3 names separated by commas? Tom, Sue, George Tom|Sue|George Again, one per line? Tom, Sue, George Tom|Sue|George

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.

line input 'Enter a comment, press Enter, enter a comment': comment_1$, comment_2$ print comment_1$ print comment_2$

Output:

Enter a comment, press Enter, enter a comment? This is the first, with a comma Enter a comment, press Enter, enter a comment? This is the second comment This is the first, with a comma This is the second comment

Editing keys while typing

KeyWhat 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+BJumps to the start of the answer; pressed again, to its end.
Ctrl+EMoves 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+HDelete the character to the left of the cursor.
Ctrl+JDeletes the word to the left of the cursor.
Ctrl+UDeletes everything to the left of the cursor — the whole answer when the cursor is at its end.
Ctrl+VPastes the clipboard at the cursor.
TabMoves to the next input field, or ends the input.
EnterEnds the input — from anywhere in the line, not only its end.
Down arrow, Home, End, Insert, Page Up, Page Down, F1 to F12End 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).

More about key input

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.

print 'See how quick you are.' key input prompt 'Press a key, quick!', elapsed took: press$ print print 'You pressed ['; press$; ']' key input 'And another': second$ print print 'second ['; second$; '] terminator ['; _terminator$; ']'

Output:

See how quick you are. Press a key, quick!h You pressed [h] And another? z second [z] terminator [RETURN]

2. The Input Options

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.

Show me: every option, with its argument
OptionArgumentWhat it does
promptstringThe prompt, shown exactly as written (no question mark added).
defaultstringText 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).
lengthnumberThe width of the input field on the screen.
validstringA 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.
timeoutnumberSeconds to wait for an answer before the statement gives up.
elapsednumeric variableReceives the seconds the person took to answer (a real gets hundredths, an integer is rounded).
eofboolean variableSet to true when there is no more input (a closed pipe, Ctrl+Z) instead of raising an error.
atrow, columnWhere the prompt appears on the screen, 1-origin.
areatop, left, bottom, rightA rectangle for multi-line text entry.
erase—Erases the input area first.
attributesstringDisplay attributes for the field, such as 'bold' or 'reverse'.
menustringThe menu definition — the whole of section 3 onward.
screenstringA fill-in form definition: several fields on one screen.
dialogboxstringA dialog box definition; implies line input.
idstringAn identifier for the field, used by screen forms.

The options a program most often reaches for are timeout with elapsed, and eof:

line input 'Answer within 5 seconds', timeout 5, elapsed took: a$ print 'answer ['; a$; '] took '; took; ' seconds'

Output:

Answer within 5 seconds? fast answer [fast] took 0.003 seconds
line input 'Line', eof done?: a$ print 'first ['; a$; '] done '; done? line input 'Line', eof done?: b$ print 'second ['; b$; '] done '; done?

Output:

Line? only one line first [only one line] done 0 Line? second [] done 1

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:

line input 'Name', at 5, 10: n$ print 'hello '; n$

Output:

Name? Kim hello Kim
Show me: length, default, attributes, erase, valid, timeout and area at work
name_attr$ = 'bold, blink' line input 'Enter your name', attributes name_attr$: name$ input 'Enter a city', length 20: city$ input 'Enter the state code', default 'CA': state$ input 'Enter age', length 5, valid 'integer': age$
  • 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$.

valid

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:

print 'integer 32 '; valid('32', 'integer') print 'integer abc '; valid('abc', 'integer') print 'number 3.5 '; valid('3.5', 'number') print 'required "" '; valid('', 'required') print 'digits 12a '; valid('12a', 'digits') print 'letters abc '; valid('abc', 'letters') print 'date ymd '; valid('20260920', 'date ymd') print 'two rules ok '; valid('12345', 'digits; minlength 5') print 'two rules no '; valid('1234', 'digits; minlength 5')

Output:

integer 32 1 integer abc 0 number 3.5 1 required "" 0 digits 12a 0 letters abc 1 date ymd 1 two rules ok 1 two rules no 0

timeout

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:

when exception in input 'Name', timeout 4.5: name$ use name$ = 'guest' end when

area

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:

line input area 5, 10, 8, 60: text$ print at 10, 1: 'Rewrapped text' print wrap$(text$, 1, 30)

Output:

This is an example of wrapped text. The text is wrapping. Rewrapped text This is an example of wrapped text. The text is wrapping.

3. Menus

A menu is a string. Items are separated by commas, an item can carry a value, an item can open a submenu, and % directives set the title, the position, the layout and the behaviour. The statement is line input menu spec$: choice$; the person moves with the arrow keys and picks with Enter, Space or a click.

print 'Welcome to the fruit stand' spec$ = '%title ' + quote$('Pick a fruit') + ', ' + 'apples, pears, ' + '%bar, ' + 'tropical = { mango, papaya }' line input menu spec$: choice$ print 'you chose '; choice$ print 'path '; _string$ Welcome to the fruit stand +---------Pick a fruit---------+ | APPLES | | PEARS | |------------------------------| | TROPICAL > | +------------------------------+

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:

Welcome to the fruit stand +-----------TROPICAL-----------+ | MANGO | | PAPAYA | +------------------------------+

Choosing papaya closes both menus and the program continues:

Welcome to the fruit stand you chose PAPAYA path #3;#2
Show me: item syntax, values, submenus, and what the program gets back

Items

  • Items are comma-separated. An unquoted item is shown in upper case (apples becomes APPLES); a quoted item keeps its case exactly — "Apples".
  • text = value shows the text and returns the value:
line input menu 'Small = S, Medium = M, Large = L': size$ print 'code '; size$; ' path '; _string$

Output:

code M path #2
  • 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.
  • A value keeps its case when it is quoted, like an item: "Control Panel" = "ctrl" returns ctrl, while "Notepad" = notepad returns NOTEPAD.
  • A description that holds spaces or special characters must be quoted.
  • A menu can hold up to 5,000 items.
  • %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:
line input menu '"DATA ENTRY", "REPORTS", %bar"*", MAIL, EXIT': ans$ print 'ans '; ans$ line input menu '"Control Panel" = "ctrl", "Notepad" = notepad': ans$ print 'ans ['; ans$; ']' 1. DATA ENTRY 2. REPORTS * 3. MAIL 4. EXIT menu> 3 ans MAIL 1. Control Panel 2. Notepad menu> 1 ans [ctrl]

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.

What the program gets back

  • The variable receives the chosen item's value, or its text when it has no value.
  • _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.
  • Escape (or the Back item of a submenu) leaves the menu with an empty result. Ctrl+Z leaves it too and sets _exit to true — a console application should test that before trusting the result:
line input menu 'go, stop': ans$ print 'ans ['; ans$; '] exit flag '; _exit ans [] exit flag 1

Pre-selecting an item, and the other options

  • The 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.
  • input menu spec$: choice$ is the same statement as line input menu.

The keys a person uses

  • Up and Down move the highlight; Delete jumps to the first item.
  • Enter, Space, Right arrow, or a click chooses the item, or opens its submenu.
  • Escape or Left arrow goes back to the calling menu; from the top menu, Escape leaves with an empty result.
  • Ctrl+Z leaves the whole menu and sets _exit.

4. The Menu Directives

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:

spec$ = '%title ' + quote$('Layout') + ', ' + '%at 3,5, ' + '%heading ' + quote$('Fruit') + ', ' + 'apples, pears, ' + '%split, ' + '%heading ' + quote$('Veg') + ', ' + 'carrots, %invalid peas, beans' line input menu spec$: pick$ print 'pick '; pick$; ' path '; _string$ +----------------------------Layout----------------------------+ |Fruit | Veg | | APPLES | CARROTS | | PEARS | PEAS | | | BEANS | +--------------------------------------------------------------+
pick APPLES path #1

%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.

Show me: all twenty-four directives

Layout

DirectiveMeaning
%at row, colPosition of the menu; either may be center, as in %at center, center.
%splitStart a new column here.
%columns nSplit the items evenly into n columns.
%items nAt most n items per column before a new column starts.
%size nRows visible in the current column (at least 2); more items scroll.
%width nMinimum width of the current column.
%maxwidth nMaximum width of the whole menu (at least 5).
%vbarA vertical bar after the current column.
%autovbar on|offAutomatic bars between columns (on by default).
%lockstep on|offColumns scroll together (on by default).
%leftEntries flush left in their column.
%border on|offDraw the frame (on by default).
%menubarA horizontal menu bar with pull-down submenus, one row per column.

Content

DirectiveMeaning
%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 itemThe next item is shown but cannot be chosen.

Behaviour

DirectiveMeaning
%multiChoose several items — section 5.
%replaceA submenu that replaces its parent instead of opening beside it; its Back item returns.
%autodisplay on|offSubmenus open as soon as their item is highlighted (on by default).
%nomouseoverNo highlighting under the mouse pointer. Top-level menu only.
%inactiveThe menu is shown as a normal window that others may overlap. Top-level only.
%attachedThe menu minimizes and restores with the console window. Top-level only.
One error for every mistake. A directive with a missing or bad argument, a top-level-only directive inside a submenu, an empty quoted item, or a menu that ends before any item all raise the same exception, Invalid input menu format. When the reason is known it is in _string$ — see the %multi rule below.
Show me: what each directive looks like on the screen

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.

%at center, center

spec$ = '%title ' + quote$('Centred') + ', ' + '%at center, center, ' + 'one, two, three' line input menu spec$: choice$ +-----------Centred------------+ | ONE | | TWO | | THREE | +------------------------------+

%size 3 — three rows visible, the rest scroll

spec$ = '%title ' + quote$('Only three rows') + ', ' + '%size 3, ' + 'alpha, beta, gamma, delta, epsilon, zeta' line input menu spec$: choice$ +-------Only three rows--------+ | ALPHA | | BETA | | GAMMA | +------------------------------+

%columns 2 — the items split evenly

spec$ = '%title ' + quote$('Two columns') + ', ' + '%columns 2, ' + 'jan, feb, mar, apr, may, jun' line input menu spec$: choice$ +-------------------------Two columns--------------------------+ | JAN | APR | | FEB | MAY | | MAR | JUN | +--------------------------------------------------------------+

%items 3 — a new column every three items

spec$ = '%title ' + quote$('Three per column') + ', ' + '%items 3, ' + 'jan, feb, mar, apr, may, jun' line input menu spec$: choice$ +-----------------------Three per column-----------------------+ | JAN | APR | | FEB | MAY | | MAR | JUN | +--------------------------------------------------------------+

%maxwidth 40 — the whole menu capped, the last column cut

spec$ = '%title ' + quote$('Capped at 40') + ', ' + '%maxwidth 40, %columns 2, ' + 'jan, feb, mar, apr' line input menu spec$: choice$ +--------------Capped at 40--------------+ | JAN | MAR | | FEB | APR | +----------------------------------------+

%autovbar off — no bars between columns

spec$ = '%title ' + quote$('Bars off') + ', ' + '%autovbar off, ' + 'jan, feb, %split, mar, apr' line input menu spec$: choice$ +--------------------------Bars off---------------------------+ | JAN MAR | | FEB APR | +-------------------------------------------------------------+

%vbar — a bar after this column only

spec$ = '%title ' + quote$('One bar, where asked') + ', ' + '%autovbar off, ' + 'jan, feb, %vbar, %split, mar, apr' line input menu spec$: choice$ +---------------------One bar, where asked---------------------+ | JAN | MAR | | FEB | APR | +--------------------------------------------------------------+

%border off — no frame, and so no title

print 'The line above the menu' spec$ = '%title ' + quote$('Borderless') + ', ' + '%border off, ' + 'one, two' line input menu spec$: choice$

Output:

The line above the menu ONE TWO

%bar 'text' — a rule that carries a label

spec$ = '%title ' + quote$('Rules') + ', ' + 'coffee, tea, ' + '%bar ' + quote$('cold drinks') + ', ' + 'juice, water' line input menu spec$: choice$ +------------Rules-------------+ | COFFEE | | TEA | |-------- cold drinks ---------| | JUICE | | WATER | +------------------------------+

%replace — the submenu takes the parent's place

The parent, then the screen after choosing reports: the submenu is where the parent was, not beside it. Its Back item returns.

spec$ = '%title ' + quote$('Main') + ', ' + 'reports = { %replace, %title ' + quote$('Reports') + ', daily, weekly }, ' + 'settings' line input menu spec$: a$ print 'a = '; a$ +-------------Main-------------+ | REPORTS > | | SETTINGS | +------------------------------+
+-----------Reports------------+ | DAILY | | WEEKLY | +------------------------------+
a = WEEKLY

%menubar — a horizontal bar with pull-downs

spec$ = '%menubar, ' + 'file = { open, save }, edit = { cut, paste }, help' line input menu spec$: choice$ +----------------------------------------------------------------------------- | FILE > EDIT > HELP +-----------------------------------------------------------------------------

%multi — a checklist

spec$ = '%title ' + quote$('Toppings') + ', ' + '%multi, ' + 'cheese, onions, olives' line input menu spec$: a$ print 'a = '; change$(a$, chr$(10), '|') +-----------Toppings-----------+ | [ ] CHEESE | | [ ] ONIONS | | [ ] OLIVES | +------------------------------+
a = CHEESE|OLIVES

%width 40 — a column at least 40 wide

spec$ = '%title ' + quote$('At least 40 wide') + ', ' + '%width 40, ' + 'yes, no' line input menu spec$: choice$ +------------At least 40 wide------------+ | YES | | NO | +----------------------------------------+

%left — no indent in front of the items

spec$ = '%title ' + quote$('Flush left') + ', ' + '%left, ' + 'one, two' line input menu spec$: choice$ +----------Flush left----------+ |ONE | |TWO | +------------------------------+

5. Choosing Several Items: %multi

%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.

Show me: the result of a %multi menu, and its one rule
spec$ = '%title ' + quote$('Colours') + ', ' + '%multi, ' + 'red, green, blue' line input menu spec$: picks$ print 'picks: '; change$(picks$, chr$(10), '|') print 'count: '; pieces(picks$, chr$(10)) +-----------Colours------------+ | [ ] RED | | [ ] GREEN | | [ ] BLUE | +------------------------------+ picks: RED|BLUE count: 2

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:

when exception in line input menu '%multi, a = {x, y}, b': ans$ use print 'error '; extype; ': '; extext$ print 'detail: '; _string$ end when

Output:

error -4023 : Invalid input menu format detail: a %multi menu cannot contain submenus (an item written as name={...}): use %multi only on a menu whose items are all plain choices

6. Fill-in Fields: the SCREEN Option

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.

input screen 'Soc. sec.: <DIGITS:###-##-####>': ssn print 'ssn '; ssn input screen '<:(###) ###-####>': phone print 'phone '; phone input screen 'License #: <@@@ @@@@>': license$ print 'license '; license$

Output:

ssn 555486662 phone 5555547879 license INF5783

The person saw Soc. sec.: ___-__-____, typed nine digits into it, and the program received the number without the dashes.

Show me: the format characters, the format options, and a whole form

Format characters

CharacterWhat 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 otherShown as it is. The first > ends the field, so a field's text cannot hold one.

Format options

Options come first, separated by commas, and end with a colon: <aj, digits: ###-####>.

OptionWhat it does
ucase, lcaseEvery letter typed becomes upper case, or lower case.
noechoWhat is typed is not shown — a password field: <noecho:Password? @@@@@>.
digitsDigits only — not even the minus sign and decimal point that # allows.
lettersLetters only.
ajAuto-jump: as soon as the field is full the cursor moves to the next field.
reqRequired: the field cannot be left empty.
at row, columnWhere the field appears on the screen; either may be center, as in <at center, center: ...>.
nobackEscape 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_nameA 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$.

Running without a screen

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.

Testing in the window: typeahead

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.

// Expect: form [Ada|90210] left [] // age: Timeout on input // after the refusal, left [] tab$ = chr$(9) cr$ = chr$(13) set window: typeahead 'Ada' + tab$ + '90210' + cr$ input screen '': name$, zip$ ask window: typeahead left$ print 'form ['; name$; '|'; zip$; '] left ['; left$; ']' set window: typeahead 'abc' + cr$ + '42' + cr$ when exception in input 'Age', valid 'integer', timeout 3: age use print 'age: '; extext$ end when ask window: typeahead left$ print 'after the refusal, left ['; left$; ']'

A check of your own on a field: call

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:

form$ = '<at 5, 10: Name @@@@@@@@>' + '<at 7, 10, call check_zip: Zip #####>' + '<at 9, 10, valid "integer", call check_age: Age ###>' input screen form$: name$, zip$, age$ print name$; ' '; zip$; ' '; age$ routine check_zip if _string$ = '00000' then message error: 'zip 00000 is not a place' end routine routine check_age if val(_string$) > 120 then message error: 'nobody is that old' end routine

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.

A form: several fields in one statement

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.

city$ = 'St Paul' state$ = 'MN' df$ = city$ + chr$(10) + state$ clear scr$ = '<at 6, 10: City @@@@@@@@@@@@@@@@@@@@@@@@@@>' + '<at 7, 10: State ^^>' input screen scr$, default df$: city$, state$
form$ = %text trim <at 5, 10: Full name @@@@@@@@@@@@@@@@@@@@@@@@> <at 7, 10: Address @@@@@@@@@@@@@@@@@@@@@@@@> <at 9, 10: City @@@@@@@@@@@@> <at 9, 38, aj, req, letters: State ^^> <at 9, 50, req, digits: Zip #####> <at 11, 10, valid "required; integer": Age ###> %end text clear input screen form$, timeout 60, elapsed took: name$, addr$, city$, state$, zip$, age$

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:

defaults$ = join$(split('Ada Lovelace|12 Analytical Row|London|UK|12345|36', '|'), chr$(10)) input screen form$, default defaults$: name$, addr$, city$, state$, zip$, age$

For anything larger than this — labels, checkboxes, dropdowns, buttons — use a dialog box (Dialog Boxes: Forms, Fields, and Native File Pickers).

7. Messages, Pauses and a Clean Screen

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.

Show me: message, delay, clear and clear area

message

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.

message 'number is', 123; 456; 789

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

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 input 'Please enter your name': name$ print 'Hello, '; name$ delay clear

clear and clear area

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:

clear clear area box, bold: 5, 10, 11, 60 print at 7, 20: 'Inside the box' print at 12, 1: 'Outside the box' input at 14, 1, prompt 'Press Enter: ': a$

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):

Inside the box Outside the box Press Enter: .........###################################################.................... .........#.................................................#.................... .........#.................................................#.................... .........#.................................................#.................... .........#.................................................#.................... .........#.................................................#.................... .........###################################################....................

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.

8. PRINT USING Directives

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$().)

Show me: {date}, {rotate}, {time} and {zipcode}
print using '{date}?': '990122' print using '{date dmcy}?': '990122' print using '{date mdcy}##/##/####': '20000115' print using '{rotate 3}?': '5552527800' print using '{rotate 3}###~ ###~-####': '5552527800' print using '{time}?': '1022' print using '{time}?': '19:45:36' print using '{zipcode}?': '92126' print using '{zipcode}?': 'K8A3P9' print using '{zipcode}?': '931327845'

Output:

01221999 22011999 01/15/2000 8005552527 800 555-2527 10:22 AM 07:45:36 PM 92126 K8A 3P9 93132-7845
DirectiveThe valueThe 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.

Beyond the Console: Dialog Boxes

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.

Making Console Applications Takeaways

  • input stops at a comma or space, line input takes the whole line, key input takes one keystroke.
  • A plain quoted prompt gets ? appended; the prompt option shows the text exactly as written.
  • Options are comma-separated after the prompt and end with : — timeout with elapsed, eof, at, default, valid, length, area.
  • A menu is a string: comma-separated items, text = value, text = { submenu }, and % directives for title, position, columns and behaviour.
  • The program gets the chosen value, the path in _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.
  • Every menu mistake raises 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.