more refactoring churn for no reason
This commit is contained in:
parent
f610201b9d
commit
e57833f1e5
@ -1,4 +1,4 @@
|
||||
(local core (require :fennel-ls.core))
|
||||
(local dispatch (require :fennel-ls.dispatch))
|
||||
(local json-rpc (require :fennel-ls.json-rpc))
|
||||
|
||||
(λ main-loop [in out]
|
||||
@ -6,7 +6,7 @@
|
||||
(local state [])
|
||||
(while true
|
||||
(let [msg (json-rpc.read in)]
|
||||
(core.handle state send msg))))
|
||||
(dispatch.handle state send msg))))
|
||||
|
||||
(λ main []
|
||||
(main-loop
|
||||
|
||||
@ -1,10 +1,4 @@
|
||||
(local fennel (require :fennel))
|
||||
(local fennelutils (require :fennel.utils))
|
||||
(local utils (require :fennel-ls.utils))
|
||||
(local insert table.insert)
|
||||
|
||||
(local sym? fennel.sym?)
|
||||
(local list? fennel.list?)
|
||||
|
||||
;; words surrounded by - are symbols,
|
||||
;; because fennel doesn't allow 'require in a runtime file
|
||||
@ -13,32 +7,6 @@
|
||||
(local -λ- (fennel.sym :λ))
|
||||
(local -lambda- (fennel.sym :lambda))
|
||||
|
||||
(λ contains? [?ast byte]
|
||||
;; check if an ast contains a byte
|
||||
(and (= (type ?ast) :table)
|
||||
(utils.get-ast-info ?ast :bytestart)
|
||||
(utils.get-ast-info ?ast :byteend)
|
||||
(<= (utils.get-ast-info ?ast :bytestart)
|
||||
byte
|
||||
(+ 1 (utils.get-ast-info ?ast :byteend)))))
|
||||
|
||||
(λ does-not-contain? [?ast byte]
|
||||
;; check if a byte is in range of the ast
|
||||
(and (= (type ?ast) :table)
|
||||
(utils.get-ast-info ?ast :bytestart)
|
||||
(utils.get-ast-info ?ast :byteend)
|
||||
(not
|
||||
(<= (utils.get-ast-info ?ast :bytestart)
|
||||
byte
|
||||
(+ 1 (utils.get-ast-info ?ast :byteend))))))
|
||||
|
||||
|
||||
(λ past? [?ast byte]
|
||||
;; check if a byte is past an ast object
|
||||
(and (= (type ?ast) :table)
|
||||
(utils.get-ast-info ?ast :bytestart)
|
||||
(< byte (utils.get-ast-info ?ast :bytestart))
|
||||
false))
|
||||
|
||||
(λ multisym? [t]
|
||||
;; check if t is a symbol with multiple parts, eg. foo.bar.baz
|
||||
@ -61,7 +29,7 @@
|
||||
(tset self key val)
|
||||
val))})
|
||||
|
||||
(λ analyze [file]
|
||||
(λ compile [file]
|
||||
"Compile the file, and record all the useful information from the compiler into the file object"
|
||||
|
||||
(local references [])
|
||||
@ -84,6 +52,7 @@
|
||||
;; Add a definition to the definitions
|
||||
;; recursively explore the binding (which, in the general case, is a destructuring assignment)
|
||||
;; right now I'm not keeping track of *how* the symbol was destructured: just finding all the symbols for now.
|
||||
;; also, there's no logic for (values)
|
||||
(λ recurse [binding]
|
||||
(if (fennel.sym? binding)
|
||||
(tset (. definitions scope)
|
||||
@ -156,68 +125,5 @@
|
||||
(set file.references references)
|
||||
;; (set file.definitions definitions) ;; not needed yet
|
||||
(set file.ast ast))
|
||||
;; (set file.analyzed? true))
|
||||
|
||||
(var
|
||||
(search-assignment
|
||||
search-symbol
|
||||
search)
|
||||
nil)
|
||||
|
||||
(set search-assignment
|
||||
(λ search-assignment [self file binding ?definition stack]
|
||||
(if (= 0 (length stack))
|
||||
binding
|
||||
;; TODO sift down the binding
|
||||
(search self file ?definition stack))))
|
||||
|
||||
(set search-symbol
|
||||
(λ search-symbol [self file symbol stack]
|
||||
(let [split (utils.multi-sym-split symbol)]
|
||||
(for [i (length split) 2 -1]
|
||||
(table.insert stack (. split i))))
|
||||
(match (. file.references symbol)
|
||||
to (search-assignment self file to.binding to.definition stack)
|
||||
nil nil)))
|
||||
|
||||
(set search
|
||||
(λ search [self file item stack]
|
||||
(if (fennelutils.table? item)
|
||||
(if (. item (. stack (length stack)))
|
||||
(search self file (. item (table.remove stack)) stack)
|
||||
nil)
|
||||
(sym? item)
|
||||
(search-symbol self file item stack)
|
||||
;; TODO
|
||||
;; functioncall (continue searching in body)
|
||||
;; require call (search in the new module)
|
||||
:else (error (.. "I don't know what to do with " (fennel.view item))))))
|
||||
|
||||
(λ find-symbol [ast byte ?recursively-called]
|
||||
(if (not= :table (type ast))
|
||||
nil
|
||||
(does-not-contain? ast byte)
|
||||
nil
|
||||
(sym? ast)
|
||||
ast
|
||||
(or (not ?recursively-called)
|
||||
(fennel.list? ast)
|
||||
(fennel.sequence? ast))
|
||||
;; TODO binary search
|
||||
(accumulate
|
||||
[result nil
|
||||
_ v (ipairs ast)
|
||||
&until (or result (past? v byte))]
|
||||
(find-symbol v byte true))
|
||||
:else
|
||||
(accumulate
|
||||
[result nil
|
||||
k v (pairs ast)
|
||||
&until result]
|
||||
(or
|
||||
(find-symbol k byte true)
|
||||
(find-symbol v byte true)))))
|
||||
|
||||
{: analyze
|
||||
: find-symbol
|
||||
: search-symbol}
|
||||
;; (set file.compiled? true))
|
||||
{: compile}
|
||||
@ -1,4 +1,4 @@
|
||||
"core
|
||||
"Dispatch
|
||||
This module is responsible for deciding which code to call in response
|
||||
to a given LSP request from the client.
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
"Big dispatch
|
||||
"Handlers
|
||||
You finally made it. Here is the main code that implements the language server protocol
|
||||
|
||||
Every time the client sends a message, it gets handled by a function in the corresponding table type.
|
||||
(ie, a textDocument/didChange notification will call notifications.textDocument/didChange
|
||||
and a textDocument/defintion request will call requests.textDocument/didChange)"
|
||||
(local utils (require :fennel-ls.utils))
|
||||
(local {: pos->byte : apply-changes} (require :fennel-ls.utils))
|
||||
(local message (require :fennel-ls.message))
|
||||
|
||||
(local state (require :fennel-ls.state))
|
||||
(local analyze (require :fennel-ls.analyze))
|
||||
(local language (require :fennel-ls.language))
|
||||
|
||||
(local requests [])
|
||||
(local notifications [])
|
||||
@ -61,17 +60,17 @@ Every time the client sends a message, it gets handled by a function in the corr
|
||||
|
||||
(λ requests.textDocument/definition [self send {: position :textDocument {: uri}}]
|
||||
(local file (state.get-by-uri self uri))
|
||||
(local byte (utils.pos->byte file.text position.line position.character))
|
||||
(match (analyze.find-symbol file.ast byte)
|
||||
(local byte (pos->byte file.text position.line position.character))
|
||||
(match (language.find-symbol file.ast byte)
|
||||
symbol
|
||||
(match (analyze.search-symbol self file symbol [])
|
||||
(match (language.search-symbol self file symbol [])
|
||||
definition
|
||||
{:range (message.range file.text definition)
|
||||
:uri uri})))
|
||||
(λ notifications.textDocument/didChange [self send {: contentChanges :textDocument {: uri}}]
|
||||
(local file (state.get-by-uri self uri))
|
||||
(assert file.open?)
|
||||
(utils.apply-changes (. self.files uri) contentChanges))
|
||||
(apply-changes (. self.files uri) contentChanges))
|
||||
|
||||
(λ notifications.textDocument/didOpen [self send {:textDocument {: languageId : text : uri}}]
|
||||
(local file (state.set-uri-contents self uri text))
|
||||
|
||||
104
src/fennel-ls/language.fnl
Normal file
104
src/fennel-ls/language.fnl
Normal file
@ -0,0 +1,104 @@
|
||||
(local fennel (require :fennel))
|
||||
(local fennelutils (require :fennel.utils))
|
||||
(local utils (require :fennel-ls.utils))
|
||||
(local state (require :fennel-ls.state))
|
||||
|
||||
(local get-ast-info utils.get-ast-info)
|
||||
|
||||
(local sym? fennel.sym?)
|
||||
(local list? fennel.list?)
|
||||
|
||||
(var
|
||||
(search-assignment
|
||||
search-symbol
|
||||
search)
|
||||
nil)
|
||||
|
||||
(set search-assignment
|
||||
(λ search-assignment [self file binding ?definition stack]
|
||||
(if (= 0 (length stack))
|
||||
binding
|
||||
;; TODO sift down the binding
|
||||
(search self file ?definition stack))))
|
||||
|
||||
(set search-symbol
|
||||
(λ search-symbol [self file symbol stack]
|
||||
(let [split (utils.multi-sym-split symbol)]
|
||||
(for [i (length split) 2 -1]
|
||||
(table.insert stack (. split i))))
|
||||
(match (. file.references symbol)
|
||||
to (search-assignment self file to.binding to.definition stack)
|
||||
nil nil)))
|
||||
|
||||
(set search
|
||||
(λ search [self file item stack]
|
||||
(if
|
||||
(fennelutils.table? item)
|
||||
(if (. item (. stack (length stack)))
|
||||
(search self file (. item (table.remove stack)) stack)
|
||||
nil)
|
||||
(sym? item)
|
||||
(search-symbol self file item stack)
|
||||
;; TODO
|
||||
;; functioncall (continue searching in body with parameters bound)
|
||||
(match item
|
||||
[-require- mod]
|
||||
(let [newfile (state.get-by-module self mod)
|
||||
newitem (. newfile.ast (length newfile.ast))]
|
||||
(print newfile.uri mod)
|
||||
(search self newfile newitem stack))
|
||||
_ (error (.. "I don't know what to do with " (fennel.view item)))))))
|
||||
|
||||
(λ past? [?ast byte]
|
||||
;; check if a byte is past an ast object
|
||||
(and (= (type ?ast) :table)
|
||||
(get-ast-info ?ast :bytestart)
|
||||
(< byte (get-ast-info ?ast :bytestart))
|
||||
false))
|
||||
|
||||
(λ contains? [?ast byte]
|
||||
;; check if an ast contains a byte
|
||||
(and (= (type ?ast) :table)
|
||||
(get-ast-info ?ast :bytestart)
|
||||
(get-ast-info ?ast :byteend)
|
||||
(<= (get-ast-info ?ast :bytestart)
|
||||
byte
|
||||
(+ 1 (utils.get-ast-info ?ast :byteend)))))
|
||||
|
||||
(λ does-not-contain? [?ast byte]
|
||||
;; check if a byte is in range of the ast
|
||||
(and (= (type ?ast) :table)
|
||||
(get-ast-info ?ast :bytestart)
|
||||
(get-ast-info ?ast :byteend)
|
||||
(not
|
||||
(<= (get-ast-info ?ast :bytestart)
|
||||
byte
|
||||
(+ 1 (get-ast-info ?ast :byteend))))))
|
||||
|
||||
(λ find-symbol [ast byte ?recursively-called]
|
||||
(if (not= :table (type ast))
|
||||
nil
|
||||
(does-not-contain? ast byte)
|
||||
nil
|
||||
(and (sym? ast) (contains? ast byte))
|
||||
ast
|
||||
(or (not ?recursively-called)
|
||||
(fennel.list? ast)
|
||||
(fennel.sequence? ast))
|
||||
;; TODO binary search
|
||||
(accumulate
|
||||
[result nil
|
||||
_ v (ipairs ast)
|
||||
&until (or result (past? v byte))]
|
||||
(find-symbol v byte true))
|
||||
:else
|
||||
(accumulate
|
||||
[result nil
|
||||
k v (pairs ast)
|
||||
&until result]
|
||||
(or
|
||||
(find-symbol k byte true)
|
||||
(find-symbol v byte true)))))
|
||||
|
||||
{: find-symbol
|
||||
: search-symbol}
|
||||
@ -1,9 +1,11 @@
|
||||
"Message
|
||||
Here are all the constructors for the various JSON-RPC responses
|
||||
that may need to be sent to the client.
|
||||
Here are all the message constructor helpers for the various
|
||||
LSP and JSON-RPC responses that may need to be sent to the client.
|
||||
|
||||
I have them all here because I have a feeling I am conflating
|
||||
missing fields with null fields, and I want to have one location
|
||||
to look to fix this in the future."
|
||||
|
||||
I have them all here because I have a feeling I am conflating missing fields with null fields,
|
||||
and I want to have one location to look to fix this in the future."
|
||||
(local utils (require :fennel-ls.utils))
|
||||
|
||||
(local error-codes
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
(local utils (require :fennel-ls.utils))
|
||||
(local searcher (require :fennel-ls.searcher))
|
||||
|
||||
(local {: analyze} (require :fennel-ls.analyze))
|
||||
(local {: compile} (require :fennel-ls.compiler))
|
||||
|
||||
(λ init-state [self params]
|
||||
(set self.files {})
|
||||
@ -16,19 +16,26 @@
|
||||
(λ get-by-uri [self uri]
|
||||
(or (. self.files uri)
|
||||
(let [file (read-file uri)]
|
||||
(analyze file)
|
||||
(compile file)
|
||||
(tset self.files uri file)
|
||||
file)))
|
||||
|
||||
(λ get-by-module [self module]
|
||||
;; check the cache
|
||||
(match (. self.modules module)
|
||||
uri (or (get-by-uri self uri)
|
||||
uri
|
||||
(or (get-by-uri self uri)
|
||||
;; if the cached uri isn't found, clear the cache and try again
|
||||
(do (tset self.modules module nil)
|
||||
(get-by-module self module)))
|
||||
nil (let [uri (searcher.lookup self module)]
|
||||
nil
|
||||
(match (searcher.lookup self module)
|
||||
uri
|
||||
(do
|
||||
(tset self.modules module uri)
|
||||
(get-by-uri self uri))))
|
||||
(get-by-uri self uri))
|
||||
nil
|
||||
(error (.. "cannot find module " module)))))
|
||||
|
||||
(λ set-uri-contents [self uri text]
|
||||
(if (. self.files uri)
|
||||
@ -36,12 +43,12 @@
|
||||
(let [file (. self.files uri)]
|
||||
(when (not= text file.text)
|
||||
(set file.text text)
|
||||
(analyze file)
|
||||
(compile file)
|
||||
file))
|
||||
;; create new file
|
||||
(let [file {: uri : text}]
|
||||
(tset self.files uri file)
|
||||
(analyze file)
|
||||
(compile file)
|
||||
file)))
|
||||
|
||||
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
(local {: ROOT-URI
|
||||
: setup-server} (require :test.util))
|
||||
|
||||
(local core (require :fennel-ls.core))
|
||||
(local dispatch (require :fennel-ls.dispatch))
|
||||
(local message (require :fennel-ls.message))
|
||||
|
||||
(describe "jump to definition"
|
||||
|
||||
(fn check [request-file line char response-file start-line start-col end-line end-col]
|
||||
(local state (doto [] setup-server))
|
||||
(let [message (core.handle* state
|
||||
(let [message (dispatch.handle* state
|
||||
(message.create-request 2 "textDocument/definition"
|
||||
{:position {:character char :line line}
|
||||
:textDocument {:uri (.. ROOT-URI "/" request-file)}}))
|
||||
@ -47,13 +47,13 @@
|
||||
(check "example.fnl" 21 9 "example.fnl" 16 13 16 16))
|
||||
|
||||
(it "can go to a function inside a table"
|
||||
(check "example.fnl" 28 6 "example.fnl" 4 4 4 7)))
|
||||
(check "example.fnl" 28 6 "example.fnl" 4 4 4 7))
|
||||
|
||||
;; (it "handles (local _ (require XXX)"
|
||||
;; (check "example.fnl" 0 11 "foo.fnl" 0 0 0 0))
|
||||
(it "handles (local _ (require XXX))"
|
||||
(check "example.fnl" 0 10 "foo.fnl" 0 0 0 0))
|
||||
|
||||
;; (it "handles (require XXX))"
|
||||
;; (check "example.fnl" 1 5 "bar.fnl" 0 0 0 0))
|
||||
(it "handles (require XXX))"
|
||||
(check "example.fnl" 1 5 "bar.fnl" 0 0 0 0)))
|
||||
|
||||
;; (it "can go to a field inside of a table")
|
||||
;; (it "can go to a destructured function argument")
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
(local is (require :luassert))
|
||||
|
||||
(local {: ROOT-PATH : ROOT-URI} (require :test.util))
|
||||
(local core (require :fennel-ls.core))
|
||||
(local dispatch (require :fennel-ls.dispatch))
|
||||
|
||||
(local server-initialize-message
|
||||
{:id 1
|
||||
@ -22,7 +22,7 @@
|
||||
(describe "language server"
|
||||
(it "responds to initialize"
|
||||
(is-matching
|
||||
(core.handle* [] server-initialize-message)
|
||||
(dispatch.handle* [] server-initialize-message)
|
||||
[{:jsonrpc "2.0" :id 1
|
||||
:result {:capabilities {}
|
||||
:serverInfo {:name "fennel-ls" : version}}}])))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
(local core (require :fennel-ls.core))
|
||||
(local dispatch (require :fennel-ls.dispatch))
|
||||
|
||||
(local ROOT-PATH
|
||||
(-> (io.popen "pwd")
|
||||
@ -24,6 +24,6 @@
|
||||
:uri ROOT-URI}]}})
|
||||
|
||||
(fn setup-server [state]
|
||||
(core.handle* state initialization-message))
|
||||
(dispatch.handle* state initialization-message))
|
||||
|
||||
{: ROOT-URI : setup-server}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user