From fbd9b0981fcd3bc8bb566bc3c94c4771439ba0b9 Mon Sep 17 00:00:00 2001 From: XeroOl Date: Fri, 5 Jul 2024 12:40:15 -0500 Subject: [PATCH] switch from initialization options and didChangeConfiguration to flsproject.fnl --- src/fennel-ls/config.fnl | 25 ++++++++++++++++------ src/fennel-ls/files.fnl | 33 ++++++++++++++-------------- src/fennel-ls/handlers.fnl | 3 --- src/fennel-ls/searcher.fnl | 44 +++++++++++--------------------------- src/fennel-ls/utils.fnl | 32 +++++++++++++++++++++++++-- test/settings.fnl | 32 ++++++++++++--------------- test/utils/client.fnl | 6 ------ test/utils/init.fnl | 2 -- 8 files changed, 91 insertions(+), 86 deletions(-) diff --git a/src/fennel-ls/config.fnl b/src/fennel-ls/config.fnl index 6e540a6..3c00b88 100644 --- a/src/fennel-ls/config.fnl +++ b/src/fennel-ls/config.fnl @@ -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} diff --git a/src/fennel-ls/files.fnl b/src/fennel-ls/files.fnl index 7ba9646..bc25d74 100644 --- a/src/fennel-ls/files.fnl +++ b/src/fennel-ls/files.fnl @@ -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} diff --git a/src/fennel-ls/handlers.fnl b/src/fennel-ls/handlers.fnl index af1e903..a1655e1 100644 --- a/src/fennel-ls/handlers.fnl +++ b/src/fennel-ls/handlers.fnl @@ -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) diff --git a/src/fennel-ls/searcher.fnl b/src/fennel-ls/searcher.fnl index 3cfacc5..9a70918 100644 --- a/src/fennel-ls/searcher.fnl +++ b/src/fennel-ls/searcher.fnl @@ -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)))))) diff --git a/src/fennel-ls/utils.fnl b/src/fennel-ls/utils.fnl index babd6e8..25a4630 100644 --- a/src/fennel-ls/utils.fnl +++ b/src/fennel-ls/utils.fnl @@ -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} diff --git a/test/settings.fnl b/test/settings.fnl index 5823aa7..25f1b5b 100644 --- a/test/settings.fnl +++ b/test/settings.fnl @@ -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} diff --git a/test/utils/client.fnl b/test/utils/client.fnl index 3e2f985..68fc638 100644 --- a/test/utils/client.fnl +++ b/test/utils/client.fnl @@ -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 diff --git a/test/utils/init.fnl b/test/utils/init.fnl index 42cc1bb..a69f6a5 100644 --- a/test/utils/init.fnl +++ b/test/utils/init.fnl @@ -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