diff --git a/.dir-locals.el b/.dir-locals.el index 273bf42..2351726 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -6,10 +6,11 @@ (nil . ((eval . (progn - (unless (fboundp 'clj-watch) - (load (expand-file-name - "watch.el" - (locate-dominating-file default-directory ".dir-locals.el")))) + (let ((root (locate-dominating-file default-directory ".dir-locals.el"))) + (unless (fboundp 'clj-watch) + (load (expand-file-name "watch.el" root))) + (unless (fboundp 'clj-game-throw-last-error) + (load (expand-file-name "cider-error.el" root)))) (defun clj-game-run-main () "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 e") #'clj-game-clear-error) (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))) (unless (fboundp 'clj-game-mode) diff --git a/src/engine.clj b/src/engine.clj index 2425d43..d9e5610 100644 --- a/src/engine.clj +++ b/src/engine.clj @@ -8,6 +8,15 @@ (defonce ^:private game-state (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! [] (reset! last-error nil)) @@ -25,15 +34,17 @@ (do (rl/set-trace-log-level! rl/log-warning) (rl/init-window! width height title) - (rl/set-target-fps! 60) + (rl/set-target-fps! 30) (let [config (if config-path (edn/read-string (slurp config-path)) {})] (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 (reset! game-state (init config)) (catch Throwable t - (println t))) + (report-exception! t))) (while (not (rl/window-should-close?)) (if @last-error (Thread/sleep 50) @@ -45,14 +56,13 @@ (draw config @game-state) (w/watch! (watch-fn config @game-state)) (catch Throwable t - (println t) - (reset! last-error t) + (report-exception! t) (w/watch! (merge (watch-fn config @game-state) {:error t})))))))) (try (when unload (unload @game-state)) (catch Throwable t - (println t))) + (report-exception! t))) (rl/close-window!) (reset! last-error nil) (reset! game-state nil)