Skip to content

Commit

Permalink
Merge pull request #23 from CFiggers/dev
Browse files Browse the repository at this point in the history
v0.0.5
  • Loading branch information
CFiggers authored Jun 14, 2024
2 parents 2bc9f6b + 76cd314 commit d3e51d9
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 253 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Other editors that implement LSP client protocols, either built-in or through ed
- Sublime Text
- Helix
- Kakoune
- Zed

If you get Janet LSP working with any of these options, please let me know!

Expand All @@ -61,16 +62,22 @@ $ jpm deps
$ jpm build
```

Both a stand-alone (albeit _dynamically_ linked) binary executable and a .jimage (Janet image) file will be generated.
A .jimage (Janet image) file will be generated in `/build`. Using a .jimage file makes Janet LSP fully cross-platform (wherever there is a compatible Janet binary on the user's path). But it also means that you must have a Janet binary to use Janet LSP (this author struggles to imagine a scenario where you would both need the LSP and NOT have Janet itself installed).

### Installing

After running the commands above, the following command will copy the `janet-lsp` binary to a location that can be executed via the command line.
After running the commands above, the following command will copy the `janet-lsp` binscript to a location that can be executed via the command line.

```shell
$ jpm install
```

Test successful install by running the following:

```shell
$ janet-lsp --version
```

### Debug Console

Starting in version 0.0.3, you can start a debug console by passing `--console` to any invocation of Janet LSP, including any of the following:
Expand Down
6 changes: 4 additions & 2 deletions project.janet
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
(declare-project
:name "janet-lsp"
:description "A Language Server (LSP) for the Janet Programming Language"
:version "0.0.4"
:version "0.0.5"
:dependencies ["https://github.com/janet-lang/spork.git"
"https://github.com/ianthehenry/judge.git"])
"https://github.com/CFiggers/jayson.git"
"https://github.com/ianthehenry/judge.git"
"https://github.com/CFiggers/cmd.git"])

# (def cflags
# (case (os/which)
Expand Down
11 changes: 8 additions & 3 deletions src/doc.janet
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@
(when col (string ", column " col))))
"\n\n"
(if d
(string/join (-> (string/split "\n" d)
(array/insert 1 "```")
(array/insert 0 "```janet")) "\n")
(let [parts (string/split "\n" d)]
(if (every? ((juxt |(string/has-prefix? "(" $)
|(string/has-suffix? ")" $))
(parts 0)))
(string/join (-> parts
(array/insert 1 "```")
(array/insert 0 "```janet")) "\n")
d))
"No documentation found.\n"))))

(deftest "test make-module-entry: string/trim"
Expand Down
237 changes: 2 additions & 235 deletions src/lookup.janet
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@
(defn lookup [{:line line :character character} source]
(string/from-bytes (((string/split "\n" source) line) character)))

(deftest "lookup"
(test (lookup {:line 0 :character 0} "1\n23\n45") "1")
(test (lookup {:line 1 :character 0} "1\n23\n45") "2")
(test (lookup {:line 1 :character 1} "1\n23\n45") "3")
(test (lookup {:line 2 :character 0} "1\n23\n45") "4")
(test (lookup {:line 2 :character 1} "1\n23\n45") "5"))

(def word-peg
(peg/compile
~{:s (set " \t\0\f\v") :s* (any :s) :s+ (some :s)
Expand All @@ -29,122 +22,18 @@
(break)))
ret)))

(test (peg/match word-peg "(defn main [& args] (+ 1 1))")
@[[0 "" 0]
[1 "defn" 5]
[6 "main" 10]
[11 "[&" 13]
[14 "args]" 19]
[20 "" 20]
[21 "+" 22]
[23 "1" 24]
[25 "1" 26]
[27 "" 27]])

(test (peg/match word-peg "") nil)

