; -*- mode:lisp; package:steve; readtable:cl; -*- ;Copyright (c) May 1983 by Christopher Eliot ; and Massachusetts Institute of Technology. All rights reserved. ;Permission to copy all or part of this material is granted, provided ; that the copies are not made or distributed for resale, the MIT ; copyright notice and reference to the source file and the software ; distribution version appear, and that notice is given that copying ; is by permission of Massachusetts Institute of Technology. ; (defflavor editor-rubout-handling-stream (buffer istream ostream chars rereading? pos) (input-stream) :initable-instance-variables) (defmethod (editor-rubout-handling-stream :re-init) () (unless (null buffer) (setq chars (reverse buffer)) (setq rereading? t))) ;;With an argument this should behave just as if that char was typed. (defmethod (editor-rubout-handling-stream :read-char) (&optional (char nil char?)) (when (null char?) (cond ((null rereading?) (cursorpos (car pos) (cdr pos) ostream) (setq char (send istream :read-char))) (t (setq char (car (pop chars)))))) (cond ((char= char #\rubout) (send self :rubout) (send self :re-init) (throw 'rubout-tag nil)) ((char= char #\^u) (loop while (not (null buffer)) do (send self :rubout)) (send self :re-init) (throw 'rubout-tag nil)) ((char= char #\^w) (loop with flag = nil while (not (null buffer)) while (if (alphanumericp (caar buffer)) (setq flag t) (null flag)) do (send self :rubout)) (send self :re-init) (throw 'rubout-tag nil)) ((char= char #\bell) (ed-warn "Aborted"))) (unless rereading? (push (list char (cursorpos istream)) buffer) (send ostream :write-char char) (setq pos (cursorpos istream))) (when (and rereading? (null chars)) (setq rereading? nil)) char) (defmethod (editor-rubout-handling-stream :unread-char) (char) (setq rereading? t) (push char chars) char) (defmethod (editor-rubout-handling-stream :peek-char) () (send self :unread-char (send self :read-char))) (defmethod (editor-rubout-handling-stream :rubout) () (unless rereading? (when (null buffer) (throw 'rubout-tag t)) (setq pos (cadr (pop buffer))) (cursorpos (car pos) (cdr pos) ostream) (send ostream :clear-eol) t)) (defmethod (editor-rubout-handling-stream :buffer-size) () (length buffer)) (defmethod (editor-rubout-handling-stream :beep) () (send ostream :send-if-handles :beep)) (defmethod (editor-rubout-handling-stream :echo-false-char) (char) (send ostream :write-char char)) ; ;Init with :buffer nil :stream STREAM :index 0 :size 0 (defflavor editor-completion-stream (buffer stream index size) (input-stream) :initable-instance-variables) (defmethod (editor-completion-stream :re-init) () (send stream :re-init) (setq buffer nil size 0 index 0)) (defmethod (editor-completion-stream :read-char) () (when (>=& index size) (push (send stream :read-char) buffer) (setq size (1+& size))) (setq index (1+& index)) (nth (-& size index) buffer)) (defmethod (editor-completion-stream :unread-char) (char) (setq index (1-& index)) char) (defmethod (editor-completion-stream :peek-char) () (send self :unread-char (send self :read-char))) (defmethod (editor-completion-stream :buffer-size) () (send stream :buffer-size)) (defmethod (editor-completion-stream :beep) () (send stream :send-if-handles :beep)) (defmethod (editor-completion-stream :rubout) () (send stream :rubout) (pop buffer)) (defmethod (editor-completion-stream :echo-false-char) (char) (send stream :send-if-handles :echo-false-char char)) (defmethod (editor-completion-stream :completion-string) (string replacing &aux (length (string-length string))) (when (>=& index size) (loop repeat replacing do (send stream :rubout) do (pop buffer)) (setq replacing 0) (loop for i from 0 below length do (send stream :read-char (char string i)))) (loop with tail = (nthcdr (+& (-& size index) replacing) buffer) with head = (loop for i downfrom size above index for x in buffer with value = nil do (setq value (cons x value)) ;Reverse order. finally (return value)) for i from 0 below length do (push (char string i) tail) finally (loop for x in head do (push x tail)) finally (setq buffer tail)) (setq size (-& (+& size length) replacing) index (-& (+& index length) replacing))) (defun prescan (function &optional (eof nil eof?)) (with-no-passall (let ((stream (make-instance 'editor-completion-stream :buffer nil :stream (make-instance 'editor-rubout-handling-stream :buffer nil :istream terminal-io :ostream terminal-io :rereading? nil :chars nil :pos (cursorpos terminal-io)) :index 0 :size 0))) (loop for frob = (catch 'rubout-tag (catch 'completion-reread (list (funcall function stream)))) if (consp frob) return (car frob) do (cond ((null frob) (send stream :re-init)) ((0p (or (send stream :send-if-handles :buffer-size) 1)) (cond ((null eof?) (send stream :send-if-handles :beep)) (t (return eof)))))))))