cli: stop drain-stdin!/escape-watcher from spinning on EOF
ober
67a3cbf06869d71b9e2ba3ef6bbfc33f8b524581
--- a/src/jcode/ui/cli.ss +++ b/src/jcode/ui/cli.ss @@ -314,11 +314,14 @@ EXAMPLES: (system "stty cbreak -echo 2>/dev/null")) (def (drain-stdin!) + ;; char-ready? returns #t at EOF and read-char returns the eof-object, + ;; so a naive loop spins at 100% CPU when stdin is closed (piped input). (guard (e [#t (void)]) (let loop () (when (char-ready? (current-input-port)) - (read-char (current-input-port)) - (loop))))) + (let ((c (read-char (current-input-port)))) + (unless (eof-object? c) + (loop))))))) (def (start-escape-watcher!) "Spawn thread that polls stdin in cbreak mode for ESC key." @@ -330,9 +333,14 @@ EXAMPLES: (unless (car *stream-abort*) (if (char-ready? (current-input-port)) (let ((c (read-char (current-input-port)))) - (when (and (char? c) (= (char->integer c) 27)) - (set-car! *stream-abort* #t)) - (unless (car *stream-abort*) (loop))) + ;; EOF on stdin means no more keystrokes will ever arrive + ;; (e.g. piped input). Exit instead of spinning. + (cond + ((eof-object? c) (void)) + ((and (char? c) (= (char->integer c) 27)) + (set-car! *stream-abort* #t)) + (else + (unless (car *stream-abort*) (loop))))) (begin ;; thread-sleep!; (sleep (make-time ...)) is broken ;; because the prelude shadows make-time.