Refactor work and remove all unnecessary fnlfmt changes

This commit is contained in:
Emma 2024-09-07 22:03:38 -04:00
parent 3de4def951
commit 72c9a30343
5 changed files with 111 additions and 112 deletions

View File

@ -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}

View File

@ -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}

View File

@ -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,

View File

@ -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

View File

@ -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}