switch from initialization options and didChangeConfiguration to flsproject.fnl

This commit is contained in:
XeroOl 2024-07-05 12:40:15 -05:00
parent 7ff4581e50
commit fbd9b0981f
8 changed files with 91 additions and 86 deletions

View File

@ -10,6 +10,9 @@ There are no global settings. They're all stored in the `server` object.
;; Have an option for "union of all lua versions" lua version.
;; Have an option for "intersection of all lua versions", ie disallow using (unpack) without saying (or table.unpack _G.unpack).
(local files (require :fennel-ls.files))
(local utils (require :fennel-ls.utils))
(local option-mt {})
(fn option [default-value] (doto [default-value] (setmetatable option-mt)))
@ -62,19 +65,27 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf-
:utf-8
:utf-16)))
(λ try-parsing [{: text : uri}]
(local fennel (require :fennel))
(local [ok? _err result] [(pcall (fennel.parser text uri))])
(if ok? result))
(λ make-configuration-2 [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))))
(λ initialize [server params]
(set server.files {})
(set server.modules {})
(set server.root-uri params.rootUri)
(set server.position-encoding (choose-position-encoding params))
(set server.configuration (make-configuration (?. params :initializationOptions :fennel-ls)))
(set server.configuration (make-configuration-2 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)))
(λ write-configuration [server ?configuration]
"This is where we can put anything that needs to react to config changes"
(set server.configuration (make-configuration ?configuration)))
{: initialize
: write-configuration}
{: initialize}

View File

@ -11,31 +11,29 @@ in the \"server\" object."
(local {: compile} (require :fennel-ls.compiler))
(λ read-file [server uri]
(let [text (case (?. server.preload uri)
preload preload
_ (let [file (io.open (utils.uri->path uri))]
(if file
(let [body (file:read :*a)]
(file:close)
body)
(error (.. "failed to open file " uri)))))]
{: uri : text}))
(case (?. server.preload uri)
preload {: uri :text preload}
_ (case (io.open (utils.uri->path uri) "r")
file (let [text (file:read :*a)]
(file:close)
{: uri : text}))))
(λ get-by-uri [server uri]
(or (. server.files uri)
(let [file (read-file server uri)]
(compile server file)
(tset server.files uri file)
file)))
(case (read-file server uri)
file (do
(compile server file)
(tset server.files uri file)
file))))
(λ get-by-module [server module]
;; check the cache
(case (. server.modules module)
uri
(or (get-by-uri server uri)
;; if the cached uri isn't found, clear the cache and try again
(do (tset server.modules module nil)
(get-by-module server module)))
;; if the cached uri isn't found, clear the cache and try again
(do (tset server.modules module nil)
(get-by-module server module)))
nil
(case (searcher.lookup server module)
uri
@ -67,4 +65,5 @@ in the \"server\" object."
{: flush-uri
: get-by-module
: get-by-uri
: set-uri-contents}
: set-uri-contents
: read-file}

View File

@ -284,9 +284,6 @@ Every time the client sends a message, it gets handled by a function in the corr
;; TODO only reload from disk if we didn't get a didSave, instead of always
(files.flush-uri server uri))
(λ notifications.workspace/didChangeConfiguration [server _send {: settings}]
(config.write-configuration server (?. settings :fennel-ls)))
(λ requests.shutdown [_server _send]
"The server still needs to respond to this request, so the program can't close yet. Just wait until notifications.exit"
nil)

View File

