Note: I know this is a dirty hack, but it works extremely well for my cases.
I've been using an approach for providing both functions and macros from a single .fnl
file. The caveat is that it needs to be required in a special way.
For example, here's how I require my async.fnl library:
(local a (require :async))
(import-macros {: go} (doto :async require))
Here are the error messages I get in my LSP client:
8 0 error l-d---b [string "require("lib.async")..."]:1: module 'lib.async' not found:
160 11 error l-d---b unknown identifier: go
fennel-ls
doesn't seem to recognize the (doto :lib.async require)
part, because if I just do (import-macros {: go} :async)
it doesn't complain anymore, but this breaks my library.
A basic single-file macro-function library looks like this:
(eval-compiler
(local lib-name
(or ... :do1))
(fn do-1 [expr ...]
`(let [res# ,expr]
(do ,...)
res#))
(tset macro-loaded lib-name {: do-1}))
(require-macros (or ... :do1))
(fn some-fn [x y]
(do-1 (+ x y)
(print :done)))
{: some-fn}
It can then be used in the REPL:
>> (require-macros (doto :do1 require))
nil
>> (do-1 (+ 1 2) (print :done))
done
3
>> (local {: some-fn} (require :do1))
nil
>> (some-fn 1 3)
done
4
Any chance this pattern could be supported by fennel-ls
?
Note, the errors were from the actual project, I just forgot to mention that (hence the
lib.async
, and not justasync
)
More examples of libraries that use this approach (if you need this for testing purposes):