switch from initialization options and didChangeConfiguration to flsproject.fnl
This commit is contained in:
parent
7ff4581e50
commit
fbd9b0981f
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))))))
|
||||
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user