One of the most powerful words in CamelForth is the line input routine, ACCEPT which goes beyond the requirements of the ANS definition, allowing such things as automatic filename replacement (by collecting mail from the Filer for example).
The following editing keys are provided in the standard ACCEPT routine:
By specifying the length of the input buffer as negative, ACCEPT will use the current contents of the buffer as the initial input, placing the cursor after the last non-space character. Try this as an example:
PAD 80 BLANK S" edit me" PAD SWAP CMOVE PAD -80 ACCEPT
The deferred word (ACC_EVT) is executed whenever a key event occurs that is not normally handled by ACCEPT. It is normally used to implement application command codes, together with its equivalent for KEY, (KEY) - see the example application, Puzzle Of The Pyramid for details.
You can also use this word to extend ACCEPTs editing facilities, by manipulating the stack contents. You should be careful to ensure that the screen properly reflects your changes, using characters 8 and 9 to properly reposition the cursor. The stack effects should be:
(ACC_EVT) ( maxlen curlen addr pos eventcode -- maxlen curlen' addr pos' )
For example, the following will replace the character under the cursor with an asterisk if you press the TAB key, and beep for all other unhandled events:
: MYHANDLER 9 = IF 2DUP + [CHAR] * SWAP C! [CHAR] * EMIT 8 EMIT ELSE 7 EMIT THEN ; ' MYHANDLER IS (ACC_EVT)
The default word for (ACC_EVT) is DROP which effectively silently discards the event code.
A second deferred word, (ACC_MAIL) is executed firstly when ACCEPT starts, and then on every occasion that the application may have been preempted. As it's name implies, this is intended mainly to allow any new mail received to be placed in the buffer, but you could use it for other purposes. The stack effects for this word should be:
(ACC_MAIL) ( maxlen curlen addr pos -- maxlen curlen' addr pos' )
A typical example, which replaces the current input with any filename passed in NAME-type mail is shown below. Because the name is null-terminated we have to first remove the null, and also ensure that it doesn't overflow the buffer. To properly update the screen, we first move the cursor to the start of the input by moving back by pos characters, overwrite the current input with curlen spaces, and move back again with curlen back characters, before finally typing out the received mail string:
: MYMAIL 0" NAME" CHECKMAIL IF 1- 2>R 0 ?DO 8 EMIT LOOP OVER 0 ?DO SPACE LOOP SWAP 0 ?DO 8 EMIT LOOP OVER 2R> ROT UMIN 2DUP TYPE >R OVER R@ CMOVE R> TUCK THEN ; ' MYMAIL IS (ACC_MAIL)
The default word for (ACC_MAIL) is NOOP which does nothing.
A character-sized variable INACC? is available to determine whether the current input word is ACCEPT or not. This variable is properly nested, and is set to false when (ACC_EVT) is executed, to ensure it is valid if this invokes a further input word. Note that if you enable escape detection, and (RC_ESC) invokes another input word or THROWs an exception, you should ensure this variable is properly updated yourself.
The main use for this variable is to allow redraw words to automatically retype the current line being edited, repositioning the cursor correctly. When (RC_DRAW) executes and the variable is set, the current input parameters can be found below 7 (indeterminate) items. The following code is suitable to incorporate into your redraw facility:
: MYREDRAW drawstuff / re-draws everything except input line INACC? C@ IF 2>R 2>R 2>R >R / punt 7 unwanted items to return stack >R 2DUP SWAP TYPE OVER R@ - 0 ?DO 8 CEMIT LOOP R> R> 2R> 2R> 2R> THEN ;
More about CamelForth
Back to the Z88 home page