From 41a92088f84023778d0249fc892b2bef6e15dbe9 Mon Sep 17 00:00:00 2001 From: Emma Date: Sun, 4 Aug 2024 08:46:17 -0400 Subject: [PATCH 01/11] Add git clone utility function --- tools/util/git.fnl | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tools/util/git.fnl diff --git a/tools/util/git.fnl b/tools/util/git.fnl new file mode 100644 index 0000000..ebc9727 --- /dev/null +++ b/tools/util/git.fnl @@ -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} From 2bddb4be3ac08455ff7ba923755f4dc401204b28 Mon Sep 17 00:00:00 2001 From: Emma Date: Sun, 4 Aug 2024 09:10:07 -0400 Subject: [PATCH 02/11] Add non-working love2d documentation tooling and integrate with get-docs.fnl --- tools/get-docs.fnl | 44 ++++++++++++++++++++++++--------------- tools/get-docs/love2d.fnl | 22 ++++++++++++++++++++ 2 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 tools/get-docs/love2d.fnl diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl index e1cd8ad..b83d0ef 100644 --- a/tools/get-docs.fnl +++ b/tools/get-docs.fnl @@ -1,33 +1,43 @@ "Script to generate /src/fennel-ls/docs/lua54.fnl and friends automatically" + (local {: sh} (require :tools.util.sh)) (fn curl-cached [url] - (let [filename (.. "build/" (url:gsub "[/:]" "_")) + (let [filename (.. :build/ (url:gsub "[/:]" "_")) file (io.open filename :r)] (if file file (do - (sh "curl" url [">"] filename) + (sh :curl url [">"] filename) (io.open filename :r))))) +(fn write-doc-file! [out-filename doc-src doc-tbl] + (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/") + (sh :mkdir :-p :build/) + (sh :mkdir :-p :src/fennel-ls/docs/generated/) (let [{: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))) + {:convert tic80-manual} (require :tools.get-docs.tic80) + {:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] + (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 tic80-manual) + (write-doc-file! :love2d.fnl + "https://github.com/love2d-community/love-api/" + (download-and-convert-love2d-manual!)))) (main) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl new file mode 100644 index 0000000..568cd03 --- /dev/null +++ b/tools/get-docs/love2d.fnl @@ -0,0 +1,22 @@ +(local fennel (require :deps.fennel)) +(local {:clone git-clone} (require :tools.util.git)) + +(fn download-love-api-tooling! [] + "Clones the LÖVE-API git repository that contains tooling to scrape and + convert the LÖVE Wiki into a Lua table." + (when (not (io.open :build/love-api)) + (git-clone :build/love-api "https://github.com/love2d-community/love-api"))) + +; EXAMPLE SHAPE +; +; {:love {:binding :love +; :fields {:callbacks {:binding :love.callbacks +; :fields {:mousepressed {:binding :mousepressed +; :metadata {:fnl/arglist [""] +; :fnl/docstring "..."}}}}}}} + +(fn convert [_contents] + (download-love-api-tooling!) + (fennel.view {:love "I did it\\!"})) + +{: convert} From f5bfbf1c26254eb64c1b968a7f39bf40c15a0547 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 10 Aug 2024 15:14:24 -0400 Subject: [PATCH 03/11] Convert primary love object and functions --- tools/get-docs.fnl | 3 ++ tools/get-docs/love2d.fnl | 80 ++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl index b83d0ef..a09bbc2 100644 --- a/tools/get-docs.fnl +++ b/tools/get-docs.fnl @@ -1,6 +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 "[/:]" "_")) @@ -12,6 +13,8 @@ (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"))) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl index 568cd03..2f4845c 100644 --- a/tools/get-docs/love2d.fnl +++ b/tools/get-docs/love2d.fnl @@ -1,22 +1,82 @@ (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))) + +(local stringify-table fennel.view) + (fn download-love-api-tooling! [] "Clones the LÖVE-API git repository that contains tooling to scrape and convert the LÖVE Wiki into a Lua table." (when (not (io.open :build/love-api)) - (git-clone :build/love-api "https://github.com/love2d-community/love-api"))) + (git-clone love-api-build-directory + "https://github.com/love2d-community/love-api"))) -; EXAMPLE SHAPE -; -; {:love {:binding :love -; :fields {:callbacks {:binding :love.callbacks -; :fields {:mousepressed {:binding :mousepressed -; :metadata {:fnl/arglist [""] -; :fnl/docstring "..."}}}}}}} +(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)))))) -(fn convert [_contents] +(fn fn-arguments->names [arguments] + "Given an array of arguments, return all names as an array." + (icollect [_i {:description _ : name :type _} (ipairs arguments)] + name)) + +(fn fn-return->string [returns] + "Given an array of arguments, return a formatted description." + (accumulate [x "\n\nReturns -" _i {: description : name :type return-type} (ipairs returns)] + (.. x "\n" " * " name " (`" return-type "`) - " description))) + +(fn parse-fn-variant [variant] + "Given an array of fuction variants, return an object where the first variant + is made the formatted LSP option, with any remaining variants being formatted + as a single description." + (collect [v-key v-value (pairs variant)] + (case v-key + :returns (values :returns v-value) + :arguments (values :args (fn-arguments->names v-value))))) + +; (fn build-arg-name-list [arguments-tbl] +; "Returns a list of all argument names" +; (print (.. "CHECK OUT THIS TABLE —" (fennel.view arguments-tbl))) +; (icollect [_ v (ipairs arguments-tbl)] +; v.name)) + +(fn build-lsp-value [name ?args ?docstring] + "Takes ... and returns a table to be used with the LSP." + (let [lsp-value {:binding name :metadata {}}] + (when ?args (set lsp-value.metadata.fnl/arglist ?args)) + (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) + lsp-value)) + +(fn get-love-functions [love-docs-tbl] + "Takes the LÖVE-API documentation table and generates a list of the + library-level functions suitable for the Fennel LSP." + (collect [_i value (ipairs love-docs-tbl.functions)] + (let [{: name : description} value + ?variants (?. value :variants) + first-variant (if ?variants + (parse-fn-variant (. ?variants 1)) + nil) + ?args (?. first-variant :args) + ?returns (?. first-variant :returns) + docstring (.. description (if ?returns (fn-return->string ?returns) + ""))] + (values name (build-lsp-value name ?args docstring))))) + +(fn convert [] (download-love-api-tooling!) - (fennel.view {:love "I did it\\!"})) + (let [love-docs-tbl (require-love-api) + love-doc-string (.. "LÖVE is a framework for making " + "2D games in the Lua programming language.") + love-docs (build-lsp-value :love nil love-doc-string) + love-functions {:fields (get-love-functions love-docs-tbl)}] + (stringify-table {:love (merge love-docs love-functions)}))) {: convert} From 0cb16a6456c7492a673d781a0345eb5db9eacd18 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 10 Aug 2024 16:37:16 -0400 Subject: [PATCH 04/11] Parse functions and callbacks from root love table --- tools/get-docs/love2d.fnl | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl index 2f4845c..42fc85f 100644 --- a/tools/get-docs/love2d.fnl +++ b/tools/get-docs/love2d.fnl @@ -21,7 +21,9 @@ {} (faccumulate [result {} i 1 arg-count] (collect [k v (pairs (. args i)) &into result] - (values k v)))))) + (if (?. result k) + (values k (merge v (. result k))) + (values k v))))))) (fn fn-arguments->names [arguments] "Given an array of arguments, return all names as an array." @@ -55,10 +57,13 @@ (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) lsp-value)) -(fn get-love-functions [love-docs-tbl] +; TODO - This function takes the functions object directly, then it can be used +; for any high-level object. + +(fn get-love-functions [docs-tbl] "Takes the LÖVE-API documentation table and generates a list of the library-level functions suitable for the Fennel LSP." - (collect [_i value (ipairs love-docs-tbl.functions)] + (collect [_i value (ipairs docs-tbl)] (let [{: name : description} value ?variants (?. value :variants) first-variant (if ?variants @@ -76,7 +81,8 @@ love-doc-string (.. "LÖVE is a framework for making " "2D games in the Lua programming language.") love-docs (build-lsp-value :love nil love-doc-string) - love-functions {:fields (get-love-functions love-docs-tbl)}] - (stringify-table {:love (merge love-docs love-functions)}))) + love-functions {:fields (get-love-functions love-docs-tbl.functions)} + love-callbacks {:fields (get-love-functions love-docs-tbl.callbacks)}] + (stringify-table {:love (merge love-docs love-functions love-callbacks)}))) {: convert} From 3816bd81cc7c4f86d3953246b66348515dc95b9f Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 10 Aug 2024 16:55:36 -0400 Subject: [PATCH 05/11] Clean up file and abstract root love module parsing --- tools/get-docs/love2d.fnl | 87 ++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl index 42fc85f..7536057 100644 --- a/tools/get-docs/love2d.fnl +++ b/tools/get-docs/love2d.fnl @@ -7,13 +7,9 @@ (local stringify-table fennel.view) -(fn download-love-api-tooling! [] - "Clones the LÖVE-API git repository that contains tooling to scrape and - convert the LÖVE Wiki into a Lua table." - (when (not (io.open :build/love-api)) - (git-clone love-api-build-directory - "https://github.com/love2d-community/love-api"))) - +; +; UTILS +; ----- (fn merge [...] (let [arg-count (select "#" ...) args [...]] @@ -25,6 +21,23 @@ (values k (merge v (. result k))) (values k v))))))) +(fn download-love-api-tooling! [] + "Clones the LÖVE-API git repository that contains tooling to scrape and + convert the LÖVE Wiki into a Lua table." + (when (not (io.open :build/love-api)) + (git-clone love-api-build-directory + "https://github.com/love2d-community/love-api"))) + +(fn build-lsp-value [name ?args ?docstring] + "Takes ... and returns a table to be used with the LSP." + (let [lsp-value {:binding name :metadata {}}] + (when ?args (set lsp-value.metadata.fnl/arglist ?args)) + (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) + lsp-value)) + +; +; PARSERS +; ------- (fn fn-arguments->names [arguments] "Given an array of arguments, return all names as an array." (icollect [_i {:description _ : name :type _} (ipairs arguments)] @@ -44,45 +57,33 @@ :returns (values :returns v-value) :arguments (values :args (fn-arguments->names v-value))))) -; (fn build-arg-name-list [arguments-tbl] -; "Returns a list of all argument names" -; (print (.. "CHECK OUT THIS TABLE —" (fennel.view arguments-tbl))) -; (icollect [_ v (ipairs arguments-tbl)] -; v.name)) +(fn parse-doc-module-tbl [docs-tbl] + "Takes a LÖVE-API documentation table and generates a list of each + key with values suitable for the Fennel LSP." + {:fields (collect [_i value (ipairs docs-tbl)] + (let [{: name : description} value + ?variants (?. value :variants) + first-variant (if ?variants + (parse-fn-variant (. ?variants 1)) + nil) + ?args (?. first-variant :args) + ?returns (?. first-variant :returns) + docstring (.. description + (if ?returns (fn-return->string ?returns) ""))] + (values name (build-lsp-value name ?args docstring))))}) -(fn build-lsp-value [name ?args ?docstring] - "Takes ... and returns a table to be used with the LSP." - (let [lsp-value {:binding name :metadata {}}] - (when ?args (set lsp-value.metadata.fnl/arglist ?args)) - (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) - lsp-value)) - -; TODO - This function takes the functions object directly, then it can be used -; for any high-level object. - -(fn get-love-functions [docs-tbl] - "Takes the LÖVE-API documentation table and generates a list of the - library-level functions suitable for the Fennel LSP." - (collect [_i value (ipairs docs-tbl)] - (let [{: name : description} value - ?variants (?. value :variants) - first-variant (if ?variants - (parse-fn-variant (. ?variants 1)) - nil) - ?args (?. first-variant :args) - ?returns (?. first-variant :returns) - docstring (.. description (if ?returns (fn-return->string ?returns) - ""))] - (values name (build-lsp-value name ?args docstring))))) +(fn love-api->root-lsp-tbl [love-api] + (let [love-doc-string (.. "LÖVE is a framework for making " + "2D games in the Lua programming language.") + love-docs (build-lsp-value :love nil love-doc-string) + love-functions (parse-doc-module-tbl love-api.functions) + love-callbacks (parse-doc-module-tbl love-api.callbacks)] + {:love (merge love-docs love-functions love-callbacks)})) (fn convert [] (download-love-api-tooling!) - (let [love-docs-tbl (require-love-api) - love-doc-string (.. "LÖVE is a framework for making " - "2D games in the Lua programming language.") - love-docs (build-lsp-value :love nil love-doc-string) - love-functions {:fields (get-love-functions love-docs-tbl.functions)} - love-callbacks {:fields (get-love-functions love-docs-tbl.callbacks)}] - (stringify-table {:love (merge love-docs love-functions love-callbacks)}))) + (let [love-api (require-love-api) + root-lsp-tbl (love-api->root-lsp-tbl love-api)] + (stringify-table root-lsp-tbl))) {: convert} From e1d3b7b2576481ca53bc7d650eeccabce1d121fa Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 6 Sep 2024 18:42:31 -0400 Subject: [PATCH 06/11] Clean up love2d parser and restructure code --- tools/get-docs/love2d.fnl | 123 ++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl index 7536057..781abbf 100644 --- a/tools/get-docs/love2d.fnl +++ b/tools/get-docs/love2d.fnl @@ -5,21 +5,18 @@ (local require-love-api (partial require (.. love-api-build-directory :/love_api))) -(local stringify-table fennel.view) - ; ; UTILS ; ----- -(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] - (if (?. result k) - (values k (merge v (. result k))) - (values k v))))))) +(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 download-love-api-tooling! [] "Clones the LÖVE-API git repository that contains tooling to scrape and @@ -28,62 +25,86 @@ (git-clone love-api-build-directory "https://github.com/love2d-community/love-api"))) -(fn build-lsp-value [name ?args ?docstring] - "Takes ... and returns a table to be used with the LSP." - (let [lsp-value {:binding name :metadata {}}] - (when ?args (set lsp-value.metadata.fnl/arglist ?args)) - (when ?docstring (set lsp-value.metadata.fnl/docstring ?docstring)) - lsp-value)) +(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 fn-arguments->names [arguments] +(fn variant-arguments->names [arguments] "Given an array of arguments, return all names as an array." (icollect [_i {:description _ : name :type _} (ipairs arguments)] name)) -(fn fn-return->string [returns] - "Given an array of arguments, return a formatted description." +(fn variant-return->string [returns] + "Given an array of return values, return a formatted description." (accumulate [x "\n\nReturns -" _i {: description : name :type return-type} (ipairs returns)] (.. x "\n" " * " name " (`" return-type "`) - " description))) -(fn parse-fn-variant [variant] - "Given an array of fuction variants, return an object where the first variant - is made the formatted LSP option, with any remaining variants being formatted - as a single description." +(fn parse-first-function-variant [[variant]] + "Given an array of fuction variants, format and return the first variant + for the LSP." (collect [v-key v-value (pairs variant)] (case v-key - :returns (values :returns v-value) - :arguments (values :args (fn-arguments->names v-value))))) + :returns (values :returns (variant-return->string v-value)) + :arguments (values :args (variant-arguments->names v-value))))) -(fn parse-doc-module-tbl [docs-tbl] - "Takes a LÖVE-API documentation table and generates a list of each - key with values suitable for the Fennel LSP." - {:fields (collect [_i value (ipairs docs-tbl)] - (let [{: name : description} value - ?variants (?. value :variants) - first-variant (if ?variants - (parse-fn-variant (. ?variants 1)) - nil) - ?args (?. first-variant :args) - ?returns (?. first-variant :returns) - docstring (.. description - (if ?returns (fn-return->string ?returns) ""))] - (values name (build-lsp-value name ?args docstring))))}) +(fn love-functions->lsp [docs-tbl prefix] + "Given an array of documented functions for a LÖVE module, generate a table + for the Fennel LSP." + (collect [_i value (ipairs docs-tbl)] + (let [{: name : description} value + binding (.. prefix name) + ?variants (?. value :variants) + first-variant (if ?variants + (parse-first-function-variant ?variants) + nil) + ?args (?. first-variant :args) + ?returns (or (?. first-variant :returns) "") + docstring (.. description ?returns)] + (values name (build-lsp-value binding ?args docstring))))) -(fn love-api->root-lsp-tbl [love-api] - (let [love-doc-string (.. "LÖVE is a framework for making " - "2D games in the Lua programming language.") - love-docs (build-lsp-value :love nil love-doc-string) - love-functions (parse-doc-module-tbl love-api.functions) - love-callbacks (parse-doc-module-tbl love-api.callbacks)] - {:love (merge love-docs love-functions love-callbacks)})) +(fn module-list->fields [modules ?prefix] + "Given a list of LÖVE modules from the LÖVE-API Lua library, recursively + generate LSP data for Fennel." + (collect [_i module (ipairs modules)] + (let [{: name} module ; Other keys - :enum, :functions, :types + prefix (if ?prefix (.. ?prefix ".") "") + binding (.. prefix name) + ?docstring (?. module :description) + ?functions (?. module :functions) + ?modules (?. module :modules) + function-keys (if ?functions + (love-functions->lsp ?functions (.. binding ".")) + {}) + module-keys (if ?modules (module-list->fields ?modules binding) {}) + fields (merge function-keys module-keys)] + (values name (build-lsp-value binding nil ?docstring fields))))) + +(fn get-all-love-api-functions [love-api] + [(table.unpack love-api.functions) (table.unpack love-api.callbacks)]) + +(fn love-api->lsp [love-api] + "Given documentation for the entire LÖVE framework from the LÖVE-API Lua + library, generate the root LÖVE object suitable for the Fennel LSP." + (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->fields [root-module]))) (fn convert [] + "Convert LÖVE framework from Lua table to a configuration object + used by fennel-ls." (download-love-api-tooling!) - (let [love-api (require-love-api) - root-lsp-tbl (love-api->root-lsp-tbl love-api)] - (stringify-table root-lsp-tbl))) + (let [love-api (require-love-api)] + (fennel.view (love-api->lsp love-api)))) {: convert} From 0e0121825d382ebb8149278940e5939a67dfd74e Mon Sep 17 00:00:00 2001 From: Emma Date: Fri, 6 Sep 2024 18:46:20 -0400 Subject: [PATCH 07/11] WIP adding Love2D configuration --- docs/manual.md | 3 +- src/fennel-ls/config.fnl | 73 ++++++++++++-------------- src/fennel-ls/docs.fnl | 53 +++++++++---------- src/fennel-ls/docs/generated/lua54.fnl | 14 ++--- 4 files changed, 67 insertions(+), 76 deletions(-) diff --git a/docs/manual.md b/docs/manual.md index d3afa30..7dfd248 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -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 {:love-2d false + :tic-80 false} :extra-globals "" :lints {:unused-definition true :unknown-module-field true diff --git a/src/fennel-ls/config.fnl b/src/fennel-ls/config.fnl index 3e1cbd4..7c2c05b 100644 --- a/src/fennel-ls/config.fnl +++ b/src/fennel-ls/config.fnl @@ -17,33 +17,30 @@ There are no global settings. They're all stored in the `server` object. (fn option [default-value] (doto [default-value] (setmetatable option-mt))) (local default-configuration - {:fennel-path (option "./?.fnl;./?/init.fnl;src/?.fnl;src/?/init.fnl") - :macro-path (option "./?.fnl;./?/init-macros.fnl;./?/init.fnl;src/?.fnl;src/?/init-macros.fnl;src/?/init.fnl") - :lua-version (option "lua54") - :lints {:unused-definition (option true) - :unknown-module-field (option true) - :unnecessary-method (option true) - :bad-unpack (option true) - :var-never-set (option true) - :op-with-no-arguments (option true) - :multival-in-middle-of-call (option true)} - :libraries {:tic-80 (option false)} - :extra-globals (option "")}) + {:fennel-path (option "./?.fnl;./?/init.fnl;src/?.fnl;src/?/init.fnl") + :macro-path (option "./?.fnl;./?/init-macros.fnl;./?/init.fnl;src/?.fnl;src/?/init-macros.fnl;src/?/init.fnl") + :lua-version (option :lua54) + :lints {:unused-definition (option true) + :unknown-module-field (option true) + :unnecessary-method (option true) + :bad-unpack (option true) + :var-never-set (option true) + :op-with-no-arguments (option true) + :multival-in-middle-of-call (option true)} + :libraries {:love2d (option false) :tic-80 (option false)} + :extra-globals (option "")}) (fn make-configuration-from-template [default ?user ?parent] (if (= option-mt (getmetatable default)) - (let [setting - (case-try ?user - nil (?. ?parent :all) - nil (. default 1))] + (let [setting (case-try ?user + nil (?. ?parent :all) + nil (. default 1))] (assert (= (type (. default 1)) (type setting))) setting) (= :table (type default)) (collect [k _ (pairs default)] - k (make-configuration-from-template - (. default k) - (?. ?user k) - ?user)) + k + (make-configuration-from-template (. default k) (?. ?user k) ?user)) (error "This is a bug with fennel-ls: default-configuration has a key that isn't a table or option"))) (λ make-configuration [?c] @@ -52,18 +49,14 @@ There are no global settings. They're all stored in the `server` object. (λ choose-position-encoding [init-params] "fennel-ls natively uses utf-8, so the goal is to choose positionEncoding=\"utf-8\". However, when not an option, fennel-ls will fall back to positionEncoding=\"utf-16\" (with a performance hit)." - (let [?position-encodings (?. init-params :capabilities :general :positionEncodings) - utf8? - (if (= (type ?position-encodings) :table) - (accumulate [utf-8? false - _ encoding (ipairs ?position-encodings) - &until utf-8?] - (or (= encoding :utf-8) - (= encoding :utf8))) - false)] - (if utf8? - :utf-8 - :utf-16))) + (let [?position-encodings (?. init-params :capabilities :general + :positionEncodings) + utf8? (if (= (type ?position-encodings) :table) + (accumulate [utf-8? false _ encoding (ipairs ?position-encodings) + &until utf-8?] + (or (= encoding :utf-8) (= encoding :utf8))) + false)] + (if utf8? :utf-8 :utf-16))) (λ try-parsing [{: text : uri}] (local fennel (require :fennel)) @@ -72,11 +65,11 @@ 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"))) - try-parsing)))) + (make-configuration (when server.root-uri + (-?> (files.read-file server + (utils.path->uri (utils.path-join (utils.uri->path server.root-uri) + :flsproject.fnl))) + try-parsing)))) (λ reload [server] (set server.configuration (load-config server))) @@ -89,7 +82,7 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf- (reload server) ;; Eglot does completions differently than every other client I've seen so far, in that it considers foo.bar to be one "symbol". ;; If the user types `foo.b`, every other client accepts `bar` as a completion, bun eglot wants the full `foo.bar` symbol. - (set server.EGLOT_COMPLETION_QUIRK_MODE (= (?. params :clientInfo :name) :Eglot))) + (set server.EGLOT_COMPLETION_QUIRK_MODE + (= (?. params :clientInfo :name) :Eglot))) -{: initialize - : reload} +{: initialize : reload} diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index b6e7c8c..e90287b 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -1,38 +1,40 @@ (local fennel (require :fennel)) (local {:metadata METADATA - :scopes {:global {:specials SPECIALS - :macros MACROS}}} - (require :fennel.compiler)) + :scopes {:global {:specials SPECIALS :macros MACROS}}} + (require :fennel.compiler)) -(local specials - (collect [name value (pairs SPECIALS)] - name {:binding name :metadata (. METADATA value)})) +(local specials (collect [name value (pairs SPECIALS)] + name + {:binding name :metadata (. METADATA value)})) -(local macros* - (collect [name value (pairs MACROS)] - name {:binding name :metadata (. METADATA value)})) +(local macros* (collect [name value (pairs MACROS)] + name + {:binding name :metadata (. METADATA value)})) (local lua-versions - {:lua51 (require :fennel-ls.docs.generated.lua51) - :lua52 (require :fennel-ls.docs.generated.lua52) - :lua53 (require :fennel-ls.docs.generated.lua53) - :lua54 (require :fennel-ls.docs.generated.lua54)}) + {:lua51 (require :fennel-ls.docs.generated.lua51) + :lua52 (require :fennel-ls.docs.generated.lua52) + :lua53 (require :fennel-ls.docs.generated.lua53) + :lua54 (require :fennel-ls.docs.generated.lua54)}) (fn get-lua-version [version] (when (not (. lua-versions version)) (error (.. "fennel-ls doesn't know about lua version " version "\n" "The allowed versions are: " - (fennel.view (doto (icollect [key (pairs lua-versions)] key) table.sort))))) + (fennel.view (doto (icollect [key (pairs lua-versions)] key) + table.sort))))) (. lua-versions version)) (local libraries - {:tic-80 (require :fennel-ls.docs.generated.tic80)}) + {:love-2d (require :fennel-ls.docs.generated.love2d) + :tic-80 (require :fennel-ls.docs.generated.tic80)}) (fn get-library [library] (when (not (. libraries library)) (error (.. "fennel-ls doesn't know about library " library "\n" "The builtin libraries are: " - (fennel.view (doto (icollect [key (pairs libraries)] key) table.sort))))) + (fennel.view (doto (icollect [key (pairs libraries)] key) + table.sort))))) (. libraries library)) (fn get-all-globals [server] @@ -41,23 +43,18 @@ (when enabled? (icollect [name (pairs (get-library library)) &into result] name))) - (icollect [name (pairs (get-lua-version server.configuration.lua-version)) &into result] + (icollect [name (pairs (get-lua-version server.configuration.lua-version)) + &into result] 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 (and server.configuration.libraries.tic-80 + (. (get-library :tic-80) global-name)) + (. (get-lua-version server.configuration.lua-version) global-name))) (fn get-builtin [_server builtin-name] - (or (. specials builtin-name) - (. macros* builtin-name))) + (or (. specials builtin-name) (. macros* builtin-name))) ;; TODO get-module-metadata -{: get-global - : get-builtin - : get-all-globals} +{: get-global : get-builtin : get-all-globals} diff --git a/src/fennel-ls/docs/generated/lua54.fnl b/src/fennel-ls/docs/generated/lua54.fnl index 0769d47..566c6f3 100644 --- a/src/fennel-ls/docs/generated/lua54.fnl +++ b/src/fennel-ls/docs/generated/lua54.fnl @@ -1,5 +1,5 @@ ;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.4/manual.html -;; Lua Lua 5.4 Reference Manual last updated Tue May 2 20:09:38 UTC 2023 +;; Lua Lua 5.4 Reference Manual last updated Thu Jun 13 22:15:52 UTC 2024 (local docs {:_G {:binding "_G" :metadata {:fnl/docstring "A global variable (not a function) that holds the global environment @@ -223,13 +223,13 @@ The returned table can contain all the fields returned by `lua_getinfo`, with the string `?what` describing which fields to fill in. The default for `?what` is to get all information available, except the table of valid lines. -If present, -the option `\"f\"` +The option `\"f\"` adds a field named `func` with the function itself. -If present, -the option `\"L\"` -adds a field named `activelines` with the table of -valid lines. +The option `\"L\"` adds a field named `activelines` +with the table of valid lines, +provided the function is a Lua function. +If the function has no debug information, +the table is empty. For instance, the expression `debug.getinfo(1,\"n\").name` returns a name for the current function, From f0c512575eb3b780eee5d807964be4574ae3bb53 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 7 Sep 2024 12:33:57 -0400 Subject: [PATCH 08/11] Add Love2D API generation flag option to make docs target --- .gitignore | 1 + Makefile | 2 +- docs/packaging.md | 11 +++++++++++ tools/get-docs.fnl | 15 +++++++++------ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index bb0ce15..003a793 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /result /lua*.html /build +/src/fennel-ls/docs/generated/love2d.fnl diff --git a/Makefile b/Makefile index 3bd85a5..87a539e 100644 --- a/Makefile +++ b/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/ diff --git a/docs/packaging.md b/docs/packaging.md index b4dab70..e193068 100644 --- a/docs/packaging.md +++ b/docs/packaging.md @@ -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`. diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl index a09bbc2..498d0b5 100644 --- a/tools/get-docs.fnl +++ b/tools/get-docs.fnl @@ -27,9 +27,9 @@ (fn main [] (sh :mkdir :-p :build/) (sh :mkdir :-p :src/fennel-ls/docs/generated/) - (let [{:convert lua-manual} (require :tools.get-docs.lua-manual) - {:convert tic80-manual} (require :tools.get-docs.tic80) - {:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] + (let [generate-love2d-docs? (case arg [:--generate-love2d] true _ false) + {:convert lua-manual} (require :tools.get-docs.lua-manual) + {:convert tic80-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" @@ -39,8 +39,11 @@ (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 tic80-manual) - (write-doc-file! :love2d.fnl - "https://github.com/love2d-community/love-api/" - (download-and-convert-love2d-manual!)))) + (when generate-love2d-docs? + (let [{:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] + (print "generating Love2D docs...") + (write-doc-file! :love2d.fnl + "https://github.com/love2d-community/love-api/" + (download-and-convert-love2d-manual!)))))) (main) From 1c6999ea3fb91fd30b68312d7220099e39865241 Mon Sep 17 00:00:00 2001 From: Phil Hagelberg Date: Sat, 7 Sep 2024 15:00:13 -0700 Subject: [PATCH 09/11] Fix loading of globals from love2d generated documentation. The first thing to change is to load the love2d docset inside a pcall, because it's not included in the standard `make` build, so we need to not crash if it's not present. Note that we are storing these under libraries.love2d rather than libraries.love-2d, because even tho it's inconsistent with tic-80; I've never seen them use the hyphenated version, and now the name matches the module name. Secondly, we extend the get-global function to work with anything in the server.configuration.libraries table, not just hard-coded to tic-80. Finally, update the manual to reflect the removal of the love2d hypen. --- docs/manual.md | 2 +- src/fennel-ls/docs.fnl | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/manual.md b/docs/manual.md index 7dfd248..ecee8aa 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -70,7 +70,7 @@ 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 {:love-2d false + :libraries {:love2d false :tic-80 false} :extra-globals "" :lints {:unused-definition true diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index e90287b..cbd11b0 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -25,9 +25,11 @@ table.sort))))) (. lua-versions version)) -(local libraries - {:love-2d (require :fennel-ls.docs.generated.love2d) - :tic-80 (require :fennel-ls.docs.generated.tic80)}) +(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)) @@ -47,9 +49,13 @@ &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)) + (or (get-library-global server global-name) (. (get-lua-version server.configuration.lua-version) global-name))) (fn get-builtin [_server builtin-name] From 3de4def9510167c7baabd76f20933d5645274632 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 7 Sep 2024 21:16:07 -0400 Subject: [PATCH 10/11] Remove print statement for Love2D doc generation --- tools/get-docs.fnl | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl index 498d0b5..58f7f6f 100644 --- a/tools/get-docs.fnl +++ b/tools/get-docs.fnl @@ -41,7 +41,6 @@ (derive-docs-from-url "https://tic80.com/learn" :tic80.fnl tic80-manual) (when generate-love2d-docs? (let [{:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] - (print "generating Love2D docs...") (write-doc-file! :love2d.fnl "https://github.com/love2d-community/love-api/" (download-and-convert-love2d-manual!)))))) From 72c9a303434d5d8c0ca3900145d9edbc38b67b63 Mon Sep 17 00:00:00 2001 From: Emma Date: Sat, 7 Sep 2024 22:03:38 -0400 Subject: [PATCH 11/11] Refactor work and remove all unnecessary fnlfmt changes --- src/fennel-ls/config.fnl | 73 ++++++++++++++------------ src/fennel-ls/docs.fnl | 44 ++++++++-------- src/fennel-ls/docs/generated/lua54.fnl | 14 ++--- tools/get-docs.fnl | 26 ++++----- tools/get-docs/love2d.fnl | 66 +++++++++++------------ 5 files changed, 111 insertions(+), 112 deletions(-) diff --git a/src/fennel-ls/config.fnl b/src/fennel-ls/config.fnl index 7c2c05b..42ad462 100644 --- a/src/fennel-ls/config.fnl +++ b/src/fennel-ls/config.fnl @@ -17,30 +17,33 @@ There are no global settings. They're all stored in the `server` object. (fn option [default-value] (doto [default-value] (setmetatable option-mt))) (local default-configuration - {:fennel-path (option "./?.fnl;./?/init.fnl;src/?.fnl;src/?/init.fnl") - :macro-path (option "./?.fnl;./?/init-macros.fnl;./?/init.fnl;src/?.fnl;src/?/init-macros.fnl;src/?/init.fnl") - :lua-version (option :lua54) - :lints {:unused-definition (option true) - :unknown-module-field (option true) - :unnecessary-method (option true) - :bad-unpack (option true) - :var-never-set (option true) - :op-with-no-arguments (option true) - :multival-in-middle-of-call (option true)} - :libraries {:love2d (option false) :tic-80 (option false)} - :extra-globals (option "")}) + {:fennel-path (option "./?.fnl;./?/init.fnl;src/?.fnl;src/?/init.fnl") + :macro-path (option "./?.fnl;./?/init-macros.fnl;./?/init.fnl;src/?.fnl;src/?/init-macros.fnl;src/?/init.fnl") + :lua-version (option "lua54") + :lints {:unused-definition (option true) + :unknown-module-field (option true) + :unnecessary-method (option true) + :bad-unpack (option true) + :var-never-set (option true) + :op-with-no-arguments (option true) + :multival-in-middle-of-call (option true)} + :libraries {:love2d (option false) :tic-80 (option false)} + :extra-globals (option "")}) (fn make-configuration-from-template [default ?user ?parent] (if (= option-mt (getmetatable default)) - (let [setting (case-try ?user - nil (?. ?parent :all) - nil (. default 1))] + (let [setting + (case-try ?user + nil (?. ?parent :all) + nil (. default 1))] (assert (= (type (. default 1)) (type setting))) setting) (= :table (type default)) (collect [k _ (pairs default)] - k - (make-configuration-from-template (. default k) (?. ?user k) ?user)) + k (make-configuration-from-template + (. default k) + (?. ?user k) + ?user)) (error "This is a bug with fennel-ls: default-configuration has a key that isn't a table or option"))) (λ make-configuration [?c] @@ -49,14 +52,18 @@ There are no global settings. They're all stored in the `server` object. (λ choose-position-encoding [init-params] "fennel-ls natively uses utf-8, so the goal is to choose positionEncoding=\"utf-8\". However, when not an option, fennel-ls will fall back to positionEncoding=\"utf-16\" (with a performance hit)." - (let [?position-encodings (?. init-params :capabilities :general - :positionEncodings) - utf8? (if (= (type ?position-encodings) :table) - (accumulate [utf-8? false _ encoding (ipairs ?position-encodings) - &until utf-8?] - (or (= encoding :utf-8) (= encoding :utf8))) - false)] - (if utf8? :utf-8 :utf-16))) + (let [?position-encodings (?. init-params :capabilities :general :positionEncodings) + utf8? + (if (= (type ?position-encodings) :table) + (accumulate [utf-8? false + _ encoding (ipairs ?position-encodings) + &until utf-8?] + (or (= encoding :utf-8) + (= encoding :utf8))) + false)] + (if utf8? + :utf-8 + :utf-16))) (λ try-parsing [{: text : uri}] (local fennel (require :fennel)) @@ -65,11 +72,11 @@ 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))) - try-parsing)))) + + (make-configuration + (when server.root-uri + (-?> (files.read-file server (utils.path->uri (utils.path-join (utils.uri->path server.root-uri) "flsproject.fnl"))) + try-parsing)))) (λ reload [server] (set server.configuration (load-config server))) @@ -82,7 +89,7 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf- (reload server) ;; Eglot does completions differently than every other client I've seen so far, in that it considers foo.bar to be one "symbol". ;; If the user types `foo.b`, every other client accepts `bar` as a completion, bun eglot wants the full `foo.bar` symbol. - (set server.EGLOT_COMPLETION_QUIRK_MODE - (= (?. params :clientInfo :name) :Eglot))) + (set server.EGLOT_COMPLETION_QUIRK_MODE (= (?. params :clientInfo :name) :Eglot))) -{: initialize : reload} +{: initialize + : reload} diff --git a/src/fennel-ls/docs.fnl b/src/fennel-ls/docs.fnl index cbd11b0..322220b 100644 --- a/src/fennel-ls/docs.fnl +++ b/src/fennel-ls/docs.fnl @@ -1,31 +1,32 @@ (local fennel (require :fennel)) (local {:metadata METADATA - :scopes {:global {:specials SPECIALS :macros MACROS}}} - (require :fennel.compiler)) + :scopes {:global {:specials SPECIALS + :macros MACROS}}} + (require :fennel.compiler)) -(local specials (collect [name value (pairs SPECIALS)] - name - {:binding name :metadata (. METADATA value)})) +(local specials + (collect [name value (pairs SPECIALS)] + name {:binding name :metadata (. METADATA value)})) -(local macros* (collect [name value (pairs MACROS)] - name - {:binding name :metadata (. METADATA value)})) +(local macros* + (collect [name value (pairs MACROS)] + name {:binding name :metadata (. METADATA value)})) (local lua-versions - {:lua51 (require :fennel-ls.docs.generated.lua51) - :lua52 (require :fennel-ls.docs.generated.lua52) - :lua53 (require :fennel-ls.docs.generated.lua53) - :lua54 (require :fennel-ls.docs.generated.lua54)}) + {:lua51 (require :fennel-ls.docs.generated.lua51) + :lua52 (require :fennel-ls.docs.generated.lua52) + :lua53 (require :fennel-ls.docs.generated.lua53) + :lua54 (require :fennel-ls.docs.generated.lua54)}) (fn get-lua-version [version] (when (not (. lua-versions version)) (error (.. "fennel-ls doesn't know about lua version " version "\n" "The allowed versions are: " - (fennel.view (doto (icollect [key (pairs lua-versions)] key) - table.sort))))) + (fennel.view (doto (icollect [key (pairs lua-versions)] key) table.sort))))) (. lua-versions version)) -(local libraries {:tic-80 (require :fennel-ls.docs.generated.tic80)}) +(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)) @@ -35,8 +36,7 @@ (when (not (. libraries library)) (error (.. "fennel-ls doesn't know about library " library "\n" "The builtin libraries are: " - (fennel.view (doto (icollect [key (pairs libraries)] key) - table.sort))))) + (fennel.view (doto (icollect [key (pairs libraries)] key) table.sort))))) (. libraries library)) (fn get-all-globals [server] @@ -45,8 +45,7 @@ (when enabled? (icollect [name (pairs (get-library library)) &into result] name))) - (icollect [name (pairs (get-lua-version server.configuration.lua-version)) - &into result] + (icollect [name (pairs (get-lua-version server.configuration.lua-version)) &into result] name))) (fn get-library-global [server global-name] @@ -59,8 +58,11 @@ (. (get-lua-version server.configuration.lua-version) global-name))) (fn get-builtin [_server builtin-name] - (or (. specials builtin-name) (. macros* builtin-name))) + (or (. specials builtin-name) + (. macros* builtin-name))) ;; TODO get-module-metadata -{: get-global : get-builtin : get-all-globals} +{: get-global + : get-builtin + : get-all-globals} diff --git a/src/fennel-ls/docs/generated/lua54.fnl b/src/fennel-ls/docs/generated/lua54.fnl index 566c6f3..0769d47 100644 --- a/src/fennel-ls/docs/generated/lua54.fnl +++ b/src/fennel-ls/docs/generated/lua54.fnl @@ -1,5 +1,5 @@ ;; auto-generated by `make docs` from fennel-ls. Contents come from https://www.lua.org/manual/5.4/manual.html -;; Lua Lua 5.4 Reference Manual last updated Thu Jun 13 22:15:52 UTC 2024 +;; Lua Lua 5.4 Reference Manual last updated Tue May 2 20:09:38 UTC 2023 (local docs {:_G {:binding "_G" :metadata {:fnl/docstring "A global variable (not a function) that holds the global environment @@ -223,13 +223,13 @@ The returned table can contain all the fields returned by `lua_getinfo`, with the string `?what` describing which fields to fill in. The default for `?what` is to get all information available, except the table of valid lines. -The option `\"f\"` +If present, +the option `\"f\"` adds a field named `func` with the function itself. -The option `\"L\"` adds a field named `activelines` -with the table of valid lines, -provided the function is a Lua function. -If the function has no debug information, -the table is empty. +If present, +the option `\"L\"` +adds a field named `activelines` with the table of +valid lines. For instance, the expression `debug.getinfo(1,\"n\").name` returns a name for the current function, diff --git a/tools/get-docs.fnl b/tools/get-docs.fnl index 58f7f6f..0beb0b6 100644 --- a/tools/get-docs.fnl +++ b/tools/get-docs.fnl @@ -4,12 +4,12 @@ (local fennel (require :deps.fennel)) (fn curl-cached [url] - (let [filename (.. :build/ (url:gsub "[/:]" "_")) + (let [filename (.. "build/" (url:gsub "[/:]" "_")) file (io.open filename :r)] (if file file (do - (sh :curl url [">"] filename) + (sh "curl" url [">"] filename) (io.open filename :r))))) (fn write-doc-file! [out-filename doc-src doc-tbl] @@ -25,20 +25,16 @@ (file:read :*a))))) (fn main [] - (sh :mkdir :-p :build/) - (sh :mkdir :-p :src/fennel-ls/docs/generated/) - (let [generate-love2d-docs? (case arg [:--generate-love2d] true _ false) + (sh :mkdir :-p "build/") + (sh :mkdir :-p "src/fennel-ls/docs/generated/") + (let [generate-love2d-docs? (case arg ["--generate-love2d"] true _ false) {:convert lua-manual} (require :tools.get-docs.lua-manual) - {:convert tic80-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 tic80-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) (when generate-love2d-docs? (let [{:convert download-and-convert-love2d-manual!} (require :tools.get-docs.love2d)] (write-doc-file! :love2d.fnl diff --git a/tools/get-docs/love2d.fnl b/tools/get-docs/love2d.fnl index 781abbf..afe363e 100644 --- a/tools/get-docs/love2d.fnl +++ b/tools/get-docs/love2d.fnl @@ -18,9 +18,7 @@ (when ?fields (set lsp-value.fields ?fields)) lsp-value)) -(fn download-love-api-tooling! [] - "Clones the LÖVE-API git repository that contains tooling to scrape and - convert the LÖVE Wiki into a Lua table." +(fn clone-love-api! [] (when (not (io.open :build/love-api)) (git-clone love-api-build-directory "https://github.com/love2d-community/love-api"))) @@ -37,74 +35,70 @@ ; ; PARSERS ; ------- -(fn variant-arguments->names [arguments] +(fn get-fn-argument-names [fn-arguments] "Given an array of arguments, return all names as an array." - (icollect [_i {:description _ : name :type _} (ipairs arguments)] + (icollect [_i {:description _ : name :type _} (ipairs fn-arguments)] name)) -(fn variant-return->string [returns] - "Given an array of return values, return a formatted description." - (accumulate [x "\n\nReturns -" _i {: description : name :type return-type} (ipairs returns)] +(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-function-variant [[variant]] +(fn parse-first-fn-variant [[variant]] "Given an array of fuction variants, format and return the first variant for the LSP." - (collect [v-key v-value (pairs variant)] - (case v-key - :returns (values :returns (variant-return->string v-value)) - :arguments (values :args (variant-arguments->names v-value))))) + (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 love-functions->lsp [docs-tbl prefix] - "Given an array of documented functions for a LÖVE module, generate a table - for the Fennel LSP." +(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 (.. prefix name) + 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-function-variant ?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->fields [modules ?prefix] - "Given a list of LÖVE modules from the LÖVE-API Lua library, recursively - generate LSP data for Fennel." +(fn module-list->lsp-table [modules ?namespace] (collect [_i module (ipairs modules)] (let [{: name} module ; Other keys - :enum, :functions, :types - prefix (if ?prefix (.. ?prefix ".") "") - binding (.. prefix name) + namespace (if ?namespace (.. ?namespace ".") "") + binding (.. namespace name) ?docstring (?. module :description) ?functions (?. module :functions) ?modules (?. module :modules) function-keys (if ?functions - (love-functions->lsp ?functions (.. binding ".")) + (love-functions->lsp-table ?functions (.. binding ".")) {}) - module-keys (if ?modules (module-list->fields ?modules 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 get-all-love-api-functions [love-api] - [(table.unpack love-api.functions) (table.unpack love-api.callbacks)]) - -(fn love-api->lsp [love-api] - "Given documentation for the entire LÖVE framework from the LÖVE-API Lua - library, generate the root LÖVE object suitable for the Fennel LSP." +(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->fields [root-module]))) + (module-list->lsp-table [root-module]))) (fn convert [] - "Convert LÖVE framework from Lua table to a configuration object - used by fennel-ls." - (download-love-api-tooling!) + "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 love-api)))) + (fennel.view (love-api->lsp-table love-api)))) {: convert}