Test changes, and fennel-ls now properly negotiates for utf-8 encoding

Unfortunately, fennel-ls still doesn't respect utf-16 rules if the
negotiations fail.
This commit is contained in:
XeroOl 2023-07-09 19:51:20 -05:00
parent 95245726e1
commit cd37e05e54
8 changed files with 121 additions and 20 deletions

View File

@ -64,6 +64,7 @@ Every time the client sends a message, it gets handled by a function in the corr
(λ requests.initialize [self send params]
(state.init-state self params)
{:capabilities capabilities
:positionEncoding self.position-encoding
:serverInfo {:name "fennel-ls" :version "0.0.0"}})
(λ requests.textDocument/definition [self send {: position :textDocument {: uri}}]

View File

@ -100,10 +100,27 @@ in the \"self\" object."
(λ make-configuration [?c]
(make-configuration-from-template default-configuration ?c))
(λ choose-position-encoding [init-params]
"fennel-ls natively uses utf-8, so ideally we will choose positionEncoding=utf-8.
However, fennel-ls can fall back to positionEncoding=utf-16 (with a performance hit)."
(let [?position-encodings (?. init-params :capabilities :general :positionEncodings)
utf8?
(if (= (type ?position-encodings) :table)
(accumulate [utf-8? false
_ encoding (ipairs ?position-encodings)]
(or (= encoding :utf-8)
(= encoding :utf8)))
false)]
(if utf8?
:utf-8
:utf-16)))
(λ init-state [self params]
(set self.files {})
(set self.modules {})
(set self.root-uri params.rootUri)
(set self.position-encoding (choose-position-encoding params))
(set self.configuration (make-configuration)))
(λ write-configuration [self ?configuration]

View File

@ -0,0 +1,61 @@
(import-macros {: is-matching : is-casing : describe : it : before-each} :test)
(local {: view} (require :fennel))
(local is (require :test.is))
(local {: ROOT-URI
: ROOT-PATH
: create-client} (require :test.mock-client))
(fn default [tbl field value]
(when (= nil (. tbl field))
(tset tbl field value)))
(fn client-initialization [params]
(default params :clientInfo {:name "xerool's mock client" :version "9000"}) ;; not necessary, but why not have some fun?
(default params :rootPath ROOT-PATH) ;; deprecated, TODO delete
(default params :rootUri ROOT-URI) ;; deprecated, TODO delete
{default params :workspaceFolders [{:name "my cool space" :uri ROOT-URI}]}
(default params :capabilities {})
(default params :trace "off") ;; | "messages" | "verbose"
;; :initializationOptions {}) ;; LspAny
;; :processId nil
;; :locale "en" ;; I don't support languages/translations as of now
params)
(describe "capabilities negotiations"
; (it "chooses utf-16"
; (let [(self [response])
; (create-client
; {:params
; (client-initialization
; {:capabilities
; {:general
; {:positionEncodings
; [:utf-16]}}})})]
; (is.equal :utf-16 (. response :result :positionEncoding))
; (self:open-file! "foo.fnl" "(let [𐐀𐐀 100] 𐐀𐐀)")
; (let [[response] (self:definition "foo.fnl" 0 16)]
; (is.equal 6 response.result.range.start.character)
; (is.equal 10 response.result.range.end.character))))
(it "chooses utf-8 if at all possible"
(let [(self [response])
(create-client
{:params
(client-initialization
{:capabilities
{:general
{:positionEncodings
[:utf-16 :utf-8]}}})})]
(is.equal :utf-8 (. response :result :positionEncoding))
(self:open-file! "foo.fnl" "(let [𐐀𐐀 100] 𐐀𐐀)")
(let [[response] (self:definition "foo.fnl" 0 20)]
(is.equal 6 response.result.range.start.character)
(is.equal 14 response.result.range.end.character)))))
(it "falls back to utf-16"
(let [(self [response]) (create-client {:params (client-initialization {})})]
(is.equal :utf-16 (. response :result :positionEncoding))))

View File

@ -1,3 +1,4 @@
(require :test.capabilities-test)
(require :test.completion-test)
(require :test.diagnostic-test)
(require :test.goto-definition-test)

View File

@ -64,7 +64,7 @@ function lust.it(name, fn)
end
end
end
if has(arg, "--quit-at-first-test") then os.exit(1) end
end

View File

@ -6,14 +6,11 @@
(: :read :*a)
(: :sub 1 -2) ;; take off newline
(.. "/test/test-project")))
(local ROOT-URI
(.. "file://" ROOT-PATH))
(local initialization-message
{:id 1
:jsonrpc "2.0"
:method "initialize"
:params
(local default-params
{:capabilities {}
:clientInfo {:name "Neovim" :version "0.7.2"}
:initializationOptions {}
@ -22,17 +19,23 @@
:rootUri ROOT-URI
:trace "off"
:workspaceFolders [{:name ROOT-PATH
:uri ROOT-URI}]}})
:uri ROOT-URI}]})
(local mt {})
(fn create-client [?config]
(let [self (doto {:server [] :prev-id 1} (setmetatable mt))]
(dispatch.handle* self.server initialization-message)
(if ?config
(dispatch.handle* self.server {:jsonrpc "2.0"
:method :workspace/didChangeConfiguration
:params {:settings ?config}}))
self))
(fn create-client [?opts]
(let [self (doto {:server [] :prev-id 1} (setmetatable mt))
initialize {:id 1
:jsonrpc "2.0"
:method "initialize"
:params (or (?. ?opts :params) default-params)}
result (dispatch.handle* self.server initialize)]
(case (?. ?opts :settings)
settings
(dispatch.handle* self.server
{:jsonrpc "2.0"
:method :workspace/didChangeConfiguration
:params {: settings}}))
(values self result)))
(fn next-id! [self]
(set self.prev-id (+ self.prev-id 1))
@ -80,4 +83,5 @@
: references})
{: create-client
: ROOT-URI}
: ROOT-URI
: ROOT-PATH}

