All Manuals > CLIM 2.0 User Guide > 16 Input Editing and Completion Facilities

16.1 Input Editing

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

16.1.1 Operators for Input Editing

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 Macro

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.

16.1.2 Input Editor Commands

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.

Input Editor Keystroke Commands
CommandKeystrokeCommandKeystroke

Forward character

C-f

Delete previous character

Rubout

Forward word

M-f

Delete previous word

M-Rubout

Backward character

C-b

Kill to end of line

C-k

Backward word

M-b

Clear input buffer

LispWorks: C-backspace
Liquid CL: C-M-delete

Beginning of line

C-a

Insert new line

C-o

End of line

C-e

Transpose adjacent characters

C-t

Next line

C-n

Transpose adjacent words

M-t

Previous line

C-p

Yank from kill ring

C-y

Beginning of buffer

M-<

Yank from presentation history

C-M-y

End of buffer

M->

Yank next item

M-y

Delete next character

C-d

Scroll output history forward

C-v

Delete next word

M-d

Scroll output history backward

M-v

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