(defn word-at [location source]
(defn word-at :tested [location source]
(let [{:character character-pos :line line-pos} location
line ((string/split "\n" source) line-pos)
parsed (or (sort-by last (or (peg/match word-peg line) @[[0 "" 0]])))
word (or (first-where |(>= ($ 2) character-pos) parsed) (last parsed))]
{:range [(word 0) (word 2)] :word (word 1)}))

(test (word-at {:line 0 :character 16} "(def- parse-peg\n") {:range [6 14] :word "parse-peg"})

(test (word-at {:line 1 :character 0} "(import )\n") {:range [0 0] :word ""})

(def sexp-peg
(peg/compile
~{:s-exp (group (* (position) (* "(" (any (+ (drop :s-exp) (to (set "()")))) ")") (position)))
:main (some (+ (if :s-exp 1) 1))}))

(test (peg/match sexp-peg "(defn main [& args] (+ 1 1))") @[@[0 28] @[20 27]])

(test (peg/match sexp-peg "(+ 1 (- 1 1))") @[@[0 13] @[5 12]])

(deftest "advanced sexp-peg test"
(def sample
``
(import spork)
(defmacro first-where [pred ds]
(with-syms [$pred $ds]
~(let [,$pred ,pred ,$ds ,ds]
(var ret "")
(for i 0 (length ,$ds)
(when (,$pred (,$ds i))
(set ret (,$ds i))
(break)))
ret)))
(defn main [& args]
(+ 1 1)
(let [a 1 b 2]
(first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])))
``)
(test (peg/match sexp-peg sample)
@[@[0 14]
@[16 263]
@[50 262]
@[78 261]
@[114 126]
@[134 249]
@[143 156]
@[169 248]
@[175 192]
@[183 191]
@[207 225]
@[216 224]
@[240 247]
@[282 390]
@[304 311]
@[314 389]
@[333 388]
@[347 362]
@[350 359]]))

(deftest "slicing"
(def sample
``
(import spork)
(defmacro first-where [pred ds]
(with-syms [$pred $ds]
~(let [,$pred ,pred ,$ds ,ds]
(var ret "")
(for i 0 (length ,$ds)
(when (,$pred (,$ds i))
(set ret (,$ds i))
(break)))
ret)))
(defn main [& args]
(+ 1 1)
(let [a 1 b 2]
(first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])))
``)
(test (map |[$ (string/slice sample ($ 0) ($ 1))] @[@[0 14] @[16 263] @[50 262] @[78 261] @[114 126] @[134 249] @[143 156] @[169 248] @[175 192] @[183 191] @[207 225] @[216 224] @[240 247] @[282 390] @[304 311] @[314 389] @[333 388] @[347 362] @[350 359]])
@[[@[0 14] "(import spork)"]
[@[16 263] "(defmacro first-where [pred ds]\n (with-syms [$pred $ds]\n ~(let [,$pred ,pred ,$ds ,ds]\n (var ret \"\")\n (for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))\n ret)))"]
[@[50 262] "(with-syms [$pred $ds]\n ~(let [,$pred ,pred ,$ds ,ds]\n (var ret \"\")\n (for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))\n ret))"]
[@[78 261] "(let [,$pred ,pred ,$ds ,ds]\n (var ret \"\")\n (for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))\n ret)"]
[@[114 126] "(var ret \"\")"]
[@[134 249] "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"]
[@[143 156] "(length ,$ds)"]
[@[169 248] "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"]
[@[175 192] "(,$pred (,$ds i))"]
[@[183 191] "(,$ds i)"]
[@[207 225] "(set ret (,$ds i))"]
[@[216 224] "(,$ds i)"]
[@[240 247] "(break)"]
[@[282 390] "(defn main [& args]\n (+ 1 1)\n (let [a 1 b 2]\n (first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])))"]
[@[304 311] "(+ 1 1)"]
[@[314 389] "(let [a 1 b 2]\n (first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]]))"]
[@[333 388] "(first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])"]
[@[347 362] "(< (first $) 0)"]
[@[350 359] "(first $)"]]))

(defn sexp-at [location source]
(let [{:character character-pos :line line-pos} location
idx (+ character-pos (sum (map (comp inc length) (array/slice (string/split "\n" source) 0 line-pos))))
Expand All @@ -153,72 +42,7 @@
{:source (string/slice source ;sexp-range) :range sexp-range}
{:source "" :range @[line-pos character-pos]})))

