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:
parent
95245726e1
commit
cd37e05e54
@ -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]
|
(λ requests.initialize [self send params]
|
||||||
(state.init-state self params)
|
(state.init-state self params)
|
||||||
{:capabilities capabilities
|
{:capabilities capabilities
|
||||||
|
:positionEncoding self.position-encoding
|
||||||
:serverInfo {:name "fennel-ls" :version "0.0.0"}})
|
:serverInfo {:name "fennel-ls" :version "0.0.0"}})
|
||||||
|
|
||||||
(λ requests.textDocument/definition [self send {: position :textDocument {: uri}}]
|
(λ requests.textDocument/definition [self send {: position :textDocument {: uri}}]
|
||||||
|
|||||||
@ -100,10 +100,27 @@ in the \"self\" object."
|
|||||||
(λ make-configuration [?c]
|
(λ make-configuration [?c]
|
||||||
(make-configuration-from-template default-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]
|
(λ init-state [self params]
|
||||||
(set self.files {})
|
(set self.files {})
|
||||||
(set self.modules {})
|
(set self.modules {})
|
||||||
(set self.root-uri params.rootUri)
|
(set self.root-uri params.rootUri)
|
||||||
|
(set self.position-encoding (choose-position-encoding params))
|
||||||
(set self.configuration (make-configuration)))
|
(set self.configuration (make-configuration)))
|
||||||
|
|
||||||
(λ write-configuration [self ?configuration]
|
(λ write-configuration [self ?configuration]
|
||||||
|
|||||||
61
test/capabilities-test.fnl
Normal file
61
test/capabilities-test.fnl
Normal 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))))
|
||||||
|
|
||||||
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
(require :test.capabilities-test)
|
||||||
(require :test.completion-test)
|
(require :test.completion-test)
|
||||||
(require :test.diagnostic-test)
|
(require :test.diagnostic-test)
|
||||||
(require :test.goto-definition-test)
|
(require :test.goto-definition-test)
|
||||||
|
|||||||
@ -6,14 +6,11 @@
|
|||||||
(: :read :*a)
|
(: :read :*a)
|
||||||
(: :sub 1 -2) ;; take off newline
|
(: :sub 1 -2) ;; take off newline
|
||||||
(.. "/test/test-project")))
|
(.. "/test/test-project")))
|
||||||
|
|
||||||
(local ROOT-URI
|
(local ROOT-URI
|
||||||
(.. "file://" ROOT-PATH))
|
(.. "file://" ROOT-PATH))
|
||||||
|
|
||||||
(local initialization-message
|
(local default-params
|
||||||
{:id 1
|
|
||||||
:jsonrpc "2.0"
|
|
||||||
:method "initialize"
|
|
||||||
:params
|
|
||||||
{:capabilities {}
|
{:capabilities {}
|
||||||
:clientInfo {:name "Neovim" :version "0.7.2"}
|
:clientInfo {:name "Neovim" :version "0.7.2"}
|
||||||
:initializationOptions {}
|
:initializationOptions {}
|
||||||
@ -22,17 +19,23 @@
|
|||||||
:rootUri ROOT-URI
|
:rootUri ROOT-URI
|
||||||
:trace "off"
|
:trace "off"
|
||||||
:workspaceFolders [{:name ROOT-PATH
|
:workspaceFolders [{:name ROOT-PATH
|
||||||
:uri ROOT-URI}]}})
|
:uri ROOT-URI}]})
|
||||||
|
|
||||||
(local mt {})
|
(local mt {})
|
||||||
(fn create-client [?config]
|
(fn create-client [?opts]
|
||||||
(let [self (doto {:server [] :prev-id 1} (setmetatable mt))]
|
(let [self (doto {:server [] :prev-id 1} (setmetatable mt))
|
||||||
(dispatch.handle* self.server initialization-message)
|
initialize {:id 1
|
||||||
(if ?config
|
:jsonrpc "2.0"
|
||||||
(dispatch.handle* self.server {: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
|
:method :workspace/didChangeConfiguration
|
||||||
:params {:settings ?config}}))
|
:params {: settings}}))
|
||||||
self))
|
(values self result)))
|
||||||
|
|
||||||
(fn next-id! [self]
|
(fn next-id! [self]
|
||||||
(set self.prev-id (+ self.prev-id 1))
|
(set self.prev-id (+ self.prev-id 1))
|
||||||
@ -80,4 +83,5 @@
|
|||||||
: references})
|
: references})
|
||||||
|
|
||||||
{: create-client
|
{: create-client
|
||||||
: ROOT-URI}
|
: ROOT-URI
|
||||||
|
: ROOT-PATH}
|
||||||
|
|||||||
@ -26,6 +26,22 @@
|
|||||||
(check-references "(let [x 10] x)" 0 6
|
(check-references "(let [x 10] x)" 0 6
|
||||||
[{:uri filename :range (message.pos->range 0 12 0 13)}]))
|
[{: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"
|
(it "doesn't crash here"
|
||||||
(check-references "(let [x nil] x.y)" 0 14
|
(check-references "(let [x nil] x.y)" 0 14
|
||||||
nil)))
|
nil)))
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
(import-macros {: is-matching : describe : it : before-each} :test)
|
(import-macros {: is-matching : describe : it : before-each} :test)
|
||||||
(local is (require :test.is))
|
(local is (require :test.is))
|
||||||
|
(local {: view} (require :fennel))
|
||||||
|
|
||||||
(local {: ROOT-URI
|
(local {: ROOT-URI
|
||||||
: create-client} (require :test.mock-client))
|
: create-client} (require :test.mock-client))
|
||||||
|
|
||||||
(describe "settings"
|
(describe "settings"
|
||||||
(it "can set the path"
|
(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))"))
|
(: :open-file! (.. ROOT-URI :/test.fnl) "(local {: this-is-in-modname} (require :modname))"))
|
||||||
result (client:definition (.. ROOT-URI :/test.fnl) 0 12)]
|
result (client:definition (.. ROOT-URI :/test.fnl) 0 12)]
|
||||||
(is-matching
|
(is-matching
|
||||||
@ -15,9 +16,9 @@
|
|||||||
"error message")))
|
"error message")))
|
||||||
|
|
||||||
(it "can set the macro path"
|
(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)")]
|
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)"
|
;; (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
|
;; I suspect this test will fail when I put warnings for module return type
|
||||||
(it "can disable some lints"
|
(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)")]
|
responses (client:open-file! (.. ROOT-URI :/test.fnl) "(local x 10)")]
|
||||||
(is-matching responses
|
(is-matching responses
|
||||||
[{:method :textDocument/publishDiagnostics
|
[{:method :textDocument/publishDiagnostics
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user