Right now, loading plugins has a few barriers that make it difficult to easily integrate them into, say, the REPL without
For the CLI, it would be useful to accept lua plugins either with the
--plugin
option (by extension) or via an extra --lua-plugin
option.
The main use-case here is to leverage AOT compilation either for plugins
written in a different fennel version or, more likely, to precompile a plugin
with --require-as-include
to bundle in any library component it relies upon.
Additionally, loading plugins by way of the Fennel API (instead of CLI) currently requires manually reproducing the code in launcher.fnl, as in the usecase example below.
I have a WIP pretty-macrodebug
plugin to replace the old macro hack
implementation in fnlfmt. It works, but depends on fnlfmt.fnl being somewhere
on fennel.path
. It would be a lot more useful in tooling plugins that
incorporate a library to be able to simply drop a single file either into a
project, or into e.g. ${XDG_CONFIG_HOME/fennel
for easy use from fennelrc.
Currently, using the plugin requires a fair amount of boilerplate:
(local (*opts* {: view &as fennel}) ...)
(local {:format str/fmt :gmatch str/gmatch :gsub str/gsub :sub str/sub} string)
(local HOME (os.getenv :HOME))
(local dir-sep (str/sub package.config 1 1))
(λ warn [msg-str ...]
(if (= 0 (select :# ...))
(io.stderr:write (.. msg-str "\n"))
(io.stderr:write (str/fmt (.. msg-str "\n") ...)))
nil)
(fn pat/escape [str]
(str/gsub str "([#$%^%%&*()%][-])" "%%%1") )
(fn tbl/copy [from to]
(collect [k v (pairs (or from {})) &into (or to {})] k v))
(fn str/split [str sep]
(icollect [part (str/gmatch str (.. "[^" (pat/escape sep) "]+"))]
part))
(fn load-plugin [plugin-file ?opts ...]
(let [opts (tbl/copy (or ?opts {})
{:env :_COMPILER :compiler-env _G :useMetadata true})
(ok plugin) (pcall fnl.dofile plugin-file opts ...) ]
(if ok
(table.insert *opts*.plugins plugin)
(warn (.. "Failed to load plugin '%s': %s" plugin-file
(or (and plugin (tostring plugin)) ""))))
ok))
;; load REPL plugins
(let [fnlfmt-path (table.concat [HOME "dev" "fnl-libs" "fnlfmt"] dir-sep)]
;; pretty-macrodebug needs fnlfmt on package.path
(set fnl.path (.. fnl.path ";" fnlfmt-path dir-sep "?.fnl"))
(load-plugin (.. fnlfmt-path dir-sep "macrodebug-plugin.fnl") {} ...))
Implemented in 4217c2f but not documented for now because I think we should probably treat it as experimental for a while.