  (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