View File

@ -26,6 +26,22 @@
(check-references "(let [x 10] x)" 0 6
[{:uri filename :range (message.pos->range 0 12 0 13)}]))
(let [x 10] x x x)
(it "finds multiple reference from let"
(check-references "(let [x 10] x x x)" 0 6
[{:uri filename :range (message.pos->range 0 12 0 13)}
{:uri filename :range (message.pos->range 0 14 0 15)}
{:uri filename :range (message.pos->range 0 16 0 17)}]))
(it "finds a reference from fn"
(check-references "(fn x []) x" 0 10
[{:uri filename :range (message.pos->range 0 10 0 11)}]))
; (it "finds a reference from fn"
; (check-references "(fn x []) x" 0 4
; [{:uri filename :range (message.pos->range 0 10 0 11)}]))
(it "doesn't crash here"
(check-references "(let [x nil] x.y)" 0 14
nil)))

View File

@ -1,12 +1,13 @@
(import-macros {: is-matching : describe : it : before-each} :test)
(local is (require :test.is))
(local {: view} (require :fennel))
(local {: ROOT-URI
: create-client} (require :test.mock-client))
(describe "settings"
(it "can set the path"
(let [client (doto (create-client {:fennel-ls {:fennel-path "./?/?.fnl"}})
(let [client (doto (create-client {:settings {:fennel-ls {:fennel-path "./?/?.fnl"}}})
(: :open-file! (.. ROOT-URI :/test.fnl) "(local {: this-is-in-modname} (require :modname))"))
result (client:definition (.. ROOT-URI :/test.fnl) 0 12)]
(is-matching
@ -15,9 +16,9 @@
"error message")))
(it "can set the macro path"
(let [client (create-client {:fennel-ls {:macro-path "./?/?.fnl"}})
(let [client (create-client {:settings {:fennel-ls {:macro-path "./?/?.fnl"}}})
responses (client:open-file! (.. ROOT-URI :/test.fnl) "(import-macros {: this-is-in-modname} :modname)")]
(assert (not (. responses 1 :params 1)) "if the import-macros fails it generates a diagnostic (for now at least)")))
(assert (not (. responses 1 :params :diagnostics 1)) "if the import-macros fails it generates a diagnostic (for now at least)")))
;; (it "recompiles modules if the macro files are modified)"
@ -38,7 +39,7 @@
;; I suspect this test will fail when I put warnings for module return type
(it "can disable some lints"
(let [client (create-client {:fennel-ls {:checks {:unused-definition false}}})
(let [client (create-client {:settings {:fennel-ls {:checks {:unused-definition false}}}})
responses (client:open-file! (.. ROOT-URI :/test.fnl) "(local x 10)")]
(is-matching responses
[{:method :textDocument/publishDiagnostics