From 4f96c63d006aa15fc54667a6654cb35a55f82fc5 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Mon, 29 Mar 2021 01:03:43 -0400 Subject: [PATCH] Implement a repl!! --- editor/imstate.fnl | 2 +- editor/init.fnl | 16 ++++++++++++ editor/repl.fnl | 49 +++++++++++++++++++++++++++++++++++ editor/replview.fnl | 62 +++++++++++++++++++++++++++++++++++++++++++++ lib/util.fnl | 15 ++++++++++- todo.txt | 8 ++++++ 6 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 editor/repl.fnl create mode 100644 editor/replview.fnl diff --git a/editor/imstate.fnl b/editor/imstate.fnl index bbbcafa..2c15b9f 100644 --- a/editor/imstate.fnl +++ b/editor/imstate.fnl @@ -155,7 +155,7 @@ (fn textbox [view tag text x y w] (var textNew (or text "")) - (local (h hText xText yText) (values 20 16 (+ x 2) (+ y 2))) + (local (h hText xText yText) (values (+ (style.font:get_height) 4) (style.font:get_height) (+ x 2) (+ y 2))) ; handle key events (when (focus view tag x y w h {:i 1 :iAnchor 1 :blink (love.timer.getTime)}) diff --git a/editor/init.fnl b/editor/init.fnl index 6703c70..6ffa7e7 100644 --- a/editor/init.fnl +++ b/editor/init.fnl @@ -14,4 +14,20 @@ (require :editor.editmode) +(command.add :editor.replview { + "repl:submit" #(core.active_view:submit) +}) + +(local ReplView (require :editor.replview)) +(local repl (require :editor.repl)) +(command.add nil { + "repl:create" (fn [] + (local node (core.root_view:get_active_node)) + (node:add_view (ReplView (repl.new))) + ) +}) +(keymap.add { + :return "repl:submit" +}) + {: inline-eval} diff --git a/editor/repl.fnl b/editor/repl.fnl new file mode 100644 index 0000000..5dd9203 --- /dev/null +++ b/editor/repl.fnl @@ -0,0 +1,49 @@ +(local util (require :lib.util)) +(local fennel (require :lib.fennel)) +(local style (require :core.style)) +(local lume (require :lib.lume)) + +(local repl {}) + +(fn repl.inspect [v view x y w] + (renderer.draw_text style.font (fv v) x y style.text) + (style.font:get_height)) + +(fn repl.inspector [{: vals} view x y] + (var h 0) + (each [i v (ipairs vals)] + (set h (+ h (repl.inspect v view x (+ y h) view.size.x)))) + (+ h style.padding.y)) + +(fn repl.notify [listeners line] + (each [_ listener (ipairs listeners)] + (listener:append line))) + +(fn repl.run [{: listeners}] + (local inspector (util.fn repl :inspector)) + (fennel.repl {:readChunk coroutine.yield + :onValues #(repl.notify listeners {:draw inspector :vals $1}) + :onError (fn [errType err luaSource] (repl.notify listeners {:draw inspector :vals [err]})) + :pp #$1 + :env (lume.clone _G)})) + +(fn repl.listen [{: listeners} listener] + (table.insert listeners listener)) + +(fn repl.unlisten [{: listeners} listener] + (lume.remove listeners listener)) + +(fn repl.submit [{: coro} chunk] + (coroutine.resume coro (.. chunk "\n"))) + +(fn repl.new [] + (local result + {:listeners [] + :listen (util.fn repl :listen) + :unlisten (util.fn repl :unlisten) + :submit (util.fn repl :submit) + :coro (coroutine.create repl.run)}) + (coroutine.resume result.coro result) + result) + +repl diff --git a/editor/replview.fnl b/editor/replview.fnl new file mode 100644 index 0000000..5aff52f --- /dev/null +++ b/editor/replview.fnl @@ -0,0 +1,62 @@ +(local util (require :lib.util)) +(local {: attach-imstate : textbox} (util.require :editor.imstate)) +(local View (require :core.view)) +(local style (require :core.style)) + +(local ReplView (View:extend)) + +(fn ReplView.new [self conn] + (ReplView.super.new self) + (attach-imstate self) + (set self.conn conn) + (set self.log []) + (set self.cmd "") + (set self.scrollheight math.huge) + (set self.scrollable true) + (set self.pin-to-bottom-y self.scroll.to.y) + (self.conn:listen self)) + +(fn ReplView.try_close [self do_close] + (self.conn:unlisten self) + (ReplView.super.try_close self do_close)) + +(fn ReplView.get_scrollable_size [self] self.scrollheight) + +(fn ReplView.append [self line] + (table.insert self.log line)) + +(fn ReplView.draw-cmd [{: cmd} view x y] + (renderer.draw_text style.font cmd x y style.text) + (+ (style.font:get_height) style.padding.y)) + +(fn ReplView.submit [self ?cmd] + (local cmd (or ?cmd self.cmd)) + (when (= ?cmd nil) + (set self.cmd "")) + (self:append {:draw (util.fn ReplView :draw-cmd) : cmd}) + (self.conn:submit cmd)) + +(fn ReplView.draw [self] + (self:draw_background style.background) + (self:draw_scrollbar) + (var x (- self.position.x self.scroll.x)) + (var y (- self.position.y self.scroll.y)) + (var rendered-h 0) + + ; todo: cache sizes and avoid drawing if offscreen? + ; note: then offscreen items can't be focussed without further effort + ; todo: draw line numbers + (each [i line (ipairs self.log)] + (let [h (line:draw self x y)] + (set y (+ y h)) + (set rendered-h (+ rendered-h h)))) + + (set self.cmd (textbox self :command self.cmd x y self.size.x)) + + (local pin-to-bottom (>= self.scroll.to.y (- self.scrollheight self.size.y))) + (set self.scrollheight (+ rendered-h (style.font:get_height) 4)) + (when pin-to-bottom + (set self.scroll.to.y (- self.scrollheight self.size.y)))) + +ReplView + diff --git a/lib/util.fnl b/lib/util.fnl index e7e8097..2676d3e 100644 --- a/lib/util.fnl +++ b/lib/util.fnl @@ -76,8 +76,21 @@ (fn in-coro [f ...] (-> (coroutine.create f) (coroutine.resume ...))) +(fn multival-next [multival i] + (when (< i multival.n) + (values (+ i 1) (. multival (+ i 1))))) + +(fn multival-ipairs [multival] + (values multival-next multival 0)) + +(fn multival [...] + (local multival {:n (select :# ...) :ipairs multival-ipairs}) + (for [i 1 multival.n] + (tset multival i (select i ...))) + multival) + {: int8-to-bytes : int16-to-bytes : int24-to-bytes : bytes-to-uint8 : bytes-to-uint16 : bytes-to-uint24 : splice : lo : hi : reload : hotswap : swappable :require swappable-require :fn mk-swappable-fn - : readjson : writejson : waitfor : in-coro} + : readjson : writejson : waitfor : in-coro : multival} diff --git a/todo.txt b/todo.txt index b9a1971..b777f82 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,11 @@ TODO: +* all usages of util.fn are wrong!! you can't use the table as locally defined as it will disappear!!! aargh * tile editor (geometric shapes for now?) +DEBUG TOOLS: +#1 problem: update failing crashes the editor +- store exception and stop running game; patch and restart + +Repl-y thing: +appends objects to a list (inspectable?) +