fix: runtime crash (sb-ext:timeout undefined), replace with listen-based polling
- Remove handler-case + sb-ext:with-timeout 0.1 pattern entirely. sb-ext:timeout is a condition class, not a recognized type in the compilation environment, causing runtime 'undefined function' crash. - Replace with dotimes 10 * (listen *standard-input*) + sleep 0.01 polling loop. Same 0.1s timeout, no condition type dependencies. - Also fix handler-bind → handler-case in tui-load.lisp so the stack unwinds properly (running with-terminal's shutdown-backend cleanup) before the crash handler runs, restoring terminal to normal state. - Fix paren imbalance (off by 1) in the new listen-based reader code.
This commit is contained in:
@@ -955,51 +955,51 @@ supplied (e.g. \"/\"), pre-fill the select filter with it."
|
|||||||
(when (> (length f) 0)
|
(when (> (length f) 0)
|
||||||
(setf (cl-tty.select:select-filter sel)
|
(setf (cl-tty.select:select-filter sel)
|
||||||
(subseq f 0 (1- f))))))))
|
(subseq f 0 (1- f))))))))
|
||||||
(on-key ch))))))))
|
(on-key ch))))))))
|
||||||
;; Keyboard reader with CSI escape detection
|
;; Keyboard reader: poll with 0.1s timeout via listen (no sb-ext:timeout)
|
||||||
(handler-case
|
(dotimes (_ 10)
|
||||||
(sb-ext:with-timeout 0.1
|
(when (listen *standard-input*)
|
||||||
(let* ((raw-ch (read-char-no-hang *standard-input* nil nil)))
|
(let* ((raw-ch (read-char-no-hang *standard-input* nil nil))
|
||||||
(when raw-ch
|
(code (and raw-ch (char-code raw-ch)))
|
||||||
(let* ((code (char-code raw-ch))
|
(esc-seq (and (= code 27)
|
||||||
(esc-seq (and (= code 27)
|
(let ((b nil) (t2 nil))
|
||||||
;; Poll for up to 20ms to collect CSI bytes
|
(dotimes (_ 20)
|
||||||
(let ((b nil) (t2 nil))
|
(when (listen *standard-input*)
|
||||||
(dotimes (_ 20)
|
(setq b (read-char *standard-input* nil nil))
|
||||||
(when (listen *standard-input*)
|
(return))
|
||||||
(setq b (read-char *standard-input* nil nil))
|
(sleep 0.001))
|
||||||
(return))
|
(and b (char= b #\[)
|
||||||
(sleep 0.001))
|
(dotimes (_ 10)
|
||||||
(and b (char= b #\[)
|
(when (listen *standard-input*)
|
||||||
(dotimes (_ 10)
|
(setq t2 (read-char *standard-input* nil nil))
|
||||||
(when (listen *standard-input*)
|
(return))
|
||||||
(setq t2 (read-char *standard-input* nil nil))
|
(sleep 0.001))
|
||||||
(return))
|
(case (and t2 (char-code t2))
|
||||||
(sleep 0.001))
|
(65 :up) (66 :down)
|
||||||
(case (and t2 (char-code t2))
|
(67 :right) (68 :left)
|
||||||
(65 :up) (66 :down)
|
(72 :home) (70 :end)
|
||||||
(67 :right) (68 :left)
|
(otherwise :escape)))))))
|
||||||
(72 :home) (70 :end)
|
(when raw-ch
|
||||||
(otherwise :escape))))))
|
(queue-event
|
||||||
(queue-event
|
(list :type :key
|
||||||
(list :type :key
|
:payload (list :code code
|
||||||
:payload (list :code code
|
:ch (or esc-seq
|
||||||
:ch (or esc-seq
|
(cond
|
||||||
(cond
|
((= code 13) :enter)
|
||||||
((= code 13) :enter)
|
((= code 10) :enter)
|
||||||
((= code 10) :enter)
|
((= code 27) :escape)
|
||||||
((= code 27) :escape)
|
((= code 9) :tab)
|
||||||
((= code 9) :tab)
|
((or (= code 127) (= code 8)) :backspace)
|
||||||
((or (= code 127) (= code 8)) :backspace)
|
((and (>= code 1) (<= code 26))
|
||||||
((and (>= code 1) (<= code 26))
|
(intern
|
||||||
(intern
|
(string-upcase
|
||||||
(string-upcase
|
(format nil "CTRL-~a"
|
||||||
(format nil "CTRL-~a"
|
(code-char (+ #x60 code))))
|
||||||
(code-char (+ #x60 code))))
|
:keyword))
|
||||||
:keyword))
|
(t code)))))))
|
||||||
(t code))))))))))))
|
(return)))
|
||||||
(sb-ext:timeout ())
|
(sleep 0.01))
|
||||||
;; Check for terminal resize (SIGWINCH sets this flag)
|
;; Check for terminal resize (SIGWINCH sets this flag)
|
||||||
(when (boundp 'cl-tty.input::*terminal-resized-p*)
|
(when (boundp 'cl-tty.input::*terminal-resized-p*)
|
||||||
(when cl-tty.input::*terminal-resized-p*
|
(when cl-tty.input::*terminal-resized-p*
|
||||||
(setf cl-tty.input::*terminal-resized-p* nil)
|
(setf cl-tty.input::*terminal-resized-p* nil)
|
||||||
|
|||||||
18
passepartout
18
passepartout
@@ -397,14 +397,16 @@ case "$COMMAND" in
|
|||||||
(compile-file src :output-file fasl :verbose nil :print nil))
|
(compile-file src :output-file fasl :verbose nil :print nil))
|
||||||
(load fasl :verbose nil :print nil))))
|
(load fasl :verbose nil :print nil))))
|
||||||
(in-package :passepartout)
|
(in-package :passepartout)
|
||||||
(handler-bind ((error (lambda (c) (ignore-errors
|
(handler-case
|
||||||
(with-open-file (f (merge-pathnames ".cache/passepartout/tui-crash.log" (user-homedir-pathname))
|
(passepartout.channel-tui:tui-main)
|
||||||
:direction :output :if-exists :supersede :if-does-not-exist :create)
|
(error (c)
|
||||||
(format f "CRASH: ~a~%~%" c) (sb-debug:print-backtrace :count 50 :stream f) (finish-output f)))
|
(ignore-errors
|
||||||
(format t "~%=== TUI CRASH ===~%CRASH: ~a~%" c)
|
(with-open-file (f (merge-pathnames ".cache/passepartout/tui-crash.log" (user-homedir-pathname))
|
||||||
(format t "Full backtrace saved to ~~/.cache/passepartout/tui-crash.log~%")
|
:direction :output :if-exists :supersede :if-does-not-exist :create)
|
||||||
(sleep 3) (finish-output) (uiop:quit 1))))
|
(format f "CRASH: ~a~%~%" c) (sb-debug:print-backtrace :count 50 :stream f) (finish-output f)))
|
||||||
(passepartout.channel-tui:tui-main))
|
(format t "~%=== TUI CRASH ===~%CRASH: ~a~%" c)
|
||||||
|
(format t "Full backtrace saved to ~~/.cache/passepartout/tui-crash.log~%")
|
||||||
|
(sleep 3) (finish-output)))
|
||||||
(uiop:quit 0)
|
(uiop:quit 0)
|
||||||
LISPEOF
|
LISPEOF
|
||||||
# Capture terminal dimensions in non-standard env vars
|
# Capture terminal dimensions in non-standard env vars
|
||||||
|
|||||||
Reference in New Issue
Block a user