diff --git a/fls/file.fnl b/fls/file.fnl new file mode 100644 index 0000000..ba60699 --- /dev/null +++ b/fls/file.fnl @@ -0,0 +1,22 @@ +(local stringx (require :pl.stringx)) + +(λ open-uri [uri] + (local prefix "file://") + (assert (stringx.startswith uri prefix)) + (let [path (string.sub uri 8)] + (io.open path))) + +(λ make-file [uri lines] + {: uri + : lines}) + +(λ make-file-from-disk [uri] + (make-file + uri + (with-open [file (open-uri uri)] + (icollect [line (file:lines)] + line)))) + +{: make-file + : make-file-from-disk} + diff --git a/fls/init.fnl b/fls/init.fnl index f215e76..d417c9c 100644 --- a/fls/init.fnl +++ b/fls/init.fnl @@ -1,4 +1,4 @@ {:error (require :fls.error) - :io (require :fls.io) - :state (require :fls.state) - :log (require :fls.log)} + :log (require :fls.log) + :protocol (require :fls.protocol) + :file (require :fls.file)} diff --git a/fls/io.fnl b/fls/protocol.fnl similarity index 100% rename from fls/io.fnl rename to fls/protocol.fnl diff --git a/fls/state.fnl b/fls/state.fnl deleted file mode 100644 index 4e86ceb..0000000 --- a/fls/state.fnl +++ /dev/null @@ -1,36 +0,0 @@ -(local stringx (require :pl.stringx)) - -(λ open-uri [uri] - (local prefix "file://") - (assert (stringx.startswith uri prefix)) - (let [path (string.sub uri 8)] - (io.open path))) - -(λ make-file [uri lines ?dirty] - {: uri - : lines - :dirty? ?dirty}) - -(λ make-file-from-disk [uri] - (make-file - uri - (with-open [file (open-uri uri)] - (icollect [line (file:lines)] - line)) - false)) - -(fn add-file [self uri ?contents] - ;; assert file isn't loaded yet - (assert (not (. self.files uri))) - (tset - self.files - uri - (make-file-from-disk uri))) - -(fn new-state [] - {:files {}}) - ; :variables {} - ; :settings {} - ; :other-things {} - -{: new-state : add-file} diff --git a/main.fnl b/main.fnl index 54e64b7..2100a1d 100644 --- a/main.fnl +++ b/main.fnl @@ -1,15 +1,14 @@ (local fennel (require :fennel)) (local fls (require :fls)) (local {: run} (require :fennel-ls)) -(local {: make-error-message} (require :fls.error)) (λ main-loop [in out state] (while - (let [msg (fls.io.read in)] + (let [msg (fls.protocol.read in)] (fls.log.log msg) (-?>> msg (run state) - (fls.io.write out)) + (fls.protocol.write out)) msg))) (λ main [] diff --git a/test.fnl b/test.fnl index efe7e73..6cc029a 100644 --- a/test.fnl +++ b/test.fnl @@ -1,87 +1,5 @@ -(local fennel (require :fennel)) -(local fls (require :fls)) -(local stringio (require :pl.stringio)) -(local stringx (require :pl.stringx)) -(local {: run} (require :fennel-ls)) - -(local busted (require :busted)) ((require :busted.runner)) -(macro it! [title ...] `(busted.it ,title (fn [] ,...))) -(macro describe! [title ...] `(busted.describe ,title (fn [] ,...))) - -(describe! "fennel-ls" - - (describe! "fls.io" - (it! "parses incoming messages" - (let [out (stringio.open "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}")] - (assert.same {"my json content" "is cool"} - (fls.io.read out)))) - - (it! "serializes outgoing messages" - (let [in (stringio.create)] - (fls.io.write in {"my json content" "is cool"}) - (assert.same "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}" - (in:value)))) - - (it! "can read multiple incoming messages" - (let [out (stringio.open "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}")] - (assert.same {"my json content" "is cool"} - (fls.io.read out)) - (assert.same {"my json content" "is cool"} - (fls.io.read out)) - (assert.same nil - (fls.io.read out)))) - - (it! "can report the ParseError code" - (let [out (stringio.open "Content-Length: 9\r\n\r\n{{{{{}}}}")] - (assert - (match (run [] (fls.io.read out)) - {:error {:code -32700} :jsonrpc "2.0"} - true - otherwise (values false (fennel.view otherwise))))))) - - ;; FIXME all of the other RPC codes - - (describe! "initialization" - ;; TODO get rid of hardcoded paths here - (it! "responds to initialize" - (local initialize - {:id 1 - :jsonrpc "2.0" - :method "initialize" - :params - {:capabilities {} - :clientInfo {:name "Neovim" :version "0.7.2"} - :initializationOptions {} - :processId 16245 - :rootPath "/home/xerool/Documents/projects/fennel-ls" - :rootUri "file:///home/xerool/Documents/projects/fennel-ls" - :trace "off" - :workspaceFolders [{:name "/home/xerool/Documents/projects/fennel-ls" - :uri "file:///home/xerool/Documents/projects/fennel-ls"}]}}) - (assert - (match (run [] initialize) - {:id 1 - :jsonrpc "2.0" - :result {:capabilities {} - :serverInfo {:name "fennel-ls" : version}}} - true - otherwise (values false (fennel.view otherwise)))))) - - (describe! "file syncing" - (it! "can open files from disk" - (local state (fls.state.new-state)) - (assert state) - (local uri - (-> (io.popen "pwd") - (: :read :*a) - (stringx.strip) - (->> (.. "file://")) - (.. "/test.fnl"))) - - (fls.state.add-file state uri) - (assert (. state :files uri)) - (assert.equal (. state :files uri :lines 1) - "(local fennel (require :fennel))")))) - +(require :test.protocol-test) +(require :test.file-test) +(require :test.lsp-test) diff --git a/test/file-test.fnl b/test/file-test.fnl new file mode 100644 index 0000000..e4c9d7a --- /dev/null +++ b/test/file-test.fnl @@ -0,0 +1,31 @@ +(import-macros {: it! : describe!} :test.macros) +(local assert (require :luassert)) + +(local fennel (require :fennel)) +(local fls (require :fls)) +(local stringx (require :pl.stringx)) + + +(local ROOT-URI + (.. "file://" + (-> (io.popen "pwd") + (: :read :*a) + (stringx.strip)) + "/")) + +(describe! "File Loading" + (it! "can open files from disk" + (local uri (.. ROOT-URI "test.fnl")) + + (local test-fnl-file (fls.file.make-file-from-disk uri)) + (assert.equal (. test-fnl-file.lines 1) + "((require :busted.runner))")) + + (it! "can have files with fixed contents" + (local uri (.. ROOT-URI "test.fnl")) + (local my-file (fls.file.make-file uri ["line 1" "line 2" "line 3"])) + (assert + (match my-file + {:lines ["line 1" "line 2" "line 3"]} + true + otherwise (values false (fennel.view otherwise)))))) diff --git a/test/lsp-test.fnl b/test/lsp-test.fnl new file mode 100644 index 0000000..397b5f1 --- /dev/null +++ b/test/lsp-test.fnl @@ -0,0 +1,32 @@ +(import-macros {: it! : describe!} :test.macros) +(local assert (require :luassert)) + +(local {: run} (require :fennel-ls)) +(local fennel (require :fennel)) + +(describe! "initialization" + ;; TODO get rid of hardcoded paths here + (it! "responds to initialize" + (local initialize + {:id 1 + :jsonrpc "2.0" + :method "initialize" + :params + {:capabilities {} + :clientInfo {:name "Neovim" :version "0.7.2"} + :initializationOptions {} + :processId 16245 + :rootPath "/home/xerool/Documents/projects/fennel-ls" + :rootUri "file:///home/xerool/Documents/projects/fennel-ls" + :trace "off" + :workspaceFolders [{:name "/home/xerool/Documents/projects/fennel-ls" + :uri "file:///home/xerool/Documents/projects/fennel-ls"}]}}) + (assert + (match (run [] initialize) + {:id 1 + :jsonrpc "2.0" + :result {:capabilities {} + :serverInfo {:name "fennel-ls" : version}}} + true + otherwise (values false (fennel.view otherwise)))))) + diff --git a/test/macros.fnl b/test/macros.fnl new file mode 100644 index 0000000..c9f6877 --- /dev/null +++ b/test/macros.fnl @@ -0,0 +1,4 @@ +(fn it! [title ...] `((. (require :busted) :it) ,title (fn [] ,...))) +(fn describe! [title ...] `((. (require :busted) :describe) ,title (fn [] ,...))) + +{: it! : describe!} diff --git a/test/protocol-test.fnl b/test/protocol-test.fnl new file mode 100644 index 0000000..60b4e84 --- /dev/null +++ b/test/protocol-test.fnl @@ -0,0 +1,36 @@ +(import-macros {: it! : describe!} :test.macros) +(local assert (require :luassert)) + +(local fennel (require :fennel)) +(local stringio (require :pl.stringio)) +(local fls (require :fls)) +(local {: run} (require :fennel-ls)) + +(describe! "fls.protocol" + (it! "parses incoming messages" + (let [out (stringio.open "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}")] + (assert.same {"my json content" "is cool"} + (fls.protocol.read out)))) + + (it! "serializes outgoing messages" + (let [in (stringio.create)] + (fls.protocol.write in {"my json content" "is cool"}) + (assert.same "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}" + (in:value)))) + + (it! "can read multiple incoming messages" + (let [out (stringio.open "Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}Content-Length: 29\r\n\r\n{\"my json content\":\"is cool\"}")] + (assert.same {"my json content" "is cool"} + (fls.protocol.read out)) + (assert.same {"my json content" "is cool"} + (fls.protocol.read out)) + (assert.same nil + (fls.protocol.read out)))) + + (it! "can report the ParseError code" + (let [out (stringio.open "Content-Length: 9\r\n\r\n{{{{{}}}}")] + (assert + (match (run [] (fls.protocol.read out)) + {:error {:code -32700} :jsonrpc "2.0"} + true + otherwise (values false (fennel.view otherwise)))))))