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 "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).
|
;; 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 {})
|
(local option-mt {})
|
||||||
(fn option [default-value] (doto [default-value] (setmetatable 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-8
|
||||||
:utf-16)))
|
: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]
|
(λ initialize [server params]
|
||||||
(set server.files {})
|
(set server.files {})
|
||||||
(set server.modules {})
|
(set server.modules {})
|
||||||
(set server.root-uri params.rootUri)
|
(set server.root-uri params.rootUri)
|
||||||
(set server.position-encoding (choose-position-encoding params))
|
(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".
|
;; 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.
|
;; 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)))
|
||||||
|
|
||||||
(λ write-configuration [server ?configuration]
|
{: initialize}
|
||||||
"This is where we can put anything that needs to react to config changes"
|
|
||||||
(set server.configuration (make-configuration ?configuration)))
|
|
||||||
|
|
||||||
{: initialize
|
|
||||||
: write-configuration}
|
|
||||||
|
|||||||
@ -11,22 +11,20 @@ in the \"server\" object."
|
|||||||
(local {: compile} (require :fennel-ls.compiler))
|
(local {: compile} (require :fennel-ls.compiler))
|
||||||
|
|
||||||
(λ read-file [server uri]
|
(λ read-file [server uri]
|
||||||
(let [text (case (?. server.preload uri)
|
(case (?. server.preload uri)
|
||||||
preload preload
|
preload {: uri :text preload}
|
||||||
_ (let [file (io.open (utils.uri->path uri))]
|
_ (case (io.open (utils.uri->path uri) "r")
|
||||||
(if file
|
file (let [text (file:read :*a)]
|
||||||
(let [body (file:read :*a)]
|
|
||||||
(file:close)
|
(file:close)
|
||||||
body)
|
{: uri : text}))))
|
||||||
(error (.. "failed to open file " uri)))))]
|
|
||||||
{: uri : text}))
|
|
||||||
|
|
||||||
(λ get-by-uri [server uri]
|
(λ get-by-uri [server uri]
|
||||||
(or (. server.files uri)
|
(or (. server.files uri)
|
||||||
(let [file (read-file server uri)]
|
(case (read-file server uri)
|
||||||
|
file (do
|
||||||
(compile server file)
|
(compile server file)
|
||||||
(tset server.files uri file)
|
(tset server.files uri file)
|
||||||
file)))
|
file))))
|
||||||
|
|
||||||
(λ get-by-module [server module]
|
(λ get-by-module [server module]
|
||||||
;; check the cache
|
;; check the cache
|
||||||
@ -67,4 +65,5 @@ in the \"server\" object."
|
|||||||
{: flush-uri
|
{: flush-uri
|
||||||
: get-by-module
|
: get-by-module
|
||||||
: get-by-uri
|
: 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
|
;; TODO only reload from disk if we didn't get a didSave, instead of always
|
||||||
(files.flush-uri server uri))
|
(files.flush-uri server uri))
|
||||||
|
|
||||||
(λ notifications.workspace/didChangeConfiguration [server _send {: settings}]
|
|
||||||
(config.write-configuration server (?. settings :fennel-ls)))
|
|
||||||
|
|
||||||
(λ requests.shutdown [_server _send]
|
(λ 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"
|
"The server still needs to respond to this request, so the program can't close yet. Just wait until notifications.exit"
|
||||||
nil)
|
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.
|
for using the name of a module and find the corresponding URI.
|
||||||
I suspect this file may be gone after a bit of refactoring."
|
I suspect this file may be gone after a bit of refactoring."
|
||||||
|
|
||||||
(local utils (require :fennel-ls.utils))
|
(local {: absolute-path?
|
||||||
|
: uri->path
|
||||||
(local sep (package.config:sub 1 1))
|
: path->uri
|
||||||
|
: path-sep
|
||||||
(λ absolute? [path]
|
: path-join} (require :fennel-ls.utils))
|
||||||
(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))))
|
|
||||||
|
|
||||||
(λ add-workspaces-to-path [path ?workspaces]
|
(λ add-workspaces-to-path [path ?workspaces]
|
||||||
"Make every relative path be relative to every workspace."
|
"Make every relative path be relative to every workspace."
|
||||||
(let [result []]
|
(let [result []]
|
||||||
(each [path (path:gmatch "[^;]+")]
|
(each [path (path:gmatch "[^;]+")]
|
||||||
(if (absolute? path)
|
(if (absolute-path? path)
|
||||||
(table.insert result path)
|
(table.insert result path)
|
||||||
(each [_ workspace (ipairs (or ?workspaces []))]
|
(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 ";")))
|
(table.concat result ";")))
|
||||||
|
|
||||||
(fn file-exists? [server uri]
|
(fn file-exists? [server uri]
|
||||||
(or (?. server.preload uri)
|
(or (?. server.preload uri)
|
||||||
(case (io.open (utils.uri->path uri))
|
(case (io.open (uri->path uri))
|
||||||
f (do (f:close) true))))
|
f (do (f:close) true))))
|
||||||
|
|
||||||
(λ lookup [{:configuration {: fennel-path} :root-uri ?root-uri &as server} mod]
|
(λ lookup [{:configuration {: fennel-path} :root-uri ?root-uri &as server} mod]
|
||||||
"Use the fennel path to find a file on disk"
|
"Use the fennel path to find a file on disk"
|
||||||
(when ?root-uri
|
(when ?root-uri
|
||||||
(let [mod (mod:gsub "%." sep)
|
(let [mod (mod:gsub "%." path-sep)
|
||||||
root-path (utils.uri->path ?root-uri)]
|
root-path (uri->path ?root-uri)]
|
||||||
(accumulate [uri nil
|
(accumulate [uri nil
|
||||||
segment (fennel-path:gmatch "[^;]+")
|
segment (fennel-path:gmatch "[^;]+")
|
||||||
&until uri]
|
&until uri]
|
||||||
(let [segment (segment:gsub "%?" mod)
|
(let [segment (segment:gsub "%?" mod)
|
||||||
segment (if (absolute? segment)
|
segment (if (absolute-path? segment)
|
||||||
segment
|
segment
|
||||||
(join root-path segment))
|
(path-join root-path segment))
|
||||||
segment (utils.path->uri segment)]
|
segment (path->uri segment)]
|
||||||
(if (file-exists? server segment)
|
(if (file-exists? server segment)
|
||||||
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.
|
Language-Server-Protocol representation and a Lua representation.
|
||||||
These functions are all pure functions, which makes me happy."
|
These functions are all pure functions, which makes me happy."
|
||||||
|
|
||||||
|
(local fennel (require :fennel))
|
||||||
|
|
||||||
(λ next-line [str ?from]
|
(λ next-line [str ?from]
|
||||||
"Find the start of the next line from a given byte offset, or from the start of the string."
|
"Find the start of the next line from a given byte offset, or from the start of the string."
|
||||||
(let [from (or ?from 1)]
|
(let [from (or ?from 1)]
|
||||||
@ -94,7 +96,8 @@ These functions are all pure functions, which makes me happy."
|
|||||||
(λ uri->path [uri]
|
(λ 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"
|
"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://")
|
(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)))
|
(string.sub uri (+ (length prefix) 1)))
|
||||||
|
|
||||||
(λ path->uri [path]
|
(λ 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 "[^ ]+")]
|
(icollect [m (str:gmatch "[^ ]+")]
|
||||||
m))
|
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
|
{: uri->path
|
||||||
: path->uri
|
: path->uri
|
||||||
: pos->position
|
: pos->position
|
||||||
@ -197,4 +222,7 @@ WARNING: this is only used in the test code, not in the real language server"
|
|||||||
: get-ast-info
|
: get-ast-info
|
||||||
: uniq-by
|
: uniq-by
|
||||||
: type=
|
: type=
|
||||||
: split-spaces}
|
: split-spaces
|
||||||
|
: absolute-path?
|
||||||
|
: path-join
|
||||||
|
: path-sep}
|
||||||
|
|||||||
@ -6,9 +6,8 @@
|
|||||||
(create-client
|
(create-client
|
||||||
{:modname.fnl "{:this-is-in-modname {:this :one :isnt :on :the :path}}"
|
{: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}"
|
: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))"}
|
:main.fnl "(local {: this-is-in-mod|name} (require :modname))"
|
||||||
{:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}}})
|
:flsproject.fnl "{:fennel-path \"./?/?/?/?.fnl\"}"})
|
||||||
|
|
||||||
[response] (client:definition uri cursor)]
|
[response] (client:definition uri cursor)]
|
||||||
(faith.= location response.result
|
(faith.= location response.result
|
||||||
"error message")))
|
"error message")))
|
||||||
@ -30,8 +29,10 @@
|
|||||||
;; (local client (doto [] ({:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}}))))
|
;; (local client (doto [] ({:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}}))))
|
||||||
|
|
||||||
(fn test-extra-globals []
|
(fn test-extra-globals []
|
||||||
(let [{:diagnostics good} (create-client "(foo-100 bar :baz)" {:settings {:fennel-ls {:extra-globals "foo-100 bar"}}})
|
(let [{:diagnostics good} (create-client {:main.fnl "(foo-100 bar :baz)"
|
||||||
{:diagnostics bad} (create-client "(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.= [] good)
|
||||||
(faith.not= [] bad))
|
(faith.not= [] bad))
|
||||||
nil)
|
nil)
|
||||||
@ -43,28 +44,23 @@
|
|||||||
;; (local client (doto [] (setup-server {:fennel-ls {:diagnostics {:E202 "warning"}}})))))
|
;; (local client (doto [] (setup-server {:fennel-ls {:diagnostics {:E202 "warning"}}})))))
|
||||||
|
|
||||||
(fn test-lints []
|
(fn test-lints []
|
||||||
(let [{:diagnostics good} (create-client "(local x 10)" {:settings {:fennel-ls {:checks {:unused-definition false}}}})
|
(let [{:diagnostics good} (create-client {:main.fnl "(local x 10)"
|
||||||
{:diagnostics bad} (create-client "(local x 10)")]
|
:flsproject.fnl "{:checks {:unused-definition false}}"})
|
||||||
|
{:diagnostics bad} (create-client {:main.fnl "(local x 10)"
|
||||||
|
:flsproject.fnl "{}"})]
|
||||||
(faith.= [] good)
|
(faith.= [] good)
|
||||||
(faith.not= [] bad))
|
(faith.not= [] bad))
|
||||||
nil)
|
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 []
|
(fn test-native-libaries []
|
||||||
(let [{:diagnostics bad} (create-client "(print btn)"
|
(let [{:diagnostics bad} (create-client {:main.fnl "(print btn)"
|
||||||
{:settings {}})
|
:flsproject.fnl "{}"})
|
||||||
{:diagnostics good} (create-client "(print btn)"
|
{:diagnostics good} (create-client {:main.fnl "(print btn)"
|
||||||
{:settings {:fennel-ls {:native-libraries [:tic80]}}})]
|
:flsproject.fnl "{:native-libraries [:tic80]}"})]
|
||||||
(faith.not= [] bad)
|
(faith.not= [] bad)
|
||||||
(faith.= [] good)))
|
(faith.= [] good)))
|
||||||
|
|
||||||
{: test-path
|
{: test-path
|
||||||
: test-extra-globals
|
: test-extra-globals
|
||||||
: test-lints
|
: test-lints
|
||||||
: test-initialization-options
|
|
||||||
: test-native-libaries}
|
: test-native-libaries}
|
||||||
|
|||||||
@ -25,11 +25,6 @@
|
|||||||
:version 1
|
:version 1
|
||||||
: text}})))
|
: 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]
|
(fn pretend-this-file-exists! [self name text]
|
||||||
(tset self.server.preload name text))
|
(tset self.server.preload name text))
|
||||||
|
|
||||||
@ -75,7 +70,6 @@
|
|||||||
(local client-mt
|
(local client-mt
|
||||||
{:__index {: open-file!
|
{:__index {: open-file!
|
||||||
: pretend-this-file-exists!
|
: pretend-this-file-exists!
|
||||||
: did-change-configuration
|
|
||||||
: completion
|
: completion
|
||||||
: definition
|
: definition
|
||||||
: hover
|
: hover
|
||||||
|
|||||||
@ -81,8 +81,6 @@
|
|||||||
:jsonrpc "2.0"
|
:jsonrpc "2.0"
|
||||||
:method "initialize"
|
:method "initialize"
|
||||||
: params})
|
: params})
|
||||||
_ (when opts.settings
|
|
||||||
(client:did-change-configuration opts.settings))
|
|
||||||
[{:params {: diagnostics}}] (client:open-file! uri text)]
|
[{:params {: diagnostics}}] (client:open-file! uri text)]
|
||||||
{: client
|
{: client
|
||||||
: server
|
: server
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user