@@ 1,9 1,6 @@
package.path = "./?.lua"
local js = require("js")
-local fennel = require("fennel/fennel")
-local highlight = require("highlight")
-
-- minimal shims just to allow the compilers to load in Fengari
package.loaded.ffi = {typeof=function() end}
os = {getenv=function() end}
@@ 47,7 44,8 @@ lua_source.onkeydown = function(_,e)
end
end
--- Syntax highlighting is adapted from this guide: https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code/
+-- Syntax highlighting is adapted from this guide:
+-- https://css-tricks.com/creating-an-editable-textarea-that-supports-syntax-highlighted-code/
--
-- TL;DR: To highlight syntax in a user-editable textarea, we
-- 1. Copy the contents of the textarea on every edit
@@ 57,9 55,101 @@ end
-- and ensure the input textarea and output pre have the same dimensions
-- using a bunch of CSS
-local syntax = fennel.syntax()
+local syntax = {["#"] = {["special?"] = true}, ["%"] = {["special?"] = true}, ["*"] = {["special?"] = true}, ["+"] = {["special?"] = true}, ["-"] = {["special?"] = true}, ["->"] = {["macro?"] = true}, ["->>"] = {["macro?"] = true}, ["-?>"] = {["macro?"] = true}, ["-?>>"] = {["macro?"] = true}, ["."] = {["special?"] = true}, [".."] = {["special?"] = true}, ["/"] = {["special?"] = true}, ["//"] = {["special?"] = true}, [":"] = {["special?"] = true}, ["<"] = {["special?"] = true}, ["<="] = {["special?"] = true}, ["="] = {["special?"] = true}, [">"] = {["special?"] = true}, [">="] = {["special?"] = true}, ["?."] = {["macro?"] = true}, ["^"] = {["special?"] = true}, _G = {["global?"] = true}, __ = {["global?"] = true}, ___replLocals___ = {["global?"] = true}, accumulate = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, ["and"] = {["special?"] = true}, arg = {["global?"] = true}, assert = {["function?"] = true, ["global?"] = true}, band = {["special?"] = true}, bit32 = {["global?"] = true}, ["bit32.arshift"] = {["function?"] = true, ["global?"] = true}, ["bit32.band"] = {["function?"] = true, ["global?"] = true}, ["bit32.bnot"] = {["function?"] = true, ["global?"] = true}, ["bit32.bor"] = {["function?"] = true, ["global?"] = true}, ["bit32.btest"] = {["function?"] = true, ["global?"] = true}, ["bit32.bxor"] = {["function?"] = true, ["global?"] = true}, ["bit32.extract"] = {["function?"] = true, ["global?"] = true}, ["bit32.lrotate"] = {["function?"] = true, ["global?"] = true}, ["bit32.lshift"] = {["function?"] = true, ["global?"] = true}, ["bit32.replace"] = {["function?"] = true, ["global?"] = true}, ["bit32.rrotate"] = {["function?"] = true, ["global?"] = true}, ["bit32.rshift"] = {["function?"] = true, ["global?"] = true}, bnot = {["special?"] = true}, bor = {["special?"] = true}, bxor = {["special?"] = true}, case = {["body-form?"] = true, ["macro?"] = true}, ["case-try"] = {["body-form?"] = true, ["macro?"] = true}, collect = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, collectgarbage = {["function?"] = true, ["global?"] = true}, comment = {["body-form?"] = true, ["special?"] = true}, coroutine = {["global?"] = true}, ["coroutine.create"] = {["function?"] = true, ["global?"] = true}, ["coroutine.isyieldable"] = {["function?"] = true, ["global?"] = true}, ["coroutine.resume"] = {["function?"] = true, ["global?"] = true}, ["coroutine.running"] = {["function?"] = true, ["global?"] = true}, ["coroutine.status"] = {["function?"] = true, ["global?"] = true}, ["coroutine.wrap"] = {["function?"] = true, ["global?"] = true}, ["coroutine.yield"] = {["function?"] = true, ["global?"] = true}, debug = {["global?"] = true}, ["debug.debug"] = {["function?"] = true, ["global?"] = true}, ["debug.gethook"] = {["function?"] = true, ["global?"] = true}, ["debug.getinfo"] = {["function?"] = true, ["global?"] = true}, ["debug.getlocal"] = {["function?"] = true, ["global?"] = true}, ["debug.getmetatable"] = {["function?"] = true, ["global?"] = true}, ["debug.getregistry"] = {["function?"] = true, ["global?"] = true}, ["debug.getupvalue"] = {["function?"] = true, ["global?"] = true}, ["debug.getuservalue"] = {["function?"] = true, ["global?"] = true}, ["debug.sethook"] = {["function?"] = true, ["global?"] = true}, ["debug.setlocal"] = {["function?"] = true, ["global?"] = true}, ["debug.setmetatable"] = {["function?"] = true, ["global?"] = true}, ["debug.setupvalue"] = {["function?"] = true, ["global?"] = true}, ["debug.setuservalue"] = {["function?"] = true, ["global?"] = true}, ["debug.traceback"] = {["function?"] = true, ["global?"] = true}, ["debug.upvalueid"] = {["function?"] = true, ["global?"] = true}, ["debug.upvaluejoin"] = {["function?"] = true, ["global?"] = true}, ["do"] = {["body-form?"] = true, ["special?"] = true}, dofile = {["function?"] = true, ["global?"] = true}, doto = {["body-form?"] = true, ["macro?"] = true}, each = {["binding-form?"] = true, ["body-form?"] = true, ["special?"] = true}, error = {["function?"] = true, ["global?"] = true}, ["eval-compiler"] = {["body-form?"] = true, ["special?"] = true}, faccumulate = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, fcollect = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, fn = {["body-form?"] = true, ["define?"] = true, ["special?"] = true}, fnl = {["global?"] = true}, ["fnl.ast-source"] = {["function?"] = true, ["global?"] = true}, ["fnl.comment"] = {["function?"] = true, ["global?"] = true}, ["fnl.comment?"] = {["function?"] = true, ["global?"] = true}, ["fnl.compile"] = {["function?"] = true, ["global?"] = true}, ["fnl.compile-stream"] = {["function?"] = true, ["global?"] = true}, ["fnl.compile-string"] = {["function?"] = true, ["global?"] = true}, ["fnl.compile1"] = {["function?"] = true, ["global?"] = true}, ["fnl.compileStream"] = {["function?"] = true, ["global?"] = true}, ["fnl.compileString"] = {["function?"] = true, ["global?"] = true}, ["fnl.doc"] = {["function?"] = true, ["global?"] = true}, ["fnl.dofile"] = {["function?"] = true, ["global?"] = true}, ["fnl.eval"] = {["function?"] = true, ["global?"] = true}, ["fnl.gensym"] = {["function?"] = true, ["global?"] = true}, ["fnl.granulate"] = {["function?"] = true, ["global?"] = true}, ["fnl.install"] = {["function?"] = true, ["global?"] = true}, ["fnl.list"] = {["function?"] = true, ["global?"] = true}, ["fnl.list?"] = {["function?"] = true, ["global?"] = true}, ["fnl.load-code"] = {["function?"] = true, ["global?"] = true}, ["fnl.loadCode"] = {["function?"] = true, ["global?"] = true}, ["fnl.make-searcher"] = {["function?"] = true, ["global?"] = true}, ["fnl.makeSearcher"] = {["function?"] = true, ["global?"] = true}, ["fnl.make_searcher"] = {["function?"] = true, ["global?"] = true}, ["fnl.mangle"] = {["function?"] = true, ["global?"] = true}, ["fnl.multi-sym?"] = {["function?"] = true, ["global?"] = true}, ["fnl.parser"] = {["function?"] = true, ["global?"] = true}, ["fnl.repl"] = {["function?"] = true, ["global?"] = true}, ["fnl.runtime-version"] = {["function?"] = true, ["global?"] = true}, ["fnl.runtimeVersion"] = {["function?"] = true, ["global?"] = true}, ["fnl.scope"] = {["function?"] = true, ["global?"] = true}, ["fnl.search-module"] = {["function?"] = true, ["global?"] = true}, ["fnl.searchModule"] = {["function?"] = true, ["global?"] = true}, ["fnl.searcher"] = {["function?"] = true, ["global?"] = true}, ["fnl.sequence"] = {["function?"] = true, ["global?"] = true}, ["fnl.sequence?"] = {["function?"] = true, ["global?"] = true}, ["fnl.string-stream"] = {["function?"] = true, ["global?"] = true}, ["fnl.stringStream"] = {["function?"] = true, ["global?"] = true}, ["fnl.sym"] = {["function?"] = true, ["global?"] = true}, ["fnl.sym-char?"] = {["function?"] = true, ["global?"] = true}, ["fnl.sym?"] = {["function?"] = true, ["global?"] = true}, ["fnl.syntax"] = {["function?"] = true, ["global?"] = true}, ["fnl.table?"] = {["function?"] = true, ["global?"] = true}, ["fnl.traceback"] = {["function?"] = true, ["global?"] = true}, ["fnl.unmangle"] = {["function?"] = true, ["global?"] = true}, ["fnl.varg"] = {["function?"] = true, ["global?"] = true}, ["fnl.varg?"] = {["function?"] = true, ["global?"] = true}, ["fnl.view"] = {["function?"] = true, ["global?"] = true}, ["for"] = {["binding-form?"] = true, ["body-form?"] = true, ["special?"] = true}, getmetatable = {["function?"] = true, ["global?"] = true}, global = {["define?"] = true, ["special?"] = true}, hashfn = {["special?"] = true}, icollect = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, ["if"] = {["special?"] = true}, ["import-macros"] = {["macro?"] = true}, include = {["special?"] = true}, io = {["global?"] = true}, ["io.close"] = {["function?"] = true, ["global?"] = true}, ["io.flush"] = {["function?"] = true, ["global?"] = true}, ["io.input"] = {["function?"] = true, ["global?"] = true}, ["io.lines"] = {["function?"] = true, ["global?"] = true}, ["io.open"] = {["function?"] = true, ["global?"] = true}, ["io.output"] = {["function?"] = true, ["global?"] = true}, ["io.popen"] = {["function?"] = true, ["global?"] = true}, ["io.read"] = {["function?"] = true, ["global?"] = true}, ["io.tmpfile"] = {["function?"] = true, ["global?"] = true}, ["io.type"] = {["function?"] = true, ["global?"] = true}, ["io.write"] = {["function?"] = true, ["global?"] = true}, ipairs = {["function?"] = true, ["global?"] = true}, lambda = {["body-form?"] = true, ["define?"] = true, ["macro?"] = true}, length = {["special?"] = true}, let = {["binding-form?"] = true, ["body-form?"] = true, ["special?"] = true}, load = {["function?"] = true, ["global?"] = true}, loadfile = {["function?"] = true, ["global?"] = true}, ["local"] = {["define?"] = true, ["special?"] = true}, lshift = {["special?"] = true}, lua = {["special?"] = true}, macro = {["body-form?"] = true, ["define?"] = true, ["macro?"] = true}, macrodebug = {["macro?"] = true}, macros = {["define?"] = true, ["special?"] = true}, match = {["body-form?"] = true, ["macro?"] = true}, ["match-try"] = {["body-form?"] = true, ["macro?"] = true}, math = {["global?"] = true}, ["math.abs"] = {["function?"] = true, ["global?"] = true}, ["math.acos"] = {["function?"] = true, ["global?"] = true}, ["math.asin"] = {["function?"] = true, ["global?"] = true}, ["math.atan"] = {["function?"] = true, ["global?"] = true}, ["math.atan2"] = {["function?"] = true, ["global?"] = true}, ["math.ceil"] = {["function?"] = true, ["global?"] = true}, ["math.cos"] = {["function?"] = true, ["global?"] = true}, ["math.cosh"] = {["function?"] = true, ["global?"] = true}, ["math.deg"] = {["function?"] = true, ["global?"] = true}, ["math.exp"] = {["function?"] = true, ["global?"] = true}, ["math.floor"] = {["function?"] = true, ["global?"] = true}, ["math.fmod"] = {["function?"] = true, ["global?"] = true}, ["math.frexp"] = {["function?"] = true, ["global?"] = true}, ["math.ldexp"] = {["function?"] = true, ["global?"] = true}, ["math.log"] = {["function?"] = true, ["global?"] = true}, ["math.log10"] = {["function?"] = true, ["global?"] = true}, ["math.max"] = {["function?"] = true, ["global?"] = true}, ["math.min"] = {["function?"] = true, ["global?"] = true}, ["math.modf"] = {["function?"] = true, ["global?"] = true}, ["math.pow"] = {["function?"] = true, ["global?"] = true}, ["math.rad"] = {["function?"] = true, ["global?"] = true}, ["math.random"] = {["function?"] = true, ["global?"] = true}, ["math.randomseed"] = {["function?"] = true, ["global?"] = true}, ["math.sin"] = {["function?"] = true, ["global?"] = true}, ["math.sinh"] = {["function?"] = true, ["global?"] = true}, ["math.sqrt"] = {["function?"] = true, ["global?"] = true}, ["math.tan"] = {["function?"] = true, ["global?"] = true}, ["math.tanh"] = {["function?"] = true, ["global?"] = true}, ["math.tointeger"] = {["function?"] = true, ["global?"] = true}, ["math.type"] = {["function?"] = true, ["global?"] = true}, ["math.ult"] = {["function?"] = true, ["global?"] = true}, next = {["function?"] = true, ["global?"] = true}, ["not"] = {["special?"] = true}, ["not="] = {["special?"] = true}, ["or"] = {["special?"] = true}, os = {["global?"] = true}, ["os.clock"] = {["function?"] = true, ["global?"] = true}, ["os.date"] = {["function?"] = true, ["global?"] = true}, ["os.difftime"] = {["function?"] = true, ["global?"] = true}, ["os.execute"] = {["function?"] = true, ["global?"] = true}, ["os.exit"] = {["function?"] = true, ["global?"] = true}, ["os.getenv"] = {["function?"] = true, ["global?"] = true}, ["os.remove"] = {["function?"] = true, ["global?"] = true}, ["os.rename"] = {["function?"] = true, ["global?"] = true}, ["os.setlocale"] = {["function?"] = true, ["global?"] = true}, ["os.time"] = {["function?"] = true, ["global?"] = true}, ["os.tmpname"] = {["function?"] = true, ["global?"] = true}, package = {["global?"] = true}, ["package.loadlib"] = {["function?"] = true, ["global?"] = true}, ["package.searchpath"] = {["function?"] = true, ["global?"] = true}, pairs = {["function?"] = true, ["global?"] = true}, partial = {["macro?"] = true}, pcall = {["function?"] = true, ["global?"] = true}, ["pick-args"] = {["macro?"] = true}, ["pick-values"] = {["macro?"] = true}, print = {["function?"] = true, ["global?"] = true}, quote = {["special?"] = true}, rawequal = {["function?"] = true, ["global?"] = true}, rawget = {["function?"] = true, ["global?"] = true}, rawlen = {["function?"] = true, ["global?"] = true}, rawset = {["function?"] = true, ["global?"] = true}, require = {["function?"] = true, ["global?"] = true}, ["require-macros"] = {["special?"] = true}, rshift = {["special?"] = true}, select = {["function?"] = true, ["global?"] = true}, set = {["special?"] = true}, ["set-forcibly!"] = {["special?"] = true}, setmetatable = {["function?"] = true, ["global?"] = true}, string = {["global?"] = true}, ["string.byte"] = {["function?"] = true, ["global?"] = true}, ["string.char"] = {["function?"] = true, ["global?"] = true}, ["string.dump"] = {["function?"] = true, ["global?"] = true}, ["string.find"] = {["function?"] = true, ["global?"] = true}, ["string.format"] = {["function?"] = true, ["global?"] = true}, ["string.gmatch"] = {["function?"] = true, ["global?"] = true}, ["string.gsub"] = {["function?"] = true, ["global?"] = true}, ["string.len"] = {["function?"] = true, ["global?"] = true}, ["string.lower"] = {["function?"] = true, ["global?"] = true}, ["string.match"] = {["function?"] = true, ["global?"] = true}, ["string.pack"] = {["function?"] = true, ["global?"] = true}, ["string.packsize"] = {["function?"] = true, ["global?"] = true}, ["string.rep"] = {["function?"] = true, ["global?"] = true}, ["string.reverse"] = {["function?"] = true, ["global?"] = true}, ["string.sub"] = {["function?"] = true, ["global?"] = true}, ["string.unpack"] = {["function?"] = true, ["global?"] = true}, ["string.upper"] = {["function?"] = true, ["global?"] = true}, table = {["global?"] = true}, ["table.concat"] = {["function?"] = true, ["global?"] = true}, ["table.insert"] = {["function?"] = true, ["global?"] = true}, ["table.move"] = {["function?"] = true, ["global?"] = true}, ["table.pack"] = {["function?"] = true, ["global?"] = true}, ["table.remove"] = {["function?"] = true, ["global?"] = true}, ["table.sort"] = {["function?"] = true, ["global?"] = true}, ["table.unpack"] = {["function?"] = true, ["global?"] = true}, tonumber = {["function?"] = true, ["global?"] = true}, tostring = {["function?"] = true, ["global?"] = true}, tset = {["special?"] = true}, type = {["function?"] = true, ["global?"] = true}, utf8 = {["global?"] = true}, ["utf8.char"] = {["function?"] = true, ["global?"] = true}, ["utf8.codepoint"] = {["function?"] = true, ["global?"] = true}, ["utf8.codes"] = {["function?"] = true, ["global?"] = true}, ["utf8.len"] = {["function?"] = true, ["global?"] = true}, ["utf8.offset"] = {["function?"] = true, ["global?"] = true}, values = {["special?"] = true}, var = {["define?"] = true, ["special?"] = true}, when = {["body-form?"] = true, ["macro?"] = true}, ["while"] = {["body-form?"] = true, ["special?"] = true}, ["with-open"] = {["binding-form?"] = true, ["body-form?"] = true, ["macro?"] = true}, xpcall = {["function?"] = true, ["global?"] = true}, ["~="] = {["special?"] = true}, ["\206\187"] = {["body-form?"] = true, ["define?"] = true, ["macro?"] = true}}
+
+local function scan(text)
+ local current_index = 1
+ local last_matching_at = 0
+ local text_length = string.len(text)
+ local function at_eof_3f()
+ return (current_index > text_length)
+ end
+ local function yield_buffered_nonmatching()
+ if (0 < (current_index - last_matching_at)) then
+ return coroutine.yield({kind = nil, value = string.sub(text, (last_matching_at + 1), (current_index - 1))})
+ else
+ return nil
+ end
+ end
+ local function yield(kind, matched)
+ yield_buffered_nonmatching()
+ coroutine.yield({kind = kind, value = matched})
+ current_index = (current_index + string.len(matched))
+ last_matching_at = (current_index - 1)
+ return nil
+ end
+ local function attempt_match(kind, pattern)
+ local _2_ = string.match(text, pattern, current_index)
+ if (nil ~= _2_) then
+ local matched = _2_
+ yield(kind, matched)
+ return true
+ else
+ return nil
+ end
+ end
+ local function increment_current_index()
+ current_index = (current_index + 1)
+ return nil
+ end
+ local symbol_char = "!%$&#%*%+%-%./:<=>%?%^_%w"
+ while not at_eof_3f() do
+ do local _ = (attempt_match("comment", "^(;[^\n]*[\n])") or attempt_match("string", "^(\"[^\"]*\")") or attempt_match("keyword", ("^(:[" .. symbol_char .. "]+)")) or attempt_match("number", "^([%+%-]?%d+[xX]?%d*%.?%d?)") or attempt_match("nil", ("^(nil)[^" .. symbol_char .. "]")) or attempt_match("boolean", ("^(true)[^" .. symbol_char .. "]")) or attempt_match("boolean", ("^(false)[^" .. symbol_char .. "]")) or attempt_match("symbol", ("^([" .. symbol_char .. "]+)")) or attempt_match("bracket", "^([%(%)%[%]{}])") or increment_current_index()) end
+ end
+ return yield_buffered_nonmatching()
+end
+local function with_symbol_subkind(syntax, _4_)
+ local _arg_5_ = _4_
+ local token = _arg_5_
+ local kind = _arg_5_["kind"]
+ local value = _arg_5_["value"]
+ if ("symbol" == kind) then
+ local _6_ = syntax[value]
+ if ((_G.type(_6_) == "table") and ((_6_)["special?"] == true)) then
+ token.subkind = "special-symbol"
+ elseif ((_G.type(_6_) == "table") and ((_6_)["macro?"] == true)) then
+ token.subkind = "macro-symbol"
+ elseif ((_G.type(_6_) == "table") and ((_6_)["global?"] == true)) then
+ token.subkind = "global-symbol"
+ else
+ token.subkind = nil
+ end
+ else
+ end
+ return token
+end
+local function token__3ehtml(_9_)
+ local _arg_10_ = _9_
+ local kind = _arg_10_["kind"]
+ local subkind = _arg_10_["subkind"]
+ local value = _arg_10_["value"]
+ local class = ((kind or "nonmatching") .. " " .. (subkind or ""))
+ local escaped_value = string.gsub(string.gsub(value, "&", "&"), "<", "<")
+ return ("<span class=\"" .. class .. "\">" .. escaped_value .. "</span>")
+end
+local function for_html(syntax, code)
+ local tokens
+ do
+ local tbl_17_auto = {}
+ local i_18_auto = #tbl_17_auto
+ local function _11_()
+ return scan((code .. "\n"))
+ end
+ for token in coroutine.wrap(_11_) do
+ local val_19_auto = token__3ehtml(with_symbol_subkind(syntax, token))
+ if (nil ~= val_19_auto) then
+ i_18_auto = (i_18_auto + 1)
+ do end (tbl_17_auto)[i_18_auto] = val_19_auto
+ else
+ end
+ end
+ tokens = tbl_17_auto
+ end
+ return table.concat(tokens)
+end
+
function highlight_fennel()
- fennel_highlighted.innerHTML = highlight.for_html(syntax, fennel_source.value)
+ fennel_highlighted.innerHTML = for_html(syntax, fennel_source.value)
end
function highlight_lua()