Cider exception reporting

This commit is contained in:
Joseph Ferano 2026-08-23 14:35:26 +07:00
parent 0715b84e7a
commit 53307aa95c
2 changed files with 21 additions and 9 deletions

View File

@ -6,10 +6,11 @@
(nil (nil
. ((eval . ((eval
. (progn . (progn
(let ((root (locate-dominating-file default-directory ".dir-locals.el")))
(unless (fboundp 'clj-watch) (unless (fboundp 'clj-watch)
(load (expand-file-name (load (expand-file-name "watch.el" root)))
"watch.el" (unless (fboundp 'clj-game-throw-last-error)
(locate-dominating-file default-directory ".dir-locals.el")))) (load (expand-file-name "cider-error.el" root))))
(defun clj-game-run-main () (defun clj-game-run-main ()
"Send (future (-main)) to the REPL." "Send (future (-main)) to the REPL."
@ -33,6 +34,7 @@
(define-key m (kbd "C-c g r") #'clj-game-run-main) (define-key m (kbd "C-c g r") #'clj-game-run-main)
(define-key m (kbd "C-c g e") #'clj-game-clear-error) (define-key m (kbd "C-c g e") #'clj-game-clear-error)
(define-key m (kbd "C-c g c") #'clj-game-reload-config) (define-key m (kbd "C-c g c") #'clj-game-reload-config)
(define-key m (kbd "C-c g x") #'clj-game-throw-last-error)
m))) m)))
(unless (fboundp 'clj-game-mode) (unless (fboundp 'clj-game-mode)

View File

@ -8,6 +8,15 @@
(defonce ^:private game-state (atom nil)) (defonce ^:private game-state (atom nil))
(defonce ^:private game-config (atom nil)) (defonce ^:private game-config (atom nil))
(defn report-exception!
"Stash the exception and print a marker line. Emacs watches the REPL output
for the marker and rethrows the stashed exception over nREPL, so it lands in
cider's stacktrace buffer instead of as an unreadable println. See
cider-error.el."
[^Throwable t]
(reset! last-error t)
(println "SIAM-REPORT-EXCEPTION"))
(defn clear-error! [] (defn clear-error! []
(reset! last-error nil)) (reset! last-error nil))
@ -25,15 +34,17 @@
(do (do
(rl/set-trace-log-level! rl/log-warning) (rl/set-trace-log-level! rl/log-warning)
(rl/init-window! width height title) (rl/init-window! width height title)
(rl/set-target-fps! 60) (rl/set-target-fps! 30)
(let [config (if config-path (let [config (if config-path
(edn/read-string (slurp config-path)) (edn/read-string (slurp config-path))
{})] {})]
(reset! game-config {:config-path config-path :config config}) (reset! game-config {:config-path config-path :config config})
;; TODO: We should actually not commit until the frame is complete, because if not we will re-enter
;; input and call it several times if update or draw throw
(try (try
(reset! game-state (init config)) (reset! game-state (init config))
(catch Throwable t (catch Throwable t
(println t))) (report-exception! t)))
(while (not (rl/window-should-close?)) (while (not (rl/window-should-close?))
(if @last-error (if @last-error
(Thread/sleep 50) (Thread/sleep 50)
@ -45,14 +56,13 @@
(draw config @game-state) (draw config @game-state)
(w/watch! (watch-fn config @game-state)) (w/watch! (watch-fn config @game-state))
(catch Throwable t (catch Throwable t
(println t) (report-exception! t)
(reset! last-error t)
(w/watch! (merge (watch-fn config @game-state) {:error t})))))))) (w/watch! (merge (watch-fn config @game-state) {:error t}))))))))
(try (try
(when unload (when unload
(unload @game-state)) (unload @game-state))
(catch Throwable t (catch Throwable t
(println t))) (report-exception! t)))
(rl/close-window!) (rl/close-window!)
(reset! last-error nil) (reset! last-error nil)
(reset! game-state nil) (reset! game-state nil)