(define (read-raw prompt in out offset) (dbg "Entering read-raw\n") (let ((l (call-with-current-continuation (lambda (return) (prompt-loop prompt in out "" 0 return offset))))) (dbg "Read raw: ~s\n" l) (history-add! l))) (define (parley prompt #!key (in ##sys#standard-input) (out (current-output-port))) (set-buffering-mode! out #:none) (let* ((parley-port (parley? in)) (real-in-port (first-usable-port in port-list)) (useful-term (terminal-supported? real-in-port (get-environment-variable "TERM"))) (old-attrs (and useful-term (enable-raw-mode real-in-port)))) (let ((lines (if useful-term (begin (history-init!) (unless (member in port-list) (set! port-list (cons in port-list))) (let* ((prev-input (and (char-ready? in) (slurp-all-input in))) (offset (if parley-port 1 (get-column real-in-port)))) (dbg "prev input: ~s\n" prev-input) (if prev-input (call-with-input-string (list->string prev-input) (lambda (in) (let loop ((r '())) (dbg "loop: ~s\n" r) (if (eof-object? (peek-char in)) (reverse r) (loop (cons (read-raw prompt in out offset) r)))))) (read-raw prompt real-in-port out offset)))) (begin (dbg "; Warning: dumb terminal") (set-buffering-mode! real-in-port #:none) (when (or (terminal-port? in) parley-port) (display prompt out)) (flush-output out) (let ((l (read-one-line real-in-port))) l))))) (if old-attrs (restore-terminal-settings real-in-port old-attrs)) lines))) (define (make-parley-port in #!optional prompt prompt2) (let ((l "") (handle #f) (p1 prompt) (p2 (or prompt2 "> ")) (pos 0)) (unless (member in port-list) (set! port-list (cons in port-list))) (letrec ((append-while-incomplete (lambda (start) (let* ((lines (parley (if (string-null? start) (or p1 ((repl-prompt))) p2) in: in)) (line (if (list? lines) (string-intersperse lines (string #\newline)) lines)) (res (and (string? line) (string-append start line)))) (dbg "So far: '~s' '~s' '~s'\n" lines line res) (cond ((and (eof-object? line) (string-null? start)) line) ((eof-object? line) start) ((input-missing? res) (append-while-incomplete res)) (else res))))) (char-ready? (lambda () (and (string? l) (< pos (string-length l))))) (get-next-char! (lambda () (cond ((not l) #!eof) ((char-ready?) (let ((ch (string-ref l pos))) (set! pos (+ 1 pos)) ch)) (else (set! pos 0) (set! l (append-while-incomplete "")) (if (and (useful-term? in) (string? l)) (set! l (string-append l "\n"))) (if (not (eof-object? l)) (get-next-char!) l)))))) (set! handle (lambda (s) (print-call-chain) (set! pos 0) (set! l "") (##sys#user-interrupt-hook))) (set-signal-handler! signal/int handle) (let ((p (make-input-port get-next-char! char-ready? (lambda () (set-signal-handler! signal/int #f) 'closed-parley-port)))) (set-port-name! p "(parley)") p))))