@ -3,58 +3,40 @@ This module is responsible for resolving (require) calls. It has all the logic
for using the name of a module and find the corresponding URI.
I suspect this file may be gone after a bit of refactoring."
(local utils (require :fennel-ls.utils))
(local sep (package.config:sub 1 1))
(λ absolute? [path]
(or
;; windows
(-> path
(: :sub 2 3)
(: :match ":\\"))
;; modern society
(= (path:sub 1 1) "/")))
(λ join [path suffix]
(-> (.. path sep suffix)
;; delete duplicate
;; windows
(: :gsub "%.\\" "")
(: :gsub "\\+" "\\")
;; modern society
(: :gsub "%./" "")
(: :gsub "/+" "/")
(->> (pick-values 1))))
(local {: absolute-path?
: uri->path
: path->uri
: path-sep
: path-join} (require :fennel-ls.utils))
(λ add-workspaces-to-path [path ?workspaces]
"Make every relative path be relative to every workspace."
(let [result []]
(each [path (path:gmatch "[^;]+")]
(if (absolute? path)
(if (absolute-path? path)
(table.insert result path)
(each [_ workspace (ipairs (or ?workspaces []))]
(table.insert result (join (utils.uri->path workspace) path)))))
(table.insert result (path-join (uri->path workspace) path)))))
(table.concat result ";")))
(fn file-exists? [server uri]
(or (?. server.preload uri)
(case (io.open (utils.uri->path uri))
(case (io.open (uri->path uri))
f (do (f:close) true))))
(λ lookup [{:configuration {: fennel-path} :root-uri ?root-uri &as server} mod]
"Use the fennel path to find a file on disk"
(when ?root-uri
(let [mod (mod:gsub "%." sep)
root-path (utils.uri->path ?root-uri)]
(let [mod (mod:gsub "%." path-sep)
root-path (uri->path ?root-uri)]
(accumulate [uri nil
segment (fennel-path:gmatch "[^;]+")
&until uri]
(let [segment (segment:gsub "%?" mod)
segment (if (absolute? segment)
segment (if (absolute-path? segment)
segment
(join root-path segment))
segment (utils.path->uri segment)]
(path-join root-path segment))
segment (path->uri segment)]
(if (file-exists? server segment)
segment))))))

View File

@ -3,6 +3,8 @@ A collection of utility functions. Many of these convert data between a
Language-Server-Protocol representation and a Lua representation.
These functions are all pure functions, which makes me happy."
(local fennel (require :fennel))
(λ next-line [str ?from]
"Find the start of the next line from a given byte offset, or from the start of the string."
(let [from (or ?from 1)]
@ -94,7 +96,8 @@ These functions are all pure functions, which makes me happy."
(λ uri->path [uri]
"Strips the \"file://\" prefix from a uri to turn it into a path. Throws an error if it is not a path uri"
(local prefix "file://")
(assert (startswith uri prefix) "encountered a URI that is not a file???")
(when (not (startswith uri prefix))
(error (.. "encountered URI " (fennel.view uri) " that does not start with \"file://\"")))
(string.sub uri (+ (length prefix) 1)))
(λ path->uri [path]
@ -185,6 +188,28 @@ WARNING: this is only used in the test code, not in the real language server"
(icollect [m (str:gmatch "[^ ]+")]
m))
(local path-sep (package.config:sub 1 1))
(λ absolute-path? [path]
(or
;; windows
(-> path
(: :sub 2 3)
(: :match ":\\"))
;; modern society
(= (path:sub 1 1) "/")))
(λ path-join [path suffix]
(-> (.. path path-sep suffix)
;; delete duplicate
;; windows
(: :gsub "%.\\" "")
(: :gsub "\\+" "\\")
;; modern society
(: :gsub "%./" "")
(: :gsub "/+" "/")
(->> (pick-values 1))))
{: uri->path
: path->uri
: pos->position
@ -197,4 +222,7 @@ WARNING: this is only used in the test code, not in the real language server"
: get-ast-info
: uniq-by
: type=
: split-spaces}
: split-spaces
: absolute-path?
: path-join
: path-sep}

View File

@ -6,9 +6,8 @@
(create-client
{:modname.fnl "{:this-is-in-modname {:this :one :isnt :on :the :path}}"
:modname/modname/modname/modname.fnl "(fn ==this-is-in-modname== [] nil) {: this-is-in-modname}"
:main.fnl "(local {: this-is-in-mod|name} (require :modname))"}
{:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}}})
:main.fnl "(local {: this-is-in-mod|name} (require :modname))"
:flsproject.fnl "{:fennel-path \"./?/?/?/?.fnl\"}"})
[response] (client:definition uri cursor)]
(faith.= location response.result
"error message")))
@ -30,8 +29,10 @@
;; (local client (doto [] ({:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}}))))
(fn test-extra-globals []
(let [{:diagnostics good} (create-client "(foo-100 bar :baz)" {:settings {:fennel-ls {:extra-globals "foo-100 bar"}}})
{:diagnostics bad} (create-client "(foo-100 bar :baz)")]
(let [{:diagnostics good} (create-client {:main.fnl "(foo-100 bar :baz)"
:flsproject.fnl "{:extra-globals \"foo-100 bar\"}"})
{:diagnostics bad} (create-client {:main.fnl "(foo-100 bar :baz)"
:flsproject.fnl "{}"})]
(faith.= [] good)
(faith.not= [] bad))
nil)
@ -43,28 +44,23 @@
;; (local client (doto [] (setup-server {:fennel-ls {:diagnostics {:E202 "warning"}}})))))
(fn test-lints []
(let [{:diagnostics good} (create-client "(local x 10)" {:settings {:fennel-ls {:checks {:unused-definition false}}}})
{:diagnostics bad} (create-client "(local x 10)")]
(let [{:diagnostics good} (create-client {:main.fnl "(local x 10)"
:flsproject.fnl "{:checks {:unused-definition false}}"})
{:diagnostics bad} (create-client {:main.fnl "(local x 10)"
:flsproject.fnl "{}"})]
(faith.= [] good)
(faith.not= [] bad))
nil)
(fn test-initialization-options []
(let [initialization-options {:fennel-ls {:checks {:unused-definition false}}}
{: diagnostics} (create-client "(local x 10)" {: initialization-options})]
(faith.= [] diagnostics))
nil)
(fn test-native-libaries []
(let [{:diagnostics bad} (create-client "(print btn)"
{:settings {}})
{:diagnostics good} (create-client "(print btn)"
{:settings {:fennel-ls {:native-libraries [:tic80]}}})]
(let [{:diagnostics bad} (create-client {:main.fnl "(print btn)"
:flsproject.fnl "{}"})
{:diagnostics good} (create-client {:main.fnl "(print btn)"
:flsproject.fnl "{:native-libraries [:tic80]}"})]
(faith.not= [] bad)
(faith.= [] good)))
{: test-path
: test-extra-globals
: test-lints
: test-initialization-options
: test-native-libaries}

View File

@ -25,11 +25,6 @@
:version 1
: text}})))
(fn did-change-configuration [self settings]
(dispatch.handle* self.server
(message.create-notification :workspace/didChangeConfiguration
{: settings})))
(fn pretend-this-file-exists! [self name text]
(tset self.server.preload name text))
@ -75,7 +70,6 @@
(local client-mt
{:__index {: open-file!
: pretend-this-file-exists!
: did-change-configuration
: completion
: definition
: hover

View File

@ -81,8 +81,6 @@
:jsonrpc "2.0"
:method "initialize"
: params})
_ (when opts.settings
(client:did-change-configuration opts.settings))
[{:params {: diagnostics}}] (client:open-file! uri text)]
{: client
: server