Skip to content

Instantly share code, notes, and snippets.

@joinr
Created December 19, 2019 02:53
Show Gist options
  • Save joinr/306570ae30337c8b6300abedcc2b0aee to your computer and use it in GitHub Desktop.
Save joinr/306570ae30337c8b6300abedcc2b0aee to your computer and use it in GitHub Desktop.
lanterna demo
(ns lanternademo.core
(:require [lanterna.screen :as screen]))
;;provides a way to track resources and kill rendering from the outside. we
;;could also use an atom and synchronize on it from the rendering loop. I like
;;using future here though, since it keeps our REPL thread free.
(def renderer (atom nil))
(defn kill-rendering! []
(when @renderer
(future-cancel @renderer)))
;;helper macro to ensure we cleanup on exit.
;;we're not catching all the errors though....
(defmacro with-screen [s & body]
`(let [~s (screen/get-screen)
out# ~'*out*]
(reset! renderer
(future
(try ~@body
(catch ~'Exception e# (binding [~'*out* out#]
(println e#)))
(finally (screen/stop ~s)))))))
(defn next-position [x y cmd]
(when-let [[dx dy] (case cmd
:right [1 0]
:down [0 1]
:left [-1 0]
:up [0 -1])]
[(max 0 (+ x dx)) (max 0 (+ y dy))]))
(def terminate? #{:escape :q})
(defn update-state [{:keys [cursor-x cursor-y] :as state} k]
(if-let [[x y] (next-position cursor-x cursor-y k)]
(assoc state :cursor-x x :cursor-y y)
(assoc state :terminate? (terminate? k))))
(defn render-cursor [scr {:keys [cursor-x cursor-y]}]
(doto scr
(screen/move-cursor cursor-x cursor-y)
(screen/put-string cursor-x cursor-y (str \0))))
(defn render-random-blocks [scr]
(screen/put-string scr (rand-int 80) (rand-int 24) (str (gensym "x")) ))
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}]
(doto scr
(render-cursor state)))
(defn render [& {:keys [x y] :or {x 0 y 0}}]
(with-screen scr
(let [_ (doto scr screen/start
(screen/move-cursor 0 0))]
(loop [state {:cursor-x 0 :cursor-y 0 :terminate? nil}]
(screen/redraw scr)
(screen/clear scr)
(if-not (:terminate? state)
(let [nxt (update-state state (screen/get-key-blocking scr))]
(do (render-screen scr nxt)
(recur nxt)))
(println "Goodbye!"))))))
(comment
;;if we redefine render-screen here, should get picked up.
;;just copy/paste this into the repl, or eval it.
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}]
(doto scr
(render-cursor state)
(render-random-blocks)))
;;If we go back to normal, we get our old rendering back.
(defn render-screen [scr {:keys [cursor-x cursor-y] :as state}]
(doto scr
(render-cursor state)))
;;if we eval this one, the next move will shut down the screen
;;and print the error.
(defn render-screen [scr state]
(throw (ex-info "blowup!" {:msg :forced-error})))
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment