| Presentation Types | Contents | Index | Menu Facilities |
24 Input Editing and Completion Facilities
CLIM provides number of facilities to assist in writing presentation type parser
functions, such as an interactive input editor and some ``completion''
facilities.
24.1 The Input Editor
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 Encapsulating Streams for a discussion of encapsulating streams.)
An input editing stream will have the following components:
The high level description of the operation of the input editor is that it reads either ``real'' gestures from the user (such as characters from the keyboard or pointer button events) or input editing commands. The input editing commands can modify the state of the input buffer. When such modifications take place, it is necessary to ``rescan'' the input buffer, that is, reset the scan pointer SP to its original state and reparse the contents of the input editor buffer before reading any other gestures from the user. While this rescanning operation is taking place, the ``rescan in progress'' flag is set to true . 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, and 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 has the
effect of throwing to the rescan tag in the example above. 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 eventually 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 should maintain 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
))
When a new gesture object is inserted into the input editor buffer, it is
inserted 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, then 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 are 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 arrange for a rescan to occur when they are done modifying the buffer, either by calling queue-rescan or immediate-rescan .
CLIM implementations are 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.
| interactive-stream-p | object | [Predicate] |
The input editor need only be fully implemented for interactive streams.
| input-editing-stream | [Protocol Class] |
| input-editing-stream-p | object | [Predicate] |
| standard-input-editing-stream | [Class] |
Members of this class are mutable.
| with-input-editing | (&optional stream &key input-sensitizer initial-contents class) &body body | [Macro] |
The stream argument is not evaluated, and must be a symbol that is bound to an input stream. If stream is t (the default), *standard-input* 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, the string 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 | (&optional stream &key erase) &body body | [Macro] |
The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-input* 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.
| input-editor-format | stream format-string &rest format-args | [Generic function] |
If stream is a stream that is not an input editing stream, then input-editor-format is equivalent to format .
24.1.1 The Input Editing Stream Protocol
Input editing streams obey both the extended input and extended output stream
protocols, and must support the generic functions that comprise those protocols.
For the most part, this will simply entail ``trampolining'' those operations to
the encapsulated interactive stream. However, some generic functions as
stream-read-gesture and stream-unread-gesture will need methods that
observe the use of the input editor's scan pointer.
Input editing streams will typically also implement methods for prompt-for-accept (in order to provide in-line prompting that interacts correctly with input editing) and stream-accept (in order to cause accept to obey the scan pointer).
The following generic functions comprise the remainder of the input editing protocol, and must be implemented for all classes that inherit from input-editing-stream .
| stream-input-buffer | (stream input-editing-stream ) | [Method] |
| stream-insertion-pointer | stream | [Generic function] |
| (setf stream-insertion-pointer) | pointer stream | [Generic function] |
| stream-scan-pointer | stream | [Generic function] |
| (setf stream-scan-pointer) | pointer stream | [Generic function] |
| stream-rescanning-p | stream | [Generic function] |
| reset-scan-pointer | stream &optional (scan-pointer 0 ) | [Generic function] |
| immediate-rescan | stream | [Generic function] |
| queue-rescan | stream | [Generic function] |
| rescan-if-necessary | stream &optional inhibit-activation | [Generic function] |
If inhibit-activation is false , the input line will not be activated even if there is an activation character in it.
| erase-input-buffer | stream &optional (start-position 0 ) | [Generic function] |
| redraw-input-buffer | stream &optional (start-position 0 ) | [Generic function] |
| stream-process-gesture | stream gesture type | [Generic function] |
| stream-read-gesture | (stream standard-input-editing-stream ) &key | [Method] |
The stream-read-gesture method must call stream-process-gesture , which will either return a ``real'' gesture (such as a typed character, a pointer gesture, or a timeout) or will return nil (indicating that some sort of input editing operation was performed). stream-read-gesture must only return when a real gesture was been read; if an input editing operation was performed, stream-read-gesture will loop until a ``real'' gesture is typed by the user.
| stream-unread-gesture | (stream standard-input-editing-stream ) gesture | [Method] |
24.1.2 Suggestions for Input Editing Commands
An implementation of the input editor should provide a set of generally useful
input editing commands. The exact set of these commands is unspecified, and the
key bindings for these commands may vary from platform to platform. The
following is a suggested minimum set of input editing commands and key bindings,
taken roughly from EMACS.
| | | | | |||
| | | | | | | | |
| | | | | | | | |
| | | | | |||
| | | Forward character | | | control-F | | |
| | | Forward word | | | meta-F | | |
| | | Backward character | | | control-B | | |
| | | Backward word | | | meta-B | | |
| | | Beginning of line | | | control-A | | |
| | | End of line | | | control-E | | |
| | | Next line | | | control-N | | |
| | | Previous line | | | control-P | | |
| | | Beginning of buffer | | | meta-< | | |
| | | End of buffer | | | meta-< | | |
| | | Delete next character | | | control-D | | |
| | | Delete next word | | | meta-D | | |
| | | Delete previous character | | | Rubout | | |
| | | Delete previous word | | | m-Rubout | | |
| | | Kill to end of line | | | control-K | | |
| | | Clear input buffer | | | varies | | |
| | | Insert new line | | | control-O | | |
| | | Transpose adjacent characters | | | control-T | | |
| | | Transpose adjacent words | | | meta-T | | |
| | | Yank from kill ring | | | control-Y | | |
| | | Yank from presentation history | | | control-meta-Y | | |
| | | Yank next item | | | meta-Y | | |
| | | Scroll output history forward | | | control-V | | |
| | | Scroll output history backward | | | meta-V | | |
| | | | | |||
| add-input-editor-command | gestures function | [Function] |
24.2 Activation and Delimiter Gestures
Activation gestures terminate an input ``sentence'', such as a command or
anything else being read by accept . When an activation gesture is entered
by the user, CLIM will cease reading input and ``execute'' the input that has
been entered.
Delimiter gestures terminate an input ``word'', such as a recursive call to accept .
| *activation-gestures* | [Variable] |
| *standard-activation-gestures* | [Variable] |
| with-activation-gestures | (gestures &key override) &body body | [Macro] |
If the boolean override is true , then gestures will override the current activation gestures. If it is false (the default), then gestures will be added to the existing set of activation gestures. with-activation-gestures must bind *activation-gestures* to the new set of activation gestures.
See also the :activation-gestures and :additional-activation-gestures options to accept .
| activation-gesture-p | gesture | [Function] |
| *delimiter-gestures* | [Variable] |
| with-delimiter-gestures | (gestures &key override) &body body | [Macro] |
If the boolean override is true , then gestures will override the current delimiter gestures. If it is false (the default), then gestures will be added to the existing set of delimiter gestures. with-delimiter-gestures must bind *delimiter-gestures* to the new set of delimiter gestures.
See also the :delimiter-gestures and :additional-delimiter-gestures options to accept .
| delimiter-gesture-p | gesture | [Function] |
24.3 Signalling Errors Inside present Methods
| simple-parse-error | [Error] |
This condition handles two initargs, :format-string and :format-arguments , which are used to specify a control string and arguments for a call to format .
| simple-parse-error | format-string &rest format-arguments | [Function] |
| input-not-of-required-type | [Error] |
This condition handles two initargs, :string and :type , which specify a string to be used in an error message and the expected presentation type.
| input-not-of-required-type | object type | [Function] |
24.4 Reading and Writing of Tokens
| replace-input | stream new-input &key start end buffer-start rescan | [Generic function] |
replace-input must queue a rescan by calling queue-rescan if the new input does not match the old input, or rescan is true .
The returned value is the position in the input buffer.
All input editing streams must implement a method for this function.
| presentation-replace-input | stream object type view &key buffer-start rescan query-identifier for-context-type | [Generic function] |
All input editing streams must implement a method for this function. Typically, this will be implemented by calling present-to-string on object , type , view , and for-context-type , and then calling replace-input on the resulting string.
If the object does not have a readable representation (in the Lisp sense), presentation-replace-input may create an ``accept result'' to represent the object, and insert that into the input buffer. For the purposes of input editing, ``accept results'' must be treated as a single input gesture.
| read-token | stream &key input-wait-handler pointer-button-press-handler click-only | [Function] |
If the first character of typed input is a quotation mark (
If the boolean click-only is true , then no keyboard input is allowed. In this case read-token will simply ignore any typed characters.
input-wait-handler and pointer-button-press-handler are as for stream-read-gesture .
| write-token | token stream &key acceptably | [Function] |
Typically, present methods will use write-token instead of write-string .
24.5 Completion
CLIM provides a completion facility that completes a string provided
by a user against some set of possible completions (which are themselves
strings). Each completion is associated with some Lisp object. CLIM
implementations are encouraged to provide ``chunkwise'' completion, that is, if
the user input consists of several tokens separated by ``partial delimiters'',
CLIM should complete each token separately against the set of possibilities.
| *completion-gestures* | [Variable] |
| *help-gestures* | [Variable] |
| *possibilities-gestures* | [Variable] |
| complete-input | stream function &key partial-completers allow-any-input possibility-printer (help-displays-possibilities t) | [Function] |
function is a function of two arguments. It is called to generate the completion possibilities that match the user's input; it has dynamic extent. Usually, programmers will pass either complete-from-possibilities or complete-from-generator as the value of function . Its first argument is a string containing the user's input ``so far''. Its second argument is the completion mode, one of the following:
partial-completers is a list of characters that delimit portions of a name that can be completed separately. The default is an empty list.
If the boolean allow-any-input is true , then complete-input will return as soon as the user issues an activation gesture, even if the input is not any of the possibilities. If the input is not one of the possibilities, the three values returned by complete-input will be nil , t , and the string. The default for allow-any-input is false .
If possibility-printer is supplied, it must be a function of three arguments, a possibility, a presentation type, and a stream; it has dynamic extent. The function displays the possibility on the stream. The possibility will be a list of two elements, the first being a string and the second being the object corresponding to the string.
If help-display-possibilities is true (the default), then when the user issues a help gesture (a gesture that matches one of the gesture names in *help-gestures* ), CLIM will display all the matching possibilities. If it is false , then CLIM will not display the possibilities unless the user issues a possibility gesture (a gesture that matches one of the gesture names in *possibilities-gestures* ).
| simple-completion-error | [Condition] |
| completing-from-suggestions | (stream &key partial-completers allow-any-input possibility-printer (help-displays-possibilities t )) &body body | [Macro] |
completing-from-suggestions returns three values, object , success , and string The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t (the default), *standard-input* is used.
partial-completers , allow-any-input , and possibility-printer are as for complete-input .
Implementations will probably use complete-from-generator to implement this.
| suggest | completion object | [Function] |
It is permitted for this function to have lexical scope, and be defined only within the body of completing-from-suggestions .
| complete-from-generator | string function delimiters &key (action :complete ) predicate | [Function] |
action will be one of :complete , :complete-maximal , :complete-limited , or :possibilities . These are described under the function complete-input .
predicate must be a function of one argument, an object. If the predicate returns true , the possibility corresponding to the object is processed, otherwise it is not. It has dynamic extent.
complete-from-generator returns five values, the completed input string, the success value (true if the completion was successful, otherwise false ), the object matching the completion (or nil if unsuccessful), the number of matches, and a list of possible completions if action was :possibilities .
This function is one that will typically be passed as the second argument to complete-input .
| complete-from-possibilities | string completions delimiters &key (action :complete ) predicate name-key value-key | [Function] |
action will be one of :complete , :complete-maximal , :complete-limited , or :possibilities . These are described under the function complete-input .
predicate must be a function of one argument, an object. If the predicate returns true , the possibility corresponding to the object is processed, otherwise it is not.
predicate , name-key , and value-key have dynamic extent.
complete-from-possibilities returns five values, the completed input string, the success value (true if the completion was successful, otherwise false ), the object matching the completion (or nil if unsuccessful), the number of matches, and a list of possible completions if action was :possibilities .
This function is one that will typically be passed as the second argument to complete-input .
| with-accept-help | options &body body | [Macro] |
options is a list of option specifications. Each specification is itself a list of the form (help-option help-string) . help-option is either a symbol that is a help-type or a list of the form (help-type mode-flag) .
help-type must be one of:
None of the arguments is evaluated.
| Presentation Types | Contents | Index | Menu Facilities |