An input editing stream "encapsulates" an interactive stream. That is, most operations are handled by the encapsulated interactive stream, but some operations are handled directly by the input editing stream itself. (See Appendix D: Common Lisp Streams for a discussion of encapsulating streams.)
An input editing stream has the following components:
The input editor reads either "real" gestures from the user (such as characters from the keyboard or pointer button events) or input editing commands, which can modify the state of the input buffer. When they do so, the input buffer must be "rescanned"; that is, the scan pointer sp must be reset to its original state, and the contents of the input editor buffer must be reparsed before any other gestures from the user are read. While this rescanning operation is taking place, the "rescan in progress" flag is set to t
. The relationship sp ≤ ip ≤ fp always holds.
The overall control structure of the input editor is:
(catch 'rescan ;thrown to when a rescan is invoked (reset-scan-pointer stream) ;sets STREAM-RESCANNING-P to T (loop (funcall continuation stream)))
where stream is the input editing stream and continuation is the code supplied by the programmer, which typically contains calls to such functions as accept and read-token (which will eventually call stream-read-gesture). When a rescan operation is invoked, it throws to the rescan
tag in the previous example. The loop is terminated when an activation gesture is seen, and at that point the values produced by continuation are returned as values from the input editor.
The important point is that functions such as accept, read-gesture, and unread-gesture read (or restore) the next gesture object from the buffer at the position pointed to by the scan pointer sp. However, insertion and input editing commands take place at the position pointed to by ip. The purpose of the rescanning operation is to ensure that all the input gestures issued by the user (typed characters, pointer button presses, and so forth) have been read by CLIM. During input editing, the input editor maintains some sort of visible cursor to remind the user of the position of ip.
The overall structure of stream-read-gesture on an input editing stream is:
(progn (rescan-if-necessary stream) (loop ;; If SP is less than FP ;; Then get the next gesture from the input editor buffer at SP ;; and increment SP ;; Else read the next gesture from the encapsulated stream ;; and insert it into the buffer at IP ;; Set the "rescan in progress" flag to false ;; Call STREAM-PROCESS-GESTURE on the gesture ;; If it was a "real" gesture ;; Then exit with the gesture as the result ;; Else it was an input editing command (which has already been ;; processed), so continue looping ))
A new gesture object is inserted into the input editor buffer at the insertion pointer ip. If ip = fp, this is accomplished by a vector-push-extend-like operation on the input buffer and fp, and then incrementing ip. If ip < fp, CLIM must first "make room" for the new gesture in the input buffer, then insert the gesture at ip, and finally increment both ip and fp.
When the user requests an input editor motion command, only the insertion pointer ip is affected. Motion commands do not need to request a rescan operation.
When the user requests an input editor deletion command, the sequence of gesture objects at ip is removed, and ip and fp must be modified to reflect the new state of the input buffer. Deletion commands (and other commands that modify the input buffer) must call immediate-rescan when they are done modifying the buffer.
CLIM is free to put special objects in the input editor buffer, such as "noise strings" and "accept results." A "noise string" is used to represent some sort of in-line prompt and is never seen as input; the prompt-for-accept method may insert a noise string into the input buffer. An "accept result" is an object in the input buffer that is used to represent some object that was inserted into the input buffer (typically via a pointer gesture) that has no readable representation (in the Lisp sense); presentation-replace-input may create accept results. Noise strings are skipped over by input editing commands, and accept results are treated as a single gesture.
See 16.7 Advanced Topics for an in-depth discussion of the input editing stream protocol.
interactive-stream-p Generic Function
interactive-stream-p object
Summary: Returns t
if object is an interactive stream, that is, a bidirectional stream intended for user interactions. Otherwise it returns nil
. This is exactly the same function as in X3J13 Common Lisp, except that in CLIM it is a generic function.
The input editor is only fully implemented for interactive streams.
input-editing-stream Protocol Class
Summary: The protocol class that corresponds to an input editing stream. If you want to create a new class that behaves like an input editing stream, it should be a subclass of input-editing-stream
. Subclasses of input-editing-stream
must obey the input editing stream protocol.
input-editing-stream-p Function
input-editing-stream-p object
Summary: Returns t
if object is an input editing stream (that is, a stream of the sort created by a call to with-input-editing), otherwise returns nil
.
standard-input-editing-stream Class
Summary: The class that implements CLIM's standard input editor. This is the class of stream created by calling with-input-editing.
Members of this class are mutable.
with-input-editing (&optional stream &key input-sensitizer initial-contents) &body body
Summary: Establishes a context in which the user can edit the input typed in on the interactive stream stream. body is then executed in this context, and the values returned by body are returned as the values of with-input-editing
. body may have zero or more declarations as its first forms.
The stream argument is not evaluated, and must be a symbol that is bound to an input stream. If stream is t
(the default), *query-io* is used. If stream is a stream that is not an interactive stream, then with-input-editing
is equivalent to progn.
input-sensitizer, if supplied, is a function of two arguments, a stream and a continuation function; the function has dynamic extent. The continuation, supplied by CLIM, is responsible for displaying output corresponding to the user's input on the stream. The input-sensitizer function will typically call with-output-as-presentation in order to make the output produced by the continuation sensitive.
If initial-contents is supplied, it must be either a string or a list of two elements, an object and a presentation type. If it is a string, it will be inserted into the input buffer using replace-input. If it is a list, the printed representation of the object will be inserted into the input buffer using presentation-replace-input.
with-input-editor-typeout Macro
with-input-editor-typeout (&optional stream) &body body
Summary: Establishes a context inside of with-input-editing in which output can be done by body to the input editing stream stream. with-input-editor-typeout
should call fresh-line before and after evaluating the body. body may have zero or more declarations as its first forms.
The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t
(the default), *query-io* is used. If stream is a stream that is not an input editing stream, then with-input-editor-typeout
is equivalent to calling fresh-line, evaluating the body, and then calling fresh-line again.
Keyboard input to accept can be edited until an activation keystroke is typed to terminate it. If the input cannot be parsed after an activation keystroke is entered, it must be edited and re-activated. The input editor has several keystroke commands, as listed in Input Editor Keystroke Commands . Prefix numeric arguments to input editor commands can be entered using digits and the minus sign (-) with CONTROL
and META
(as in Emacs).
The function :add-input-editor-command
can be used to bind one or more keys to an input editor command. Any keystroke can be an input editor command, but by convention only keystrokes that do not correspond to graphic characters should be used.
The input also supports "numeric arguments" (such as C-0
, C-1
, M-0
, etc.) that modify the behavior of the input editing commands. For instance, the motion and deletion commands will be repeated as many times as specified by the numeric argument. Furthermore, the accumulated numeric argument will be passed to the command processor in such a way that substitute-numerical-marker
can be used to insert the numeric argument into a command that was read via a keystroke accelerator.
CLIM 2.0 User Guide - 01 Dec 2021 19:39:00