(STREAM-DEFAULT-HANDLER #'TV-STREAM OP ARG1 REST)) ;; The stream in AI:LMIO;SUPSER also follows this protocol. ;; Below is the definition of the editor stream. The particular ;; "editor" or rubout handler used is a parameter of the stream. ;; This stream handles the :UNTYI and :RUBOUT-HANDLER operations ;; so that console streams don't have to worry about this. ;; Set up the :WHICH-OPERATIONS list ahead of time so as to avoid ;; excessive consing. This operation gets invoked every time READ ;; or READLINE is called, for instance. (DECLARE (SPECIAL ES-CONSOLE-STREAM ES-EDITOR ES-UNTYI-CHAR ES-KILL-RING ES-BUFFER ES-WHICH-OPERATIONS ES-X-ORIGIN ES-Y-ORIGIN)) (DEFUN MAKE-EDITOR-STREAM (ES-CONSOLE-STREAM ES-EDITOR &OPTIONAL (KILL-RING-SIZE 20.)) (LET ((ES-UNTYI-CHAR NIL) (ES-KILL-RING NIL) (ES-BUFFER) (ES-X-ORIGIN) (ES-Y-ORIGIN) ;; Be sure to include :CLEAR-INPUT for BREAK. Don't include :TYI and ;; :TYI-NO-HANG since we can't really do them unless the underlying ;; stream can. (ES-WHICH-OPERATIONS (UNION '(:UNTYI :RUBOUT-HANDLER :CLEAR-INPUT :LISTEN) (FUNCALL ES-CONSOLE-STREAM ':WHICH-OPERATIONS)))) (DOTIMES (I KILL-RING-SIZE) (PUSH (MAKE-ARRAY NIL 'ART-8B 400 NIL '(0 0 0)) ES-KILL-RING)) ;; Make the kill ring into a real ring. (RPLACD (LAST ES-KILL-RING) ES-KILL-RING) (SETQ ES-BUFFER (CAR ES-KILL-RING)) (CLOSURE '(ES-CONSOLE-STREAM ES-EDITOR ES-UNTYI-CHAR ES-KILL-RING ES-BUFFER ES-WHICH-OPERATIONS) #'EDITOR-STREAM))) ;; FILL-POINTER points to what has been typed so far. SCAN-POINTER points ;; to what has been read so far. TYPEIN-POINTER points to where in the ;; middle of the line we are typing. (DEFMACRO FILL-POINTER () '(ARRAY-LEADER ES-BUFFER 0)) (DEFMACRO SCAN-POINTER () '(ARRAY-LEADER ES-BUFFER 1)) (DEFMACRO TYPEIN-POINTER () '(ARRAY-LEADER ES-BUFFER 2)) ;; The third argument in the DEFSELECT function specification means ;; that we're handling :WHICH-OPERATIONS ourselves. ;; May want to flush UNTYI-CHAR infavor of using the buffer. (DEFSELECT (EDITOR-STREAM EDITOR-STREAM-DEFAULT-HANDLER T) (:WHICH-OPERATIONS () ES-WHICH-OPERATIONS) ;; Input Operations ;; Don't need EOF-OPTION for :TYI since this will always be an interactive stream. ;; Accept the option anyway since some functions may work for both interactive and ;; batch streams. (:TYI (&OPTIONAL IGNORE &AUX SCAN-POINTER) (COND ;; Give buffered-back character, if any. Don't bother echoing or putting ;; it in the editor buffer since this has already happened. We are guaranteed ;; that the untyi'ed char is the one just tyi'ed. (ES-UNTYI-CHAR (PROG1 ES-UNTYI-CHAR (SETQ ES-UNTYI-CHAR NIL))) ;; If not using a rubout processor, go directly to the underlying stream. ((NOT RUBOUT-HANDLER) (FUNCALL ES-CONSOLE-STREAM ':TYI)) ;; If using a rubout processor and unread input exists, then return it. ((> (FILL-POINTER) (SETQ SCAN-POINTER (SCAN-POINTER))) (SETF (SCAN-POINTER) (1+ SCAN-POINTER)) (AREF ES-BUFFER SCAN-POINTER)) ;; Else get more input via the rubout processor. ;; This is kind of a kludge. We really want a handle of SELF. ;; The stream state will be passed along since the specials are still bound. (T (FUNCALL ES-EDITOR #'EDITOR-STREAM)))) (:TYI-NO-HANG (&AUX SCAN-POINTER) (COND ;; Give buffered-back character, if any. (ES-UNTYI-CHAR (PROG1 ES-UNTYI-CHAR (SETQ ES-UNTYI-CHAR NIL))) ;; If not using a rubout processor, go directly to the underlying stream. ((NOT RUBOUT-HANDLER) (FUNCALL ES-CONSOLE-STREAM ':TYI-NO-HANG)) ;; Give buffered input from the rubout processor, if unread input exists. ((> (FILL-POINTER) (SETQ SCAN-POINTER (SCAN-POINTER))) (SETF (SCAN-POINTER) (1+ SCAN-POINTER)) (AREF ES-BUFFER SCAN-POINTER)) ;; In the case where the rubout handler is on, but no unread input exists, ;; just go to the underlying stream and try to get a character. Don't ;; bother with echoing it or putting it in the character buffer, although ;; this is probably what we should do. (T (FUNCALL ES-CONSOLE-STREAM ':TYI-NO-HANG)))) (:UNTYI (CHAR) (SETQ ES-UNTYI-CHAR CHAR)) ;; Should we check here to see of the console stream really supports :LISTEN? (:LISTEN () (COND (ES-UNTYI-CHAR) ((> (FILL-POINTER) (SCAN-POINTER)) (AREF ES-BUFFER (SCAN-POINTER))) (T (FUNCALL ES-CONSOLE-STREAM ':LISTEN)))) ;; If the rubout handler is on, empty the buffer. Perhaps we should clear the ;; input from the screen in this case as well since the user is still typing. ;; I don't see how this could ever happen. If the handler is off, don't clear