diff --git a/src/fennel-ls/config.fnl b/src/fennel-ls/config.fnl index b415f5c..6e540a6 100644 --- a/src/fennel-ls/config.fnl +++ b/src/fennel-ls/config.fnl @@ -64,7 +64,6 @@ However, when not an option, fennel-ls will fall back to positionEncoding=\"utf- (位 initialize [server params] (set server.files {}) - (set server.preload {}) (set server.modules {}) (set server.root-uri params.rootUri) (set server.position-encoding (choose-position-encoding params)) diff --git a/src/fennel-ls/files.fnl b/src/fennel-ls/files.fnl index 67c2086..7ba9646 100644 --- a/src/fennel-ls/files.fnl +++ b/src/fennel-ls/files.fnl @@ -11,7 +11,7 @@ in the \"server\" object." (local {: compile} (require :fennel-ls.compiler)) (位 read-file [server uri] - (let [text (case (. server.preload uri) + (let [text (case (?. server.preload uri) preload preload _ (let [file (io.open (utils.uri->path uri))] (if file diff --git a/test/capabilities.fnl b/test/capabilities.fnl index 47338bb..daf01ec 100644 --- a/test/capabilities.fnl +++ b/test/capabilities.fnl @@ -1,45 +1,46 @@ (local faith (require :faith)) -(local {: ROOT-URI - : ROOT-PATH - : create-client} (require :test.utils.client)) -(local {: get-markup} (require :test.utils)) - -(fn params-with-encodings [encodings] - {:clientInfo {:name "my mock client" :version "9000"} - :rootPath ROOT-PATH - :rootUri ROOT-URI - :workspaceFolders [{:name "foo" :uri ROOT-URI}] - :capabilities {:general {:positionEncodings encodings}} - :trace "off"}) +(local {: create-client : NIL} (require :test.utils)) (fn test-offset-encoding [] - (let [(client _ [response]) - (create-client {:params (params-with-encodings [:utf-16])}) - _ (faith.= :utf-16 (. response :result :capabilities :positionEncoding)) - {: text : cursor :ranges [{: start : end}]} (get-markup "(let [==饜悁饜悁== 100] 饜悁饜悁|)" :utf-16) - _ (client:open-file! "foo.fnl" text) - [response] (client:definition "foo.fnl" cursor)] - (faith.= start response.result.range.start) - (faith.= end response.result.range.end)) + (let [{: client + : cursor + : uri + : encoding + :locations [{:range {: start : end}}] + : initialize-response} (create-client "(let [==饜悁饜悁== 100] 饜悁饜悁|)" + {:position-encodings [:utf-16] + :markup-encoding :utf-16}) + [response] (client:definition uri cursor)] + (faith.= :utf-16 encoding) + (faith.= :utf-16 (. initialize-response 1 :result :capabilities :positionEncoding)) + (faith.= cursor {:line 0 :character 20}) + (faith.= start response.result.range.start) + (faith.= end response.result.range.end)) - (let [(client _ [response]) - (create-client {:params (params-with-encodings [:utf-16 :utf-8])}) - _ (faith.= :utf-8 (. response :result :capabilities :positionEncoding)) - {: text : cursor :ranges [{: start : end}]} (get-markup "(let [==饜悁饜悁== 100] 饜悁饜悁|)" :utf-8) - _ (client:open-file! "foo.fnl" text) - [response] (client:definition "foo.fnl" cursor)] + (let [{: client + : cursor + : uri + : encoding + :locations [{:range {: start : end}}] + : initialize-response} (create-client "(let [==饜悁饜悁== 100] 饜悁饜悁|)" + {:position-encodings [:utf-8] + :markup-encoding :utf-8}) + [response] (client:definition uri cursor)] + (faith.= :utf-8 encoding) + (faith.= :utf-8 (. initialize-response 1 :result :capabilities :positionEncoding)) + (faith.= cursor {:line 0 :character 28}) (faith.= start response.result.range.start) (faith.= end response.result.range.end)) ;; utf-16 is the fallback - (let [(_ _ [response]) (create-client {:params (params-with-encodings nil)})] - (faith.= :utf-16 (. response :result :capabilities :positionEncoding))) + (let [{: initialize-response} (create-client "" {:position-encodings NIL})] + (faith.= :utf-16 (. initialize-response 1 :result :capabilities :positionEncoding))) - (let [(_ _ [response]) (create-client {:params (params-with-encodings [:random-encoding])})] - (faith.= :utf-16 (. response :result :capabilities :positionEncoding))) + (let [{: initialize-response} (create-client "" {:position-encodings [:some-unknown-encoding]})] + (faith.= :utf-16 (. initialize-response 1 :result :capabilities :positionEncoding))) - (let [(_ _ [response]) (create-client {:params (params-with-encodings [:utf-8 :utf-16])})] - (faith.= :utf-8 (. response :result :capabilities :positionEncoding))) + (let [{: initialize-response} (create-client "" {:position-encodings [:utf-8 :utf-16]})] + (faith.= :utf-8 (. initialize-response 1 :result :capabilities :positionEncoding))) nil) diff --git a/test/code-action.fnl b/test/code-action.fnl index a04cce2..eb13bd0 100644 --- a/test/code-action.fnl +++ b/test/code-action.fnl @@ -1,12 +1,12 @@ (local faith (require :faith)) (local {: view} (require :fennel)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local {: apply-edits} (require :fennel-ls.utils)) -(create-client-with-files "(print :hi)") +(create-client "(print :hi)") (fn check [file-contents action-I-want-to-take desired-file-contents] - (let [{: client : uri :locations [range] : encoding : text} (create-client-with-files file-contents) + (let [{: client : uri :locations [range] : encoding : text} (create-client file-contents) [{:result responses}] (client:code-action uri range.range) action (accumulate [result nil _ action (ipairs responses) &until result] @@ -21,7 +21,7 @@ edited-text (apply-edits text edits encoding)] (faith.= desired-file-contents edited-text)))) (fn check-negative [file-contents action-not-suggested] - (let [{: client : uri :locations [range]} (create-client-with-files file-contents) + (let [{: client : uri :locations [range]} (create-client file-contents) [{:result responses}] (client:code-action uri range.range)] (each [_ action (ipairs responses)] (assert (not= action.title action-not-suggested) diff --git a/test/completion.fnl b/test/completion.fnl index 4499461..cc9cf15 100644 --- a/test/completion.fnl +++ b/test/completion.fnl @@ -1,5 +1,5 @@ (local faith (require :faith)) -(local {: create-client-with-files +(local {: create-client : position-past-end-of-text} (require :test.utils)) (local {: view} (require :fennel)) @@ -42,8 +42,8 @@ (and (= (type e.textEdit) :function)) (e.textEdit c.textEdit)))) i))) -(fn check [file-contents expected unexpected ?client-options] - (let [{: client : uri : cursor : text} (create-client-with-files file-contents ?client-options) +(fn check [file-contents expected unexpected ?client-opts] + (let [{: client : uri : cursor : text} (create-client file-contents ?client-opts) [{:result ?result}] (client:completion uri (or cursor (position-past-end-of-text text))) @@ -241,15 +241,7 @@ []) nil) -(local eglot {:params {:capabilities {:general {:positionEncodings [:utf-8]}} - :clientInfo {:name "Eglot" :version "1 million"} - :initializationOptions {} - :processId 1000 - :rootPath "/home/my-cool-user/my-cool-project/" - :rootUri "file:///home/my-cool-user/my-cool-project/" - :trace "off" - :workspaceFolders [{:name "/home/my-cool-user/my-cool-projects/" - :uri "file:///home/my-cool-user/my-cool-project/"}]}}) +(local eglot {:client-info {:name "Eglot" :version "1 million"}}) (fn test-eglot-fields [] "tests for handling Eglot specially" diff --git a/test/diagnostic.fnl b/test/diagnostic.fnl index 1c26233..ef0fcce 100644 --- a/test/diagnostic.fnl +++ b/test/diagnostic.fnl @@ -1,6 +1,6 @@ (local faith (require :faith)) (local {: view} (require :fennel)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (fn find [diagnostics e] "returns the index of the diagnostic that matches `e`" @@ -21,7 +21,7 @@ i))) (fn check [file-contents expected unexpected] - (let [{: diagnostics} (create-client-with-files file-contents)] + (let [{: diagnostics} (create-client file-contents)] (each [_ e (ipairs unexpected)] (let [i (find diagnostics e)] (faith.= nil i (.. "Lint matching " (view e) "\n" diff --git a/test/goto-definition.fnl b/test/goto-definition.fnl index 87ca290..b623568 100644 --- a/test/goto-definition.fnl +++ b/test/goto-definition.fnl @@ -1,10 +1,10 @@ (local faith (require :faith)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local {: null} (require :dkjson)) (local {: view} (require :fennel)) (fn check [file-contents] - (let [{: client : uri : cursor :locations [location]} (create-client-with-files file-contents) + (let [{: client : uri : cursor :locations [location]} (create-client file-contents) [message] (client:definition uri cursor)] (if location (faith.= location message.result diff --git a/test/hover.fnl b/test/hover.fnl index 407fec2..3b4eaac 100644 --- a/test/hover.fnl +++ b/test/hover.fnl @@ -1,10 +1,10 @@ (local faith (require :faith)) (local {: view} (require :fennel)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local {: null} (require :dkjson)) (fn check [file-contents ?response-string] - (let [{: client : uri : cursor} (create-client-with-files file-contents) + (let [{: client : uri : cursor} (create-client file-contents) [message] (client:hover uri cursor)] (if (= (type ?response-string) :string) (faith.= ?response-string (?. message :result :contents :value) diff --git a/test/lint.fnl b/test/lint.fnl index 9bd7621..ccda4a0 100644 --- a/test/lint.fnl +++ b/test/lint.fnl @@ -1,6 +1,6 @@ (local faith (require :faith)) (local {: view} (require :fennel)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (fn find [diagnostics e] "returns the index of the diagnostic " @@ -21,7 +21,7 @@ i))) (fn check [file-contents expected unexpected] - (let [{: diagnostics} (create-client-with-files file-contents)] + (let [{: diagnostics} (create-client file-contents)] (each [_ e (ipairs unexpected)] (let [i (find diagnostics e)] (faith.= nil i (.. "Lint matching " (view e) "\n" diff --git a/test/misc.fnl b/test/misc.fnl index 147cbef..0e9d576 100644 --- a/test/misc.fnl +++ b/test/misc.fnl @@ -1,6 +1,6 @@ (local faith (require :faith)) (local fennel (require :fennel)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local analyzer (require :fennel-ls.analyzer)) (local utils (require :fennel-ls.utils)) @@ -16,7 +16,7 @@ nil) (fn test-find-symbol [] - (let [{: server : uri} (create-client-with-files "(match [1 2 4] [1 2 sym-one] sym-one)") + (let [{: server : uri} (create-client "(match [1 2 4] [1 2 sym-one] sym-one)") file (. server.files uri) (symbol parents) (analyzer.find-symbol file.ast 23)] (faith.= symbol (fennel.sym :sym-one)) @@ -25,7 +25,7 @@ (fennel.view parents {:one-line? true}) "bad parents")) - (let [{: server : uri} (create-client-with-files "(match [1 2 4] [1 2 sym-one] sym-one)") + (let [{: server : uri} (create-client "(match [1 2 4] [1 2 sym-one] sym-one)") file (. server.files uri) (symbol parents) (analyzer.find-symbol file.ast 18)] (faith.= symbol nil) @@ -36,11 +36,11 @@ nil) (fn test-failure [] - (create-client-with-files "(macro foo {} nil) - (位 test {} nil) - (位 {} nil") - (create-client-with-files "(fn foo []\n #\n (print :test))") - (create-client-with-files "(let [map {}] (set (. map (tostring :a)) :b))") + (create-client "(macro foo {} nil) + (位 test {} nil) + (位 {} nil") + (create-client "(fn foo []\n #\n (print :test))") + (create-client "(let [map {}] (set (. map (tostring :a)) :b))") nil) (fn test-split-spaces [] diff --git a/test/references.fnl b/test/references.fnl index 2a2b16f..c29c8d9 100644 --- a/test/references.fnl +++ b/test/references.fnl @@ -1,5 +1,5 @@ (local faith (require :faith)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local {: null} (require :dkjson)) (local {: view} (require :fennel)) @@ -16,7 +16,7 @@ (= a.range.end.character b.range.end.character))))))))))) (fn check [file-contents] - (let [{: client : uri : cursor : locations} (create-client-with-files file-contents) + (let [{: client : uri : cursor : locations} (create-client file-contents) [response] (client:references uri cursor)] (if (not= null response.result) (do diff --git a/test/rename.fnl b/test/rename.fnl index 0190b81..2247bf9 100644 --- a/test/rename.fnl +++ b/test/rename.fnl @@ -1,10 +1,10 @@ (local faith (require :faith)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (local {: null} (require :dkjson)) (local {: apply-edits} (require :fennel-ls.utils)) (fn check [file-content new-name expected-file-content] - (let [{: client : uri : cursor : text : encoding} (create-client-with-files file-content) + (let [{: client : uri : cursor : text : encoding} (create-client file-content) [{: result}] (client:rename uri cursor new-name)] (if (= null result) (faith.= expected-file-content text) diff --git a/test/settings.fnl b/test/settings.fnl index f3a8d8a..5823aa7 100644 --- a/test/settings.fnl +++ b/test/settings.fnl @@ -1,11 +1,9 @@ (local faith (require :faith)) -(local {: ROOT-URI - : ROOT-PATH} (require :test.utils.client)) -(local {: create-client-with-files} (require :test.utils)) +(local {: create-client} (require :test.utils)) (fn test-path [] (let [{: client : uri : cursor :locations [location]} - (create-client-with-files + (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))"} @@ -17,7 +15,7 @@ ;; TODO fix macros to use a custom searcher ; (let [{: diagnostics} - ; (create-client-with-files + ; (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 "(import-macros {: this-is-in-modname} :modname) @@ -32,8 +30,8 @@ ;; (local client (doto [] ({:settings {:fennel-ls {:fennel-path "./?/?/?/?.fnl"}})))) (fn test-extra-globals [] - (let [{:diagnostics good} (create-client-with-files "(foo-100 bar :baz)" {:settings {:fennel-ls {:extra-globals "foo-100 bar"}}}) - {:diagnostics bad} (create-client-with-files "(foo-100 bar :baz)")] + (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)")] (faith.= [] good) (faith.not= [] bad)) nil) @@ -45,26 +43,22 @@ ;; (local client (doto [] (setup-server {:fennel-ls {:diagnostics {:E202 "warning"}}}))))) (fn test-lints [] - (let [{:diagnostics good} (create-client-with-files "(local x 10)" {:settings {:fennel-ls {:checks {:unused-definition false}}}}) - {:diagnostics bad} (create-client-with-files "(local x 10)")] + (let [{:diagnostics good} (create-client "(local x 10)" {:settings {:fennel-ls {:checks {:unused-definition false}}}}) + {:diagnostics bad} (create-client "(local x 10)")] (faith.= [] good) (faith.not= [] bad)) nil) (fn test-initialization-options [] - (let [initializationOptions {:fennel-ls {:checks {:unused-definition false}}} - {: diagnostics} (create-client-with-files "(local x 10)" {:params {: initializationOptions - :rootPath ROOT-PATH - :rootUri ROOT-URI - :workspaceFolders [{:name ROOT-PATH - :uri ROOT-URI}]}})] + (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-with-files "(print btn)" + (let [{:diagnostics bad} (create-client "(print btn)" {:settings {}}) - {:diagnostics good} (create-client-with-files "(print btn)" + {:diagnostics good} (create-client "(print btn)" {:settings {:fennel-ls {:native-libraries [:tic80]}}})] (faith.not= [] bad) (faith.= [] good))) diff --git a/test/utils/client.fnl b/test/utils/client.fnl index 8b8cc19..3e2f985 100644 --- a/test/utils/client.fnl +++ b/test/utils/client.fnl @@ -12,34 +12,6 @@ (local default-encoding :utf-8) -(local mt {}) -(fn create-client [?opts ?provide-root-uri] - (let [server [] - params (or (?. ?opts :params) - {:capabilities {:general {:positionEncodings [default-encoding]}} - :clientInfo {:name "Neovim" :version "0.7.2"} - :initializationOptions {} - :processId 16245 - :rootPath (if ?provide-root-uri ROOT-PATH) - :rootUri (if ?provide-root-uri ROOT-URI) - :trace "off" - :workspaceFolders (if ?provide-root-uri - [{:name ROOT-PATH - :uri ROOT-URI}])}) - initialize {:id 1 - :jsonrpc "2.0" - :method "initialize" - : params} - initialize-response (dispatch.handle* server initialize) - client (doto {: server :prev-id 1} (setmetatable mt))] - (case (?. ?opts :settings) - settings - (dispatch.handle* server - {:jsonrpc "2.0" - :method :workspace/didChangeConfiguration - :params {: settings}})) - (values client server initialize-response))) - (fn next-id! [self] (set self.prev-id (+ self.prev-id 1)) self.prev-id) @@ -53,6 +25,11 @@ :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)) @@ -95,17 +72,18 @@ :textDocument {:uri file} :context {:diagnostics []}}))) -(set mt.__index - {: open-file! - : pretend-this-file-exists! - : completion - : definition - : hover - : references - : rename - : code-action}) +(local client-mt + {:__index {: open-file! + : pretend-this-file-exists! + : did-change-configuration + : completion + : definition + : hover + : references + : rename + : code-action}}) -{: create-client +{: client-mt : default-encoding : ROOT-URI : ROOT-PATH} diff --git a/test/utils/init.fnl b/test/utils/init.fnl index 2a9ee63..42cc1bb 100644 --- a/test/utils/init.fnl +++ b/test/utils/init.fnl @@ -1,9 +1,17 @@ (local {: ROOT-URI - : create-client + : ROOT-PATH + : client-mt : default-encoding} (require :test.utils.client)) -(local utils (require :fennel-ls.utils)) -(fn get-markup [text ?encoding] +(local utils (require :fennel-ls.utils)) +(local dispatch (require :fennel-ls.dispatch)) + +(local NIL {}) +(fn un-nil [arg] + (if (not= arg NIL) + arg)) + +(fn parse-markup [text ?encoding] "find the | character, which represents the cursor position" (var text text) (let [result {:ranges []} @@ -33,25 +41,49 @@ (set result.text text) result)) -(fn create-client-with-files [file-contents ?client-options] - (let [(?give-a-root-uri file-contents) (if (= (type file-contents) :string) - (values nil {:main.fnl file-contents}) - (values true file-contents)) - (client server) (create-client ?client-options ?give-a-root-uri) +(fn create-client [file-contents ?opts] + ;; TODO big function, split up + (let [opts (or ?opts {}) + (provide-root-uri file-contents) (if (= (type file-contents) :table) + (values true file-contents) + (values false {:main.fnl file-contents})) + + server {:preload (if provide-root-uri {})} + client (doto {: server :prev-id 1} + (setmetatable client-mt)) locations []] - (each [name marked (pairs file-contents)] + ;; NOT main.fnl + (each [name contents (pairs file-contents)] (if (not= name :main.fnl) (let [uri (.. ROOT-URI "/" name) - {: text : ranges} (get-markup marked)] + {: text : ranges} (parse-markup contents opts.markup-encoding)] (icollect [_ range (ipairs ranges) &into locations] {: range : uri}) (client:pretend-this-file-exists! uri text)))) + ;; main.fnl (let [uri (.. ROOT-URI "/" :main.fnl) main-file-contents (. file-contents :main.fnl) - {: text : ranges : cursor} (get-markup main-file-contents)] - (icollect [_ range (ipairs ranges) &into locations] - {: range : uri}) - (let [[{:params {: diagnostics}}] (client:open-file! uri text)] + {: text : ranges : cursor} (parse-markup main-file-contents opts.markup-encoding) + _ (icollect [_ range (ipairs ranges) &into locations] + {: range : uri}) + + params {:capabilities {:general {:positionEncodings (un-nil (or opts.position-encodings [default-encoding]))}} + :clientInfo (un-nil (or opts.client-info {:name "Neovim" :version "0.7.2"})) + :initializationOptions opts.initialization-options + :processId 16245 + :rootPath (if provide-root-uri ROOT-PATH) + :rootUri (if provide-root-uri ROOT-URI) + :trace "off" + :workspaceFolders (if provide-root-uri [{:name ROOT-PATH :uri ROOT-URI}])} + + initialize-response (dispatch.handle* server + {:id 1 + :jsonrpc "2.0" + :method "initialize" + : params}) + _ (when opts.settings + (client:did-change-configuration opts.settings)) + [{:params {: diagnostics}}] (client:open-file! uri text)] {: client : server : diagnostics @@ -59,11 +91,13 @@ : locations : text : uri - :encoding server.position-encoding})))) + : initialize-response + :encoding server.position-encoding}))) (fn position-past-end-of-text [text ?encoding] (utils.byte->position text (+ (length text) 1) (or ?encoding default-encoding))) -{: create-client-with-files +{: create-client : position-past-end-of-text - : get-markup} + : parse-markup + : NIL}