(test (sexp-at {:line 2 :character 3} "(def a-startup-symbol [])\n\nsymbol\n\n(import spork/argparse)")
{:range @[2 3] :source ""})

(test (sexp-at {:character 15 :line 2} "(def a-startup-symbol [])\n\n(import spork/argparse)")
{:range @[27 50] :source "(import spork/argparse)"})

(deftest "sexp-at"
(def sample
``
(import spork)
(defmacro first-where [pred ds]
(with-syms [$pred $ds]
~(let [,$pred ,pred ,$ds ,ds]
(var ret "")
(for i 0 (length ,$ds)
(when (,$pred (,$ds i))
(set ret (,$ds i))
(break)))
ret)))
(defn main [& args]
(+ 1 1)
(let [a 1 b 2]
(first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])))
``)
(test (map |[$ (sexp-at {:character $ :line 7} sample)] (range 0 37))
@[[0 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[1 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[2 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[3 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[4 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[5 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[6 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[7 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[8 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[9 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[10 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[11 {:range @[134 249] :source "(for i 0 (length ,$ds)\n (when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break)))"}]
[12 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[13 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[14 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[15 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[16 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[17 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]
[18 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[19 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[20 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[21 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[22 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[23 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[24 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[25 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[26 {:range @[183 191] :source "(,$ds i)"}]
[27 {:range @[183 191] :source "(,$ds i)"}]
[28 {:range @[183 191] :source "(,$ds i)"}]
[29 {:range @[183 191] :source "(,$ds i)"}]
[30 {:range @[183 191] :source "(,$ds i)"}]
[31 {:range @[183 191] :source "(,$ds i)"}]
[32 {:range @[183 191] :source "(,$ds i)"}]
[33 {:range @[183 191] :source "(,$ds i)"}]
[34 {:range @[183 191] :source "(,$ds i)"}]
[35 {:range @[175 192] :source "(,$pred (,$ds i))"}]
[36 {:range @[169 248] :source "(when (,$pred (,$ds i))\n (set ret (,$ds i))\n (break))"}]]))

(defn- to-index [location source]
(defn to-index [location source]
(let [{:character character-pos :line line-pos} location
lines (string/split "\n" source)
pre-lines (array/slice lines 0 line-pos)
Expand All @@ -229,60 +53,3 @@
(comment prin "pre-length: ") (comment pp pre-length)
(comment prin "character-pos: ") (comment pp character-pos)
(+ character-pos pre-length)))

(deftest "to-index"
(def sample
``
(import spork)
(defmacro first-where [pred ds]
(with-syms [$pred $ds]
~(let [,$pred ,pred ,$ds ,ds]
(var ret "")
(for i 0 (length ,$ds)
(when (,$pred (,$ds i))
(set ret (,$ds i))
(break)))
ret)))
(defn main [& args]
(+ 1 1)
(let [a 1 b 2]
(first-where |(< (first $) 0) [[-2 :a] [-1 :b] [0 :c]])))
``)
(to-index {:character 3 :line 7} sample))

# tests

(deftest "test word-peg1"
(def sample "word not a word")
(test (peg/match word-peg sample)
@[[0 "word" 4]
[5 "not" 8]
[9 "a" 10]
[11 "word" 14]]))

(deftest "test word-at1"
(test (map |(word-at {:line 0 :character $} "word not a word") (range 15)) @[{:range [0 4] :word "word"} {:range [0 4] :word "word"} {:range [0 4] :word "word"} {:range [0 4] :word "word"} {:range [0 4] :word "word"} {:range [5 8] :word "not"} {:range [5 8] :word "not"} {:range [5 8] :word "not"} {:range [5 8] :word "not"} {:range [9 10] :word "a"} {:range [9 10] :word "a"} {:range [11 14] :word "word"} {:range [11 14] :word "word"} {:range [11 14] :word "word"} {:range [11 14] :word "word"}]))

(deftest "test word-peg2"
(def sample "(defn main [& args] (print \"hello world\"))")
(test (peg/match word-peg sample) @[[0 "" 0] [1 "defn" 5] [6 "main" 10] [11 "[&" 13] [14 "args]" 19] [20 "" 20] [21 "print" 26] [27 "\"hello" 33] [34 "world\"" 40] [41 "" 41]]))

(deftest "test word-peg3"
(test (map |(word-at {:line 0 :character $} "(defn main [& args] (print \"hello world\"))") (range 42)) @[{:range [0 0] :word ""} {:range [1 5] :word "defn"} {:range [1 5] :word "defn"} {:range [1 5] :word "defn"} {:range [1 5] :word "defn"} {:range [1 5] :word "defn"} {:range [6 10] :word "main"} {:range [6 10] :word "main"} {:range [6 10] :word "main"} {:range [6 10] :word "main"} {:range [6 10] :word "main"} {:range [11 13] :word "[&"} {:range [11 13] :word "[&"} {:range [11 13] :word "[&"} {:range [14 19] :word "args]"} {:range [14 19] :word "args]"} {:range [14 19] :word "args]"} {:range [14 19] :word "args]"} {:range [14 19] :word "args]"} {:range [14 19] :word "args]"} {:range [20 20] :word ""} {:range [21 26] :word "print"} {:range [21 26] :word "print"} {:range [21 26] :word "print"} {:range [21 26] :word "print"} {:range [21 26] :word "print"} {:range [21 26] :word "print"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [27 33] :word "\"hello"} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [34 40] :word "world\""} {:range [41 41] :word ""}]))

(deftest "word-at-peg: line 0, character 12, of \"word not a word\n23\n45\""
(test (word-at {:line 0 :character 12} "word not a word\n23\n45") {:range [11 14] :word "word"}))

(deftest "word-at-peg: line 1, character 6, of \"\nword not a word\n23\n45\""
(test (word-at {:line 1 :character 6} "\nword not a word\n23\n45") {:range [5 8] :word "not"}))

(deftest "word-at-peg: line 0, character 0, of \"word\""
(test (word-at {:line 0 :character 0} "word") {:range [0 3] :word "word"}))

(deftest "word-at-peg: line 0, character 4, of \" word \""
(test (word-at {:line 0 :character 4} " word ") {:range [1 5] :word "word"}))

(deftest "word-at-peg: line 0, character 0, of \" \""
(test (word-at {:line 0 :character 0} " ") {:range [1 3] :word ""}))
20 changes: 9 additions & 11 deletions src/main.janet
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

(use judge)

(def version "0.0.3")
(def version "0.0.5")

(def jpm-defs (require "../libs/jpm-defs"))

Expand Down Expand Up @@ -51,11 +51,9 @@

(if (dyn :push-diagnostics)
(let [d (run-diagnostics uri content)]
(if (empty? d)
[:noresponse state]
[:ok state {:method "textDocument/publishDiagnostics"
:params {:uri uri
:diagnostics d}} :notify true]))
[:ok state {:method "textDocument/publishDiagnostics"
:params {:uri uri
:diagnostics d}} :notify true])
[:noresponse state])))

(defn on-document-diagnostic [state params]
Expand Down Expand Up @@ -217,8 +215,8 @@

(defn line-ending []
(case (os/which)
:windows "\n\n"
"\r\n\r\n"))
:windows "\r\n\r\n"
"\n\n"))

(defn read-offset []
(case (os/which)
Expand All @@ -239,10 +237,11 @@
(let [input (file/read stdin :line)
content-length (+ (parse-content-length input) (read-offset))
input (file/read stdin content-length)]
(json/decode input)))
(json/decode input)))

(defn message-loop [&named state]
(let [message (read-message)]
(let [message (read-message)]
(logging/log (string/format "got: %q" message))
(match (handle-message message state)
[:ok new-state & response] (do
(logging/log "successful rpc")
Expand Down Expand Up @@ -285,7 +284,6 @@

(defn start-language-server []
(print "Starting LSP")
(logging/log "Starting LSP")
(when (dyn :debug) (spit "janetlsp.log.txt" ""))

(merge-module root-env jpm-defs nil true)
Expand Down
Loading

0 comments on commit d3e51d9

Please sign in to comment.