{Begin SubSec The TTYIN Display Typein Editor} {Title The TTYIN Display Typein Editor} {Text {index *BEGIN* TTYIN FN} {Tag TTYIN} {Begin Note} Filed on: ttyin.im edited: June 18, 1982 by Bill van Melle translated into IM format: Thu, 21 Jul 83 10:36 PDT by Sannella {End Note} TTYIN is an Interlisp function for reading input from the terminal. It features altmode completion, spelling correction, help facility, and fancy editing, and can also serve as a glorified free text input function. This document is divided into two major sections: how to use TTYIN from the user's point of view, and from the programmer's. TTYIN exists in implementations for Interlisp-10 and Interlisp-D. The two are substantially compatible, but the capabilities of the two systems differ (Interlisp-D has a more powerful display and allows greater access to the system primitives needed to control it effectively; it also has a mouse, greatly reducing the need for keyboard-oriented editing commands). Descriptions of both are included in this document for completeness, but Interlisp-D users may find large sections irrelevant. {Begin SubSec Entering Input With TTYIN} {Title Entering Input With TTYIN} {Text There are two major ways of using TTYIN: (1) set {var LISPXREADFN} to {fn TTYIN}, so the LISPX executive uses it to obtain input, and (2) call {fn TTYIN} from within a program to gather text input. Mostly the same rules apply to both; places where it makes a difference are mentioned below. The following characters may be used to edit your input, independent of what kind of terminal you are on. The more TTYIN knows about your terminal, of course, the nicer some of these will behave. Some functions are performed by one of several characters; any character that you happen to have assigned as an interrupt character will, of couse, not be read by TTYIN. There is a (somewhat inelegant) way of changing which characters perform which functions, described under {var TTYINREADMACROS} later on. {Begin LabeledList TTYIN characters} {Indent 10percent} {Label control-A, {lisp BS}, {lisp DEL}} {Text Deletes a character. At the start of the second or subsequent lines of your input, deletes the last character of the previous line. } {Label control-W} {Text Deletes a "word". Generally this means back to the last space or parenthesis. } {Label control-Q (control-U for Tops20 users)} {Text Deletes the current line, or if the current line is blank, deletes the previous line. } {Label control-R} {Text Refreshes the current line. Two in a row refreshes the whole buffer (when doing multi-line input). } {Label {lisp ESC}} {Text Tries to complete the current word from the spelling list provided to {fn TTYIN}, if any. In the case of ambiguity, completes as far as is uniquely determined, or rings the bell. For {fn LISPX} input, the spelling list may be {var USERWORDS} (see discussion of {var TTYINCOMPLETEFLG}, {PageRef Var TTYINCOMPLETEFLG}). Interlisp-10 only: If no spelling list was provided, but the word begins with a "<", tries directory name completion (or filename completion if there is already a matching ">" in the current word). } {Label {lisp ?}} {Text If typed in the middle of a word will supply alternative completions from the {arg SPLST} argument to {fn TTYIN} (if any). {var ?ACTIVATEFLG} ({PageRef Var ?ACTIVATEFLG}) must be true to enable this feature. } {Label control-F} {Text Sumex, Tops20 only: Invokes {fn GTJFN} for filename completion on the current "word". } {Label control-Y} {Text Escapes to a Lisp userexec, from which you may return by the command {lisp OK}. However, when in READ mode and the buffer is non-empty, control-Y is treated as Lisp's unquote macro instead, so you have to use edit-control-Y (below) to invoke the userexec. } {Label in Interlisp-D, LF in Interlisp-10} {Text Retrieves characters from the previous non-empty buffer when it is able to; e.g., when typed at the beginning of the line this command restores the previous line you typed at TTYIN; when typed in the middle of a line fills in the remaining text from the old line; when typed following ^Q or ^W restores what those commands erased. } {Label ;} {Text If typed as the first character of the line means the line is a comment; it is ignored, and TTYIN loops back for more input. } {Label control-X} {Text Goes to the end of your input (or end of expression if there is an excess right parenthesis) and returns if parentheses are balanced, beeps if not. Currently implemented in Interlisp-D only. } {End LabeledList TTYIN characters} During most kinds of input, TTYIN is in "autofill" mode: if a space is typed near the right margin, a carriage return is simulated to start a new line. In fact, on cursor-addressable displays, lines are always broken, if possible, so that no word straddles the end of the line. The "pseudo-carriage return" ending the line is still read as a space, however; i.e., the program keeps track of whether a line ends in a carriage return or is merely broken at some convenient point. You won't get carriage returns in your strings unless you explicitly type them. }{End SubSec Entering Input With TTYIN} {Begin SubSec Mouse Commands [Interlisp-D Only]} {Title Mouse Commands [Interlisp-D Only]} {Text The mouse buttons are interpreted as follows during TTYIN input: {Begin LabeledList mouse buttons} {Indent 10percent} {Label {lisp LEFT}} {Text Moves the caret to where the cursor is pointing. As you hold down {lisp LEFT}, the caret moves around with the cursor; after you let up, any typein will be inserted at the new position. } {Label {lisp MIDDLE}} {Text Like {lisp LEFT}, but moves only to word boundaries. } {Label {lisp RIGHT}} {Text Deletes text from the caret to the cursor, either forward or backward. While you hold down {lisp RIGHT}, the text to be deleted is complemented; when you let up, the text actually goes away. If you let up outside the scope of the text, nothing is killed (this is how to "cancel" the command). This is roughly the same as {lisp CTRL}-{lisp RIGHT} with no initial selection (below). } {End LabeledList mouse buttons} If you hold down {lisp CTRL} and/or {lisp SHIFT} while pressing the mouse buttons, you instead get secondary selection, move selection or delete selection. You make a selection by bugging {lisp LEFT} (to select a character) or {lisp MIDDLE} (to select a word), and optionally extend the selection either left or right using {lisp RIGHT}. While you are doing this, the caret does not move, but your selected text is highlighted in a manner indicating what is about to happen. When you have made your selection (all mouse buttons up now), lift up on {lisp CTRL} and/or {lisp SHIFT} and the action you have selected will occur, which is: {Begin LabeledList CTRLand/orSHIFT} {Indent 10percent} {Label {lisp SHIFT}} {Text The selected text as typein at the caret. The text is highlighted with a broken underline during selection. } {Label {lisp CTRL}} {Text Delete the selected text. The text is complemented during selection. } {Label {lisp CTRL}-{lisp SHIFT}} {Text Combines the above: delete the selected text and insert it at the caret. This is how you move text about. } {End LabeledList CTRLand/orSHIFT} You can cancel a selection in progress by pressing {lisp LEFT} or {lisp MIDDLE} as if to select, and moving outside the range of the text. The most recent text deleted by mouse command can be inserted at the caret by typing (the same key that retrieves the previous buffer when issued at the end of a line). }{End SubSec Mouse Commands [Interlisp-D Only]} {Begin SubSec Display Editing Commands} {Title Display Editing Commands} {Text On edit-key terminals (Datamedia): In Interlisp-10, TTYIN reads from the terminal in binary mode, allowing many more editing commands via the edit key, in the style of TVEDIT commands. Note that due to Tenex's unfortunate way of handling typeahead, it is not possible to type ahead edit commands before TTYIN has started (i.e., before its prompt appears), because the edit bit will be thrown away. Also, since ESCAPE has numerous other meanings in Lisp and even in TTYIN (for completion), ESCAPE is not used as a substitute for the edit key. In Interlisp-D: Users will probably have little use for most of these commands, as cursor positioning can often be done more conveniently, and certainly more obviously, with the mouse. Nevertheless, some commands, such as the case changing commands, can be useful. The key can be used as an edit (meta) key in Chorus and subsequent releases if you perform {lisp (TTYINMETA T)}.{index TTYINMETA Fn} This calls {lisp (METASHIFT T)} to enable the meta key, redefines the middle and top blank keys, and informs TTYIN that you want to use them. Alternatively, you can use the {var EDITPREFIXCHAR} (by default on ) as described in the next paragraph. On edit-keyless display terminals (Heath): If you want to type any of these commands, you need to prefix them with the "edit prefix" character. Set the variable {var EDITPREFIXCHAR}{index EDITPREFIXCHAR Var} to the character code of the desired prefix char. Type the edit prefix twice to give an "edit-ESCAPE" command. Some users of the TENEX TVEDIT program like to make ESCAPE (33Q) be the edit prefix, but this makes it somewhat awkward to ever use escape completion. On edit-keyless hardcopy terminals: You probably want to ignore this section, since you won't be able to see what's going on when you issure edit commands; there is no attempt made to echo anything reasonable. In the descriptions below, "current word" means the word the cursor is under, or if under a space, the previous word. Currently parentheses are treated as spaces, which is usually what you want, but can occasionally cause confusion in the word deletion commands. The notation [{arg CHAR}] means edit-{arg CHAR}, if you have an edit key, or {arg CHAR} if you don't; $ = escape. Most commands can be preceded by numbers or escape (means infinity), only the first of which requires the edit key (or the edit prefix). Some commands also accept negative arguments, but some only look at the magnitude of the arg. Most of these commands are taken from the display editors TVEDIT and/or E, and are confined to work within one line of text unless otherwise noted. Cursor Movement Commands: {Begin LabeledList Cursor Movement Commands} {Indent 10percent} {Label [delete], [bs], [<]} {Text Back up one (or n) characters. } {Label [space], [>]} {Text Move forward one (or n) characters. } {Label [^]} {Text Moves up one (or n) lines. } {Label [lf]} {Text Moves down one (or n) lines. } {Label [(]} {Text Move back one (or n) words. } {Label [)]} {Text Move ahead one (or n) words. } {Label [tab]} {Text Moves to end of line; with an argument moves to nth end of line; [$tab] goes to end of buffer. } {Label [control-L]} {Text Moves to start of line (or nth previous, or start of buffer). } {Label [{lbracket}] and [{rbracket}]} {Text Go to start and end of buffer, respectively (like [$control-L] and [$tab]). } {Label [ [ ] (edit-left-bracket)} {Text Moves to beginning of the current list, where cursor is currently under an element of that list or its closing paren. (See also the auto-parenthesis-matching feature below under "Flags".) } {Label [ ] ] (edit-right-bracket)} {Text Moves to end of current list. } {Label [Sx]} {Text Skips ahead to next (or nth) occurrence of character x, or rings the bell. } {Label [Bx]} {Text Backward search, i.e., short for [-S] or [-nS]. } {End LabeledList Cursor Movement Commands} Buffer Modification Commands: {Begin LabeledList Buffer Modification Commands} {Indent 10percent} {Label [Zx]} {Text Zaps characters from cursor to next (or nth) occurrence of x. There is no unzap command yet. } {Label [A] or [R]} {Text Repeat the last S, B or Z command, regardless of any intervening input (note this differs from Tvedit's A command). } {Label [K]} {Text Kills the character under the cursor, or n chars starting at the cursor. } {Label [I]} {Text Begin inserting. Exit insert with any edit command. Characters you type will be inserted, rather than overwriting the existing text. If {var EMACSFLG} ({PageRef Var EMACSFLG}) is true (default in Interlisp-D), you are always in insert mode, and this command is a noop. Inserting behaves slightly different from in tvedit. The sequence [I] behaves as in TVEDIT; it inserts a blank line ahead of the cursor. typed any other time while in insert mode actually inserts a , behaving somewhat like TVEDIT's [B]. [$I] is the same as [I]. } {Label [cr]} {Text When the buffer is empty is the same as , i.e. restores buffer's previous contents. Otherwise is just like a (except that it also terminates an insert). Thus, [] will repeat the previous input (as will without the edit key). } {Label [O]} {Text Does "Open line", inserting a crlf after the cursor, i.e., it breaks the line but leaves the cursor where it is. } {Label [T]} {Text Transposes the characters before and after the cursor. When typed at the end of a line, transposes the previous two characters. Refuses to handle funny cases, such as tabs. } {Label [G]} {Text Grabs the contents of the previous line from the cursor position onward. [nG] grabs the nth previous line. } {Label [L]} {Text Lowercases current word, or n words on line. [$L] lowercases the rest of the line, or if given at the end of line lowercases the entire line. } {Label [U]} {Text Uppercases analogously. } {Label [C]} {Text Capitalize. If you give it an argument, only the first word is capitalized; the rest are just lowercased. } {Label [control-Q]} {Text Deletes the current line. [$control-Q] deletes from the current cursor position to the end of the buffer. No other arguments are handled. {note This is all slightly inconsistent; suggestions for better interpretations are welcome.} } {Label [control-W]} {Text Deletes the current word, or the previous word if sitting on a space. } {Label [D] and [D]} {Text Are the same as [control-W] and [control-Q], for approximate compatibility with TVEDIT. } {Label [J]} {Text "Justify" this line. This will break it if it is too long, or move words up from the next line if too short. Will not join to an empty line, or one starting with a tab (both of which are interpreted as paragraph breaks). Any new line breaks it introduces are considered spaces, not carriage returns. [nJ] justifies n lines. The linelength is defined as {var TTYJUSTLENGTH},{index TTYJUSTLENGTH Var} ignoring any prompt characters at the margin. If {var TTYJUSTLENGTH} is negative, it is interpreted as relative to the right margin. {var TTYJUSTLENGTH} is initially 8 in Interlisp-D, 72 in Interlisp-10. } {Label [$F]} {Text "Finishes" the input, regardless of where the cursor is. Specifically, it goes to the end of the input and enters a , control-Z or "]", depending on whether normal, {lisp REPEAT} or {fn READ} input is happening. Note that a "]" won't necessarily end a {fn READ}, but it seems likely to in most cases where you would be inclined to use this command, and makes for more predictable behavior. } {End LabeledList Buffer Modification Commands} Miscellaneous Commands: {Begin LabeledList Miscellaneous Commands} {Indent 10percent} {Label [P]} {Text Interlisp-D: Prettyprint buffer. Clears the buffer and reprints it using prettyprint. If there are not enough right parentheses, it will supply more; if there are too many, any excess remains unprettyprinted at the end of the buffer. May refuse to do anything if there is an unclosed string or other error trying to read the buffer. } {Label [N]} {Text Refresh line. Same as control-R. [$N] refreshes the whole buffer; [nN] refreshes n lines. Cursor movement in TTYIN depends on TTYIN being the only source of output to the screen; if you do a control-T, or a system message appears, or line noise occurs, you may need to refresh the line for best results. In Interlisp-10, if for some reason your terminal falls out of binary mode (e.g. can happen when returning to a Lisp running in a lower fork), Edit- is unreadable, so you'd have to type control-R instead. } {Label [control-Y]} {Text Gets userexec. Thus, this is like regular control-Y, except when doing a READ (when control-Y is a read macro and hence does not invoke this function). } {Label [$control-Y]} {Text Gets a userexec, but first unreads the contents of the buffer from the cursor onward. Thus if you typed at TTYIN something destined for the Lisp executive, you can do [control-L$control-Y] and give it to Lisp. } {Label [_]} {Text Adds the current word to the spelling list {var USERWORDS}. With zero arg, removes word. See {var TTYINCOMPLETEFLG} ({PageRef Var TTYINCOMPLETEFLG}). } {End LabeledList Miscellaneous Commands} Note to Datamedia, Heath users: In addition to simple cursor movement commands and insert/delete, TTYIN uses the display's cursor-addressing capability to optimize cursor movements longer than a few characters, e.g. [tab] to go to the end of the line. In order to be able to address the cursor, TTYIN has to know where it is to begin with. Lisp keeps track of the current print position within the line, but does not keep track of the line on the screen (in fact, it knows precious little about displays, much like Tenex). Thus, TTYIN establishes where it is by forcing the cursor to appear on the last line of the screen. Ordinarily this is the case anyway (except possibly on startup), but if the cursor happens to be only halfway down the screen at the time, there is a possibly unsettling leap of the cursor when TTYIN starts. }{End SubSec Display Editing Commands} {Begin SubSec Using TTYIN for Lisp Input} {Title Using TTYIN for Lisp Input} {Text When TTYIN is loaded, or a sysout containing TTYIN is started up, the function {fn SETREADFN}{index SETREADFN Fn} is called. If the terminal is a display, it sets {var LISPXREADFN} to be {fn TTYINREAD};{index TTYINREAD Fn} if the terminal is non-display, {fn SETREADFN} will set the variable back to {fn READ}. {lisp (SETREADFN 'READ)} will also set it back to {fn READ}. There are two principal differences between {fn TTYINREAD} and {fn READ}: (1) parenthesis balancing. The input does not activate on an exactly balancing right paren/bracket unless the input started with a paren/bracket, e.g., "{lisp USE (FOO) FOR (FIE)}" will all be on one line, terminated by ; and (2) read macros. In Interlisp-10, TTYIN does not use a read table (TTYIN behaves as though using the default initial Lisp terminal input readtable), so read macros and redefinition of syntax characters are not supported; however, " ' " ({fn QUOTE}) and "control-Y" ({fn EVAL}) are built in, and a simple implementation of ? and ?= is supplied. Also, the {var TTYINREADMACROS} facility described below can supply some of the functionality of immediate read macros in the editor. In Interlisp-D, read macros are (mostly) supported. Immediate read macros take effect only if typed at the end of the input (it's not clear what their semantics should be elsewhere). }{End SubSec Using TTYIN for Lisp Input} {Begin SubSec Useful Macros} {Title Useful Macros} {Text There are two useful edit macros that allow you to use TTYIN as a character editor: (1) {editcom ED}{index ED EditCom} loads the current expression into the ttyin buffer to be edited (this is good for editing comments and strings). Input is terminated in the usual way (by typing a balancing right parenthesis at the end of the input, typing at the end of an already balanced expression, or control-X anywhere inside the balanced expression). Typing control-E or clearing the buffer aborts {editcom ED}. (2) {editcom EE}{index EE EditCom} is like {editcom ED} but prettyprints the expression into the buffer, and uses its own window. The variable {var TTYINEDITPROMPT}{index TTYINEDITPROMPT} controls what prompt, if any, {editcom EE} uses; see prompt argument description in next section (the initial setting is no prompt). {editcom EE} is not yet implemented in Interlisp-10. The macro {editcom BUF}{index BUF EditCom} loads the current expression into the buffer, preceded by {lisp E}, to be used as input however desired; as a trivial example, to evaluate the current expression, {editcom BUF} followed by a to activate the buffer will perform roughly what the edit macro {editcom EVAL} does. Of course, you can edit the {lisp E} to something else to make it an edit command. {editcom BUF} is also defined at the executive level as a programmer's assistant command that loads the buffer with the {fn VALUEOF} the indicated event, to be edited as desired. {pacom TV}{index TV Pacom} is a programmer's assistant command like EV [EDITV] that performs an {editcom ED} on the value of the variable. And finally, if the event is considered "short" enough, the programmer's assistant command {pacom FIX} will load the buffer with the event's input, rather than calling the editor. If you really wanted the Interlisp editor for your fix, you could either say {lisp FIX {arg EVENT} - TTY:}, or type control-U (or whatever on tops20) once you got TTYIN's version to force you into the editor. }{End SubSec Useful Macros} {Begin SubSec Programming With TTYIN} {Title Programming With TTYIN} {Text {FnDef {Name TTYIN} {Args PROMPT SPLST HELP OPTIONS ECHOTOFILE TABS UNREADBUF RDTBL} {Text TTYIN prints {arg PROMPT}, then waits for input. The value returned in the normal case is a list of all atoms on the line, with comma and parens returned as individual atoms; {arg OPTIONS} may be used to get a different kind of value back. }} {arg PROMPT} is an atom or string (anything else is converted to a string). If {lisp NIL}, the value of {var DEFAULTPROMPT},{index DEFAULTPROMPT Var} initially {lisp "** "}, will be used. If {arg PROMPT} is {lisp T}, no prompt will be given. {arg PROMPT} may also be a dotted pair {lisp ({arg PROMPT{sub 1}} . {arg PROMPT{sub 2}})}, giving the prompt for the first and subsequent (or overflow) lines, each prompt being a string/atom or {lisp NIL} to denote absence of prompt. Note that rebinding {var DEFAULTPROMPT} gives a convenient way to affect all the "ordinary" prompts in some program module. {arg SPLST} is a spelling list, i.e., a list of atoms or dotted pairs {lisp ({arg SYNONYM} . {arg ROOT})}. If supplied, it is used to check and correct user responses, and to provide completion if the user types ESCAPE. If {arg SPLST} is one of the Lisp system spelling lists (e.g., {var USERWORDS} or {var SPELLINGS3}), words that are escape-completed get moved to the front, just as if a {fn FIXSPELL} had found them. Autocompletion is also performed when user types a break character (cr, space, paren, etc), unless one of the "nofixspell" options below is selected; i.e., if the word just typed would uniquely complete by ESCAPE, TTYIN behaves as though ESCAPE had been typed. {arg HELP}, if non-{lisp NIL}, determines what happens when the user types ? or HELP. If {arg HELP} = {lisp T}, program prints back {arg SPLST} in suitable form. If {arg HELP} is any other atom, or a string containing no spaces, it performs {lisp (DISPLAYHELP {arg HELP})}. Anything else is printed as is. If {arg HELP} is {lisp NIL}, ? and HELP are treated as any other atoms the user types. [{fn DISPLAYHELP}{index DISPLAYHELP Fn} is a user-supplied function, initially a noop; systems with a suitable HASH package, for example, have defined it to display a piece of text from a hashfile associated with the key {lisp HELP}.] {arg OPTIONS} is an atom or list of atoms chosen from among the following: {Begin LabeledList OPTIONS atoms} {Label {lisp NOFIXSPELL}} {Text Uses {arg SPLST} for HELP and Escape completion, but does not attempt any {fn FIXSPELL}ing. Mainly useful if {arg SPLST} is incomplete and the caller wants to handle corrections in a more flexible way than a straight {fn FIXSPELL}. } {Label {lisp MUSTAPPROVE}} {Text Does spelling correction, but requires confirmation. } {Label {lisp CRCOMPLETE}} {Text Requires confirmation on spelling correction, but also does autocompletion on (i.e. if what user has typed so far uniquely identifies a member of {arg SPLST}, completes it). This allows you to have the benefits of autocompletion and still allow new words to be typed. } {Label {lisp DIRECTORY}} {Text (only if {arg SPLST}={lisp NIL}) Interprets Escape to mean directory name completion [Interlisp-10 only]. } {Label {lisp USER}} {Text Like {lisp DIRECTORY}, but does username completion. This is identical to {lisp DIRECTORY} under Tenex [Interlisp-10 only]. } {Label {lisp FILE}} {Text (only if {arg SPLST}={lisp NIL}) Interprets Escape to mean filename completion, i.e. does a {fn GTJFN} [Sumex and Tops20 only]. } {Label {lisp FIX}} {Text If response is not on, or does not correct to, {arg SPLST}, interacts with user until an acceptable response is entered. A blank line (returning {lisp NIL}) is always accepted. Note that if you are willing to accept responses that are not on {arg SPLST}, you probably should specify one of the options {lisp NOXFISPELL}, {lisp MUSTAPPROVE} or {lisp CRCOMPLETE}, lest the user's new response get {fn FIXSPELL}ed away without their approval. } {Label {lisp STRING}} {Text Line is read as a string, rather than list of atoms. Good for free text. } {Label {lisp NORAISE}} {Text Does not convert lower case letters to upper case. } {Label {lisp NOVALUE}} {Text For use principally with the {arg ECHOTOFILE} arg (below). Does not compute a value, but returns {lisp T} if user typed anything, {lisp NIL} if just a blank line. } {Label {lisp REPEAT}} {Text For multi-line input. Repeatedly prompts until user types control-Z (as in Tenex sndmsg). Returns one long list; with {lisp STRING} option returns a single string of everything typed, with carriage returns (EOL) included in the string. } {Label {lisp TEXT}} {Text Implies {lisp REPEAT}, {lisp NORAISE}, and {lisp NOVALUE}. Additionally, input may be terminated with control-V, in which case the global flag {var CTRLVFLG}{index CTRLVFLG Var} will be set true (it is set to {lisp NIL} on any other termination). This flag may be utilized in any way the caller desires. } {Label {lisp COMMAND}} {Text Only the first word on the line is treated as belonging to {arg SPLST}, the remainder of the line being arbitrary text; i.e., "command format". If other options are supplied, {lisp COMMAND} still applies to the first word typed. Basically, it always returns {lisp ({arg CMD} . {arg REST-OF-INPUT})}, where {arg REST-OF-INPUT} is whatever the other options dictate for the remainder. E.g. {lisp COMMAND} {lisp NOVALUE} returns {lisp ({arg CMD})} or {lisp ({arg CMD} . T)}, depending on whether there was further input; {lisp COMMAND} {lisp STRING} returns {lisp ({arg CMD} . "{arg REST-OF-INPUT}")}. When used with {lisp REPEAT}, {lisp COMMAND} is only in effect for the first line typed; furthermore, if the first line consists solely of a command, the {lisp REPEAT} is ignored, i.e., the entire input is taken to be just the command. } {Label {lisp READ}} {Text Parens, brackets, and quotes are treated a la {fn READ}, rather than being returned as individual atoms. Control characters may be input via the control-Vx notation. Input is terminated roughly along the lines of {fn READ} conventions: a balancing or over-balancing right paren/bracket will activate the input, or when no parenthesis remains unbalanced. {lisp READ} overrides all other options (except {lisp NORAISE}). } {Label {lisp LISPXREAD}} {Text Like {lisp READ}, but implies that TTYIN should behave even more like {fn READ}, i.e., do {lisp NORAISE}, not be errorset-protected, etc. } {Label {lisp NOPROMPT}} {Text Interlisp-D only: The prompt argument is treated as usual, except that TTYIN assumes that the prompt for the first line has already been printed by the caller; the prompt for the first line is thus used only when redisplaying the line. } {End LabeledList OPTIONS atoms} {arg ECHOTOFILE} if specified, user's input is copied to this file, i.e., TTYIN can be used as a simple text-to-file routine if {lisp NOVALUE} is used. If {arg ECHOTOFILE} is a list, copies to all files in the list. {arg PROMPT} is not included on the file. {arg TABS} is a special addition for tabular input. It is a list of tabstops (numbers). When user types a tab, TTYIN automatically spaces over to the next tabstop (thus the first tabstop is actually the second "column" of input). Also treats specially the characters * and "; they echo normally, and then automatically tab over. {arg UNREADBUF} allows the caller to "preload" the TTYIN buffer with a line of input. {arg UNREADBUF} is a list, the elements of which are unread into the buffer (i.e., "the outer parentheses are stripped off") to be edited further as desired; a simple (or control-Z for {lisp REPEAT} input) will thus cause the buffer's contents to be returned unchanged. If doing {fn READ} input, the "{fn PRIN2} names" of the input list are used, i.e., quotes and %'s will appear as needed; otherwise the buffer will look as though {arg UNREADBUF} had been {fn PRIN1}'ed. {arg UNREADBUF} is treated somewhat like {var READBUF}, so that if it contains a pseudo-carriage return (the value of {var HISTSTR0}), the input line terminates there. Input can also be unread from a file, using the {var HISTSTR1}{index HISTSTR1 Var} format: {arg UNREADBUF} = {lisp ({arg } ({arg FILE} {arg START} . {arg END}))}, where {arg START} and {arg END} are file byte pointers. This makes TTYIN a miniature text file editor. {arg RDTBL} [Interlisp-D only] is the read table to use for {fn READ}ing the input when one of the {lisp READ} options is given. A lot of character interpretations are hardwired into TTYIN, so currently the only effect this has is in the actual {fn READ}, and in deciding whether a character typed at the end of the input is an immediate read macro, for purposes of termination. If the global variable {var TYPEAHEADFLG}{index TYPEAHEADFLG Var} is {lisp T}, or option {lisp LISPXREAD} is given, TTYIN permits type-ahead; otherwise it clears the buffer before prompting the user. }{End SubSec Programming With TTYIN} {Begin SubSec EE Interface} {Title EE Interface} {Text The following may be useful as a way of outsiders to call TTYIN as an editor. These functions are currently only in Interlisp-D. {FnDef {Name TTYINEDIT} {Args EXPRS WINDOW PRINTFN} {Text This is the body of {editcom EE}. Switches the tty to {arg WINDOW}, clears it, prettyprints {arg EXPRS}, a list of expressions, into it, and leaves you in TTYIN to edit it as Lisp input. Returns a new list of expressions. If {arg PRINTFN} is non-{lisp NIL}, it is a function of two arguments, {arg EXPRS} and {arg FILE}, which is called instead of {fn PRETTYPRINT} to print the expressions to the window (actually a scratch file). Note that {arg EXPRS} is a list, so normally the outer parentheses should not be printed. {arg PRINTFN}=T is shorthand for "unpretty"; use {fn PRIN2} instead of {fn PRETTYPRINT}. }} {VarDef {Name TTYINAUTOCLOSEFLG} {Text If {var TTYINAUTOCLOSEFLG} is true, {fn TTYINEDIT} closes the window on exit. }} {VarDef {Name TTYINEDITWINDOW} {Text If the {arg WINDOW} arg to {fn TTYINEDIT} is {lisp NIL}, it uses the value of {var TTYINEDITWINDOW}, creating it if it does not yet exist. }} {VarDef {Name TTYINPRINTFN} {Text The default value for {arg PRINTFN} in {editcom EE}'s call to {fn TTYINEDIT}. }} {FnDef {Name SET.TTYINEDIT.WINDOW} {Args WINDOW} {Text Called under a {fn RESETLST}. Switches the tty to {arg WINDOW} (defaulted as in {fn TTYINEDIT}) and clears it. The window's position is left so that TTYIN will be happy with it if you now call TTYIN yourself. Specifically, this means positioning an integral number of lines from the bottom of the window, the way the top-level tty window normally is. }} {FnDef {Name TTYIN.SCRATCHFILE} {Args} {Text Returns, possibly creating, the scratchfile that TTYIN uses for prettyprinting its input. The file pointer is set to zero. Since TTYIN does use this file, beware of multiple simultaneous use of the file. }} }{End SubSec EE Interface} {Begin SubSec ?= Handler} {Title ?= Handler} {Text In Interlisp, the ?= read macro displays the arguments to the function currently "in progress" in the typein. Since TTYIN wants you to be able to continue editing the buffer after a ?=, it processes this macro specially on its own, printing the arguments below your typein and then putting the cursor back where it was when ?= was typed. For users who want special treatment of ?=, the following hook exists: {VarDef {Name TTYIN?=FN} {Text The value of this variable, if non-{lisp NIL}, is a user function of one argument that is called when ?= is typed. The argument is the function that ?= thinks it is inside of. The user function should return one of the following: {Begin LabeledList TTYIN?=FN function should return one of the following} {Indent 10percent} {Label {lisp NIL}} {Text Normal ?= processing is performed. } {Label {lisp T}} {Text Nothing is done. Presumably the user function has done something privately, perhaps diddled some other window, or called {fn TTYIN.PRINTARGS} (below). } {Label a list {lisp (ARGS . {arg STUFF})}} {Text Treats {arg STUFF} as the argument list of the function in question, and performs the normal ?= processing using it. } {Label anything else} {Text The value is printed in lieu of what ?= normally prints. } {End LabeledList TTYIN?=FN function should return one of the following} }} At the time that ?= is typed, nothing has been "read" yet, so you don't have the normal context you might expect inside a conventional readmacro. If the user function wants to examine the typed-in arguments being passed to the fn, however, it can perform {lisp (TTYIN.READ?=ARGS)},{index TTYIN.READ?=ARGS Fn} which bundles up everything between the function and the typing of ?= into a list, which it returns (thus it parallels an arglist; {lisp NIL} if ?= was typed immediately after the function name). {FnDef {Name TTYIN.PRINTARGS} {Args FN ARGS ACTUALS ARGTYPE} {Text Does the function/argument printing for ?=. {arg ARGS} is an argument list, {arg ACTUALS} is a list of actual parameters (from the typein) to match up with args. {arg ARGTYPE} is a value of the function {fn ARGTYPE}; it defaults to {lisp (ARGTYPE {arg FN})}. }} }{End SubSec ?= Handler} {Begin SubSec Read Macros} {Title Read Macros} {Text When doing {fn READ} input in Interlisp-10, no Lisp-style read macros are available (but the ' and control-Y macros are built in). Principally because of the usefulness of the editor read macros (set by {fn SETTERMCHARS}), and the desire for a way of changing the meanings of the display editing commands, the following exists as a hack: {VarDef {Name TTYINREADMACROS} {Text Value is a set of shorthand inputs useable during {fn READ} input. It is an alist of entries {lisp ({arg CHARCODE} . {arg SYNONYM})}. If the user types the indicated character (edit bit is denoted by the 200Q bit in charcode), TTYIN behaves as though the synonym character had been typed. Special cases: 0 - the character is ignored; 200Q - pure Edit bit; means to read another char and turn on its edit bit; 400Q - macro quote: read another char and use its original meaning. For example, if you have macros ((33Q . 200Q) (30Q . 33Q)), then Escape (33Q) will behave as an edit prefix, and control-X (30Q) will behave like Escape. Note: currently, synonyms for edit commands are not well-supported, working only when the command is typed with no argument. Slightly more powerful macros also can be supplied; they are recognized when a character is typed on an empty line, i.e., as the first thing after the prompt. In this case, the {Var TTYINREADMACROS} entry is of the form {lisp ({arg CHARCODE} T . {arg RESPONSE})} or {lisp ({arg CHARCODE} {arg CONDITION} . {arg RESPONSE})}, where {arg CONDITION} is a list that evaluates true. If {arg RESPONSE} is a list, it is {fn EVAL}ed; otherwise it is left unevaluated. The result of this evaluation (or {arg RESPONSE} itself) is treated as follows: {Begin LabeledList result of this evaluation} {Indent 10percent} {Label {lisp NIL}} {Text The macro is ignored and the character reads normally, i.e., as though {var TTYINREADMACROS} had never existed. } {Label An integer} {Text A character code, treated as above. Special case: -1 is treated like 0, but says that the display may have been altered in the evaluation of the macro, so TTYIN should reset itself appropriately. } {Label Anything else} {Text This TTYIN input is terminated (with a crlf) and returns the value of "response" (turned into a list if necessary). This is the principal use of this facility. The macro character thus stands for the (possibly computed) reponse, terminated if necessary with a crlf. The original character is not echoed. } {End LabeledList result of this evaluation} }} Interrupt characters, of course, cannot be read macros, as TTYIN never sees them, but any other characters, even non-control chars, are allowed. The ability to return {lisp NIL} allows you to have conditional macros that only apply in specified situations (e.g., the macro might check the prompt {lisp (LISPXID)} or other contextual variables). To use this specifically to do immediate editor read macros, do the following for each edit command and character you want to invoke it with: {lisp (ADDTOVAR TTYINREADMACROS ({arg CHARCODE} 'CHARMACRO? {arg EDITCOM})))} For example, {lisp (ADDTOVAR TTYINREADMACROS (12Q CHARMACRO? !NX))} will make linefeed do the {editcom !NX} command. Note that this will only activate linefeed at the beginning of a line, not anywhere in the line. There will probably be a user function to do this in the next release. Note that putting {lisp (12Q T . !NX)} on {var TTYINREADMACROS} would also have the effect of returning {lisp "!NX"} from the {fn READ} call so that the editor would do an {editcom !NX}. However, TTYIN would also return {lisp !NX} outside the editor (probably resulting in a u.b.a. error, or convincing DWIM to enter the editor), and also the clearing of the output buffer (performed by {lisp CHARMACRO}?) would not happen. }{End SubSec Read Macros} {Begin SubSec Assorted Flags} {Title Assorted Flags} {Text These flags control aspects of TTYIN's behavior. Some have already been mentioned. Their initial values are all {lisp NIL}. In Interlisp-D, the flags are all initially {lisp T}. {VarDef {Name TYPEAHEADFLG} {Text If true, TTYIN always permits typeahead; otherwise it clears the buffer for any but {fn LISPXREAD} input. }} {VarDef {Name ?ACTIVATEFLG} {Text If true, enables the feature whereby ? lists alternative completions from the current spelling list. }} {VarDef {Name EMACSFLG} {Text Affects display editing. When true, TTYIN tries to behave a little more like EMACS (in very simple ways) than TVEDIT. Specifically, it has the following effects currently: (1) all non-edit characters self-insert (i.e. behave as if you're always in Insert mode); (2) [D] is the EMACS delete to end of word command. }} {VarDef {Name SHOWPARENFLG} {Text If true, then whenever you are typing Lisp input and type a right parenthesis/bracket, TTYIN will briefly move the cursor to the matching parenthesis/bracket, assuming it is still on the screen. The cursor stays there for about 1 second, or until you type another character (i.e., if you type fast you'll never notice it). This feature was inspired by a similar EMACS feature, and turned out to be pretty easy to implement. }} {VarDef {Name TTYINBSFLG} {Text Causes TTYIN to always physically backspace, even if you're running on a non-display (not a DM or Heath), rather than print \deletedtext\ (this assumes your hardcopy terminal or glass tty is capable of backspacing). If TTYINBSFLG is LF, then in addition to backspacing, TTYIN x's out the deleted characters as it backs up, and when you stop deleting, it outputs a linefeed to drop to a new, clean line before resuming. To save paper, this linefeed operation is not done when only a single character is deleted, on the grounds that you can probably figure out what you typed anyway. }} {VarDef {Name TTYINRESPONSES} {Text An alist of special responses that will be handled by routines designated by the programmer. See "Special Responses", below. }} {VarDef {Name TTYINERRORSETFLG} {Text [Interlisp-D only] If true, non-{fn LISPXREAD} inputs are errorset-protected (control-E traps back to the prompt), otherwise errors propagate upwards. Initially {lisp NIL}. }} {VarDef {Name TTYINMAILFLG} {Text [Tenex only] When true, performs mail checking, etc. before most inputs (except EVALQT inputs, where it is assumed this has already been done, or inputs indented by more than a few spaces). The {lisp MAILWATCH} package must be loaded for this. }} {VarDef {Name TTYINCOMPLETEFLG} {Text If true, enables Escape completion from {var USERWORDS} during READ inputs. Details below. }} {var USERWORDS} ({PageRef Var USERWORDS}) contains words you mentioned recently: functions you have defined or edited, variables you have set or evaluated at the executive level, etc. This happens to be a very convenient list for context-free escape completion; if you have recently edited a function, chances are good you may want to edit it again (typing "EF xx$") or type a call to it. If there is no completion for the current word from {var USERWORDS}, the escape echoes as "$", i.e. nothing special happens; if there is more than one possible completion, you get beeped. If typed when not inside a word, Escape completes to the value of {var LASTWORD}, i.e., the last thing you typed that the p.a. "noticed" (setting {var TTYINCOMPLETEFLG} to 0 disables this latter feature), except that Escape at the beginning of the line is left alone (it is a p.a. command). If you really wanted to enter an escape, you can, of course, just quote it with a control-V, like you can other control chars. You may explicitly add words to {var USERWORDS} yourself that wouldn't get there otherwise. To make this convenient online the edit command [_] means "add the current atom to {var USERWORDS}" (you might think of the command as "pointing out this atom"). For example, you might be entering a function definition and want to "point to" one or more of its arguments or prog variables. Giving an argument of zero to this command will instead remove the indicated atom from {var USERWORDS}. Note that this feature loses some of its value if the spelling list is too long, for then the completion takes too long computationally and, more important, there are too many alternative completions for you to get by with typing a few characters followed by escape. Lisp's maintenance of the spelling list {var USERWORDS} keeps the "temporary" section (which is where everything goes initially unless you say otherwise) limited to {var #USERWORDS} atoms, initially 100. Words fall off the end if they haven't been used (they are "used" if {fn FIXSPELL} corrects to one, or you use to complete one). }{End SubSec Assorted Flags} {Begin SubSec Special Responses} {Title Special Responses} {Text There is a facility for handling "special responses" during any non-{fn READ} TTYIN input. This action is independent of the particular call to TTYIN, and exists to allow you to effectively "advise" TTYIN to intercept certain commands. After the command is processed, control returns to the original TTYIN call. The facility is implemented via the list {var TTYINRESPONSES}. {VarDef {Name TTYINRESPONSES} {Text {var TTYINRESPONSES} is a list of elements, each of the form: {lisp ({arg COMMANDS} {arg RESPONSE-FORM} {arg OPTION})} {arg COMMANDS} is a single atom or list of commands to be recognized; {arg RESPONSE-FORM} is {fn EVAL}ed (if a list), or {fn APPLY}ed (if an atom) to the command and the rest of the line. Within this form one can reference the free variables {var COMMAND}{index COMMAND Var} (the command the user typed) and {var LINE}{index LINE Var} (the rest of the line). If {arg OPTION} is the atom {lisp LINE}, this means to pass the rest of line as a list; if it is {lisp STRING}, this means to pass it as a string; otherwise, the command is only valid if there is nothing else on the line. If {arg RESPONSE-FORM} returns the atom {atom IGNORE},{index IGNORE Litatom} it is not treated as a special response (i.e. the input is returned normally as the result of TTYIN). }} In MYCIN, the {lisp COMMENT} command is handled this way; any time the user types {lisp COMMENT} as the first word of input, TTYIN passes the rest of the line to a mycin-defined function which prompts for the text of the comment (recursively using TTYIN with the {lisp TEXT} option). When control returns, TTYIN goes back and prompts for the original input again. The {var TTYINRESPONSES} entry for this is {lisp (COMMENT (GRIPE LINE) LIST)}; {lisp GRIPE} is a MYCIN function of one argument (the one-line comment, or {lisp NIL} for extended comments). Suggested use: global commands or options can be added to the toplevel value of {var TTYINRESPONSES}. For more specialized commands, rebind {var TTYINRESPONSES} to {lisp (APPEND {arg NEWENTRIES} TTYINRESPONSES)} inside any module where you want to do this sort of special processing. Special responses are not checked for during {fn READ}-style input. }{End SubSec Special Responses} {Begin SubSec Display Types} {Title Display Types} {Text [This is not relevant in Interlisp-D] TTYIN determines the type of display by calling {fn DISPLAYTERMP}, which is initially defined to test the value of the {lisp GTTYP} jsys. It returns either {lisp NIL} (for printing terminals) or a small number giving TTYIN's internal code for the terminal type. The types TTYIN currently knows about: 0 = glass tty (capable of deleting chars by backspacing, but little else); 1 = Datamedia; 2 = Heath. Only the Datamedia has full editing power. {fn DISPLAYTERMP} has built into it the correct terminal types for Sumex and Stanford campus 20's: Datamedia = 11 on tenex, 5 on tops20; Heath = 18 on Tenex, 25 on tops20. You can override those values by setting the variable {var DISPLAYTYPES}{index DISPLAYTYPES Var} to be an alist associating the {lisp GTTYP} value with one of these internal codes. For example, Sumex displays correspond to {var DISPLAYTYPES} = {lisp ((11 . 1) (18 . 2))} [although this is actually compiled into {fn DISPLAYTERMP} for speed]. Any display terminal other than Datamedia and Heath can probably safely be assigned to "0" for glass tty. To add new terminal types, you have to choose a number for it, add new code to TTYIN for it and recompile. The TTYIN code specifies what the capabilities of the terminal are, and how to do the primitive operations: up, down, left, right, address cursor, erase screen, erase to end of line, insert character, etc. For terminals lacking an Edit key (currently only Datamedias have it), set the variable {var EDITPREFIXCHAR} to the ascii code of an Edit "prefix" (i.e. anything typed preceded by the prefix is considered to have the edit bit on). If your {var EDITPREFIXCHAR} is 33Q (Escape), you can type a real Escape by typing 3 of them (2 won't do, since that means "Edit-Escape", a legitimate argument to another command). You could also define an Escape synonym with {var TTYINREADMACROS} if you wanted (but currently it doesn't work in filename completion). Setting {var EDITPREFIXCHAR} for a terminal that is not equipped to handle the full range of editing functions (only the Heath and Datamedia are currently so equipped) is not guaranteed to work, i.e. the display will not always be up to date; but if you can keep track of what you're doing, together with an occasional control-R to help out, go right ahead. }{End SubSec Display Types} {index *END* TTYIN FN} }{End SubSec The TTYIN Display Typein Editor}