Merge branch 'eb/add-love2d'
Thank you to emlabee for adding love2d support! fennel-ls#32
This commit is contained in:
commit
64e909c457
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
/result
|
||||
/lua*.html
|
||||
/build
|
||||
/src/fennel-ls/docs/generated/love2d.fnl
|
||||
|
||||
2
Makefile
2
Makefile
@ -30,7 +30,7 @@ repl:
|
||||
$(FENNEL) $(FENNELFLAGS)
|
||||
|
||||
docs:
|
||||
$(FENNEL) $(FENNELFLAGS) tools/get-docs.fnl
|
||||
$(FENNEL) $(FENNELFLAGS) tools/get-docs.fnl $(GET_DOCS_FLAGS)
|
||||
|
||||
rm-docs:
|
||||
rm -rf src/fennel-ls/docs/
|
||||
|
||||
@ -70,7 +70,8 @@ The default `flsproject.fnl` settings are:
|
||||
{:fennel-path "./?.fnl;./?/init.fnl;src/?.fnl;src/?/init.fnl"
|
||||
:macro-path "./?.fnl;./?/init-macros.fnl;./?/init.fnl;src/?.fnl;src/?/init-macros.fnl;src/?/init.fnl"
|
||||
:lua-version "lua54"
|
||||
:libraries {:tic-80 false}
|
||||
:libraries {:love2d false
|
||||
:tic-80 false}
|
||||
:extra-globals ""
|
||||
:lints {:unused-definition true
|
||||
:unknown-module-field true
|
||||
|
||||
@ -21,6 +21,17 @@ $ make rm-docs
|
||||
$ make docs
|
||||
```
|
||||
|
||||
## Including LÖVE documentation
|
||||
Due to license incompatibility between fennel-ls and the official LÖVE
|
||||
documentation, this repository cannot include the LÖVE documentation by
|
||||
default. It must be generated manually.
|
||||
|
||||
This can be done by passing a flag to the `docs` target.
|
||||
|
||||
```sh
|
||||
$ make docs GET_DOCS_FLAGS=--generate-love2d
|
||||
```
|
||||
|
||||
## Vendored Dependencies
|
||||
The vendored dependencies are very easy to solve. You delete the dependency
|
||||
files by running `make rm-deps`.
|
||||
|
||||
@ -27,7 +27,7 @@ There are no global settings. They're all stored in the `server` object.
|
||||
:var-never-set (option true)
|
||||
:op-with-no-arguments (option true)
|
||||
:multival-in-middle-of-call (option true)}
|
||||
:libraries {:tic-80 (option false)}
|
||||
:libraries {:love2d (option false) :tic-80 (option false)}
|
||||
:extra-globals (option "")})
|
||||
|
||||
(fn make-configuration-from-template [default ?user ?parent]
|
||||
@ -72,7 +72,7 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf-
|
||||
|
||||
(λ load-config [server]
|
||||
"This is where we can put anything that needs to react to config changes"
|
||||
|
||||
|
||||
(make-configuration
|
||||
(when server.root-uri
|
||||
(-?> (files.read-file server (utils.path->uri (utils.path-join (utils.uri->path server.root-uri) "flsproject.fnl")))
|
||||
|
||||
@ -28,6 +28,10 @@
|
||||
(local libraries
|
||||
{:tic-80 (require :fennel-ls.docs.generated.tic80)})
|
||||
|
||||
;; can't just pcall require because we want to trigger require-as-include
|
||||
(case (pcall #(require :fennel-ls.docs.generated.love2d))
|
||||
(true love2d) (set libraries.love2d love2d))
|
||||
|
||||
(fn get-library [library]
|
||||
(when (not (. libraries library))
|
||||
(error (.. "fennel-ls doesn't know about library " library "\n"
|
||||
@ -44,13 +48,14 @@
|
||||
(icollect [name (pairs (get-lua-version server.configuration.lua-version)) &into result]
|
||||
name)))
|
||||
|
||||
(fn get-library-global [server global-name]
|
||||
(accumulate [g nil library-name enabled? (pairs server.configuration.libraries)
|
||||
&until g]
|
||||
(and enabled? (. (get-library library-name) global-name))))
|
||||
|
||||
(fn get-global [server global-name]
|
||||
(or
|
||||
(and server.configuration.libraries.tic-80
|
||||
(. (get-library :tic-80)
|
||||
global-name))
|
||||
(. (get-lua-version server.configuration.lua-version)
|
||||
global-name)))
|
||||
(or (get-library-global server global-name)
|
||||
(. (get-lua-version server.configuration.lua-version) global-name)))
|
||||
|
||||
(fn get-builtin [_server builtin-name]
|
||||
(or (. specials builtin-name)
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
"Script to generate /src/fennel-ls/docs/lua54.fnl and friends automatically"
|
||||
|
||||
(local {: sh} (require :tools.util.sh))
|
||||
(local fennel (require :deps.fennel))
|
||||
|
||||
(fn curl-cached [url]
|
||||
(let [filename (.. "build/" (url:gsub "[/:]" "_"))
|
||||
@ -10,24 +12,33 @@
|
||||
(sh "curl" url [">"] filename)
|
||||
(io.open filename :r)))))
|
||||
|
||||
(fn write-doc-file! [out-filename doc-src doc-tbl]
|
||||
(assert doc-tbl
|
||||
"bad argument #3, `doc-tbl` to write-doc-file! (expected string, got nil)")
|
||||
(with-open [file (io.open (.. :src/fennel-ls/docs/generated/ out-filename) :w)]
|
||||
(file:write ";; auto-generated by `make docs` from fennel-ls. Contents come from "
|
||||
doc-src "\n" doc-tbl "\n")))
|
||||
|
||||
(fn derive-docs-from-url [url out-filename convert]
|
||||
(let [result
|
||||
(convert
|
||||
(with-open [file (curl-cached url)]
|
||||
(file:read "*a")))]
|
||||
(with-open [file (io.open (.. "src/fennel-ls/docs/generated/" out-filename) :w)]
|
||||
(file:write ";; auto-generated by `make docs` from fennel-ls. Contents come from " url "\n"
|
||||
result "\n"))))
|
||||
(write-doc-file! out-filename url
|
||||
(convert (with-open [file (curl-cached url)]
|
||||
(file:read :*a)))))
|
||||
|
||||
(fn main []
|
||||
(sh :mkdir :-p "build/")
|
||||
(sh :mkdir :-p "src/fennel-ls/docs/generated/")
|
||||
(let [{:convert lua-manual} (require :tools.get-docs.lua-manual)
|
||||
(let [generate-love2d-docs? (case arg ["--generate-love2d"] true _ false)
|
||||
{:convert lua-manual} (require :tools.get-docs.lua-manual)
|
||||
{:convert tic-manual} (require :tools.get-docs.tic80)]
|
||||
(derive-docs-from-url "https://www.lua.org/manual/5.1/manual.html" "lua51.fnl" lua-manual)
|
||||
(derive-docs-from-url "https://www.lua.org/manual/5.2/manual.html" "lua52.fnl" lua-manual)
|
||||
(derive-docs-from-url "https://www.lua.org/manual/5.3/manual.html" "lua53.fnl" lua-manual)
|
||||
(derive-docs-from-url "https://www.lua.org/manual/5.4/manual.html" "lua54.fnl" lua-manual)
|
||||
(derive-docs-from-url "https://tic80.com/learn" "tic80.fnl" tic-manual)))
|
||||
(derive-docs-from-url "https://tic80.com/learn" :tic80.fnl tic-manual)
|
||||
(when generate-love2d-docs?
|
||||
(let [{:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)]
|
||||
(write-doc-file! :love2d.fnl
|
||||
"https://github.com/love2d-community/love-api/"
|
||||
(download-and-convert-love2d-manual!))))))
|
||||
|
||||
(main)
|
||||
|
||||
104
tools/get-docs/love2d.fnl
Normal file
104
tools/get-docs/love2d.fnl
Normal file
@ -0,0 +1,104 @@
|
||||
(local fennel (require :deps.fennel))
|
||||
(local {:clone git-clone} (require :tools.util.git))
|
||||
|
||||
(local love-api-build-directory :build/love-api)
|
||||
(local require-love-api
|
||||
(partial require (.. love-api-build-directory :/love_api)))
|
||||
|
||||
;
|
||||
; UTILS
|
||||
; -----
|
||||
(fn build-lsp-value [name ?args ?docstring ?fields]
|
||||
"Takes ... and returns a table to be used with the LSP."
|
||||
(let [lsp-value {:binding name}
|
||||
?metadata (or ?args ?docstring)]
|
||||
(when ?metadata (set lsp-value.metadata {}))
|
||||
(when ?args (set lsp-value.metadata.fnl/arglist ?args))
|
||||
(when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring))
|
||||
(when ?fields (set lsp-value.fields ?fields))
|
||||
lsp-value))
|
||||
|
||||
(fn clone-love-api! []
|
||||
(when (not (io.open :build/love-api))
|
||||
(git-clone love-api-build-directory
|
||||
"https://github.com/love2d-community/love-api")))
|
||||
|
||||
(fn merge [...]
|
||||
(let [arg-count (select "#" ...)
|
||||
args [...]]
|
||||
(if (= arg-count 0)
|
||||
{}
|
||||
(faccumulate [result {} i 1 arg-count]
|
||||
(collect [k v (pairs (. args i)) &into result]
|
||||
(values k v))))))
|
||||
|
||||
;
|
||||
; PARSERS
|
||||
; -------
|
||||
(fn get-fn-argument-names [fn-arguments]
|
||||
"Given an array of arguments, return all names as an array."
|
||||
(icollect [_i {:description _ : name :type _} (ipairs fn-arguments)]
|
||||
name))
|
||||
|
||||
(fn format-description-of-fn-return-values [fn-returns]
|
||||
(accumulate [x "\n\nReturns -" _i {: description : name :type return-type} (ipairs fn-returns)]
|
||||
(.. x "\n" " * " name " (`" return-type "`) - " description)))
|
||||
|
||||
(fn parse-first-fn-variant [[variant]]
|
||||
"Given an array of fuction variants, format and return the first variant
|
||||
for the LSP."
|
||||
(collect [k v (pairs variant)]
|
||||
(case k
|
||||
:returns (values :returns (format-description-of-fn-return-values v))
|
||||
:arguments (values :args (get-fn-argument-names v)))))
|
||||
|
||||
(fn get-all-love-api-functions [love-api]
|
||||
[(table.unpack love-api.functions) (table.unpack love-api.callbacks)])
|
||||
|
||||
(fn love-functions->lsp-table [docs-tbl namespace]
|
||||
(collect [_i value (ipairs docs-tbl)]
|
||||
(let [{: name : description} value
|
||||
binding (.. namespace name)
|
||||
?variants (?. value :variants)
|
||||
; LÖVE functions have several variants, e.g. different arities or
|
||||
; types; however, it's uncertain how to best display all of that
|
||||
; information, so the first is selected here as a reasonable default.
|
||||
first-variant (if ?variants
|
||||
(parse-first-fn-variant ?variants)
|
||||
nil)
|
||||
?args (?. first-variant :args)
|
||||
?returns (or (?. first-variant :returns) "")
|
||||
docstring (.. description ?returns)]
|
||||
(values name (build-lsp-value binding ?args docstring)))))
|
||||
|
||||
(fn module-list->lsp-table [modules ?namespace]
|
||||
(collect [_i module (ipairs modules)]
|
||||
(let [{: name} module ; Other keys - :enum, :functions, :types
|
||||
namespace (if ?namespace (.. ?namespace ".") "")
|
||||
binding (.. namespace name)
|
||||
?docstring (?. module :description)
|
||||
?functions (?. module :functions)
|
||||
?modules (?. module :modules)
|
||||
function-keys (if ?functions
|
||||
(love-functions->lsp-table ?functions (.. binding "."))
|
||||
{})
|
||||
module-keys (if ?modules (module-list->lsp-table ?modules binding) {})
|
||||
fields (merge function-keys module-keys)]
|
||||
(values name (build-lsp-value binding nil ?docstring fields)))))
|
||||
|
||||
(fn love-api->lsp-table [love-api]
|
||||
(let [root-module {:description (.. "LÖVE is a framework for making 2D "
|
||||
"games in the Lua programming language.")
|
||||
:functions (get-all-love-api-functions love-api)
|
||||
:modules love-api.modules
|
||||
:name :love}]
|
||||
(module-list->lsp-table [root-module])))
|
||||
|
||||
(fn convert []
|
||||
"Download documentation for the LÖVE framework via the love-api repo and
|
||||
convert it to a Lua table usable for fennel-ls."
|
||||
(clone-love-api!)
|
||||
(let [love-api (require-love-api)]
|
||||
(fennel.view (love-api->lsp-table love-api))))
|
||||
|
||||
{: convert}
|
||||
12
tools/util/git.fnl
Normal file
12
tools/util/git.fnl
Normal file
@ -0,0 +1,12 @@
|
||||
(local {: sh} (require :tools.util.sh))
|
||||
|
||||
(fn clone [location url ?tag]
|
||||
"Clones a git repository, given a location, url, and optional tag."
|
||||
(assert location "Expected file location to clone git repository into.")
|
||||
(assert url "Expected git repository url to clone.")
|
||||
(if ?tag
|
||||
(sh :git :clone :-c :advice.detachedHead=false :--depth=1 :--branch ?tag
|
||||
url location)
|
||||
(sh :git :clone :-c :advice.detachedHead=false :--depth=1 url location)))
|
||||
|
||||
{: clone}
|
||||
Loading…
Reference in New Issue
Block a user