Skip to content

Commit

Permalink
Hard fork: v0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
CFiggers committed Sep 26, 2023
1 parent 087b3b6 commit 2b3c046
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 311 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build
jpm_tree/**
.clj-kondo
.lsp
.vscode
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
All notable changes to this project will be documented in this file.
Format for entires is <version-string> - release date.

## 0.0.0 - 2022-08-08
- Created this project.
## 0.0.1 - 2023-09-26
- Hard forked this project from [JohnDoneth/janet-language-server](https://github.com/JohnDoneth/janet-language-server).

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Caleb Figgers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
73 changes: 57 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,73 @@
# Janet Language Server

## Building
A Language Server (LSP) for the Janet programming language.

### Building for Linux
# Overview

```shell
jpm clean && jpm build --lflags=-export-dynamic
```
The goal of this project is to provide an augmented tooling experience for [Janet](https://janet-lang.org), via a self-contained, [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)-compliant language server (which is itself implemented in Janet!).

`export-dynamic` is required for the server to load arbitrary Janet native
modules when it evaluates user documents. Otherwise the symbols for Janet would
not be visible to the newly loaded modules and they would fail to load.
Current features include:
- [x] Partial auto-completion based on defined symbols
- [x] On-hover definition of symbols as returned by `(doc ,symbol)`
- [x] Inline compiler errors

### Building for Windows
Planned features include:
- [ ] Additional autocompletion support
- [ ] Jump to definition/implementation
- [ ] Find references from definition/implementation
- [ ] Refactoring helps
- [ ] Symbol renaming helps

```
"c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
```
Possible (but de-prioritized) features include:
- [ ] Syntax highlighting for Janet via semantic tokens

Desirable but possibly more complicated/difficult features include:
- [ ] Stand-alone (i.e. non-Editor-dependent) usage via API/CLI

# Caveats

- Windows/MacOS support is completely untested and therefore unknown.
- The only editor integration currently tested against is [Visual Studio Code](https://code.visualstudio.com/).
- I've never written a language server before, so I don't really know what I'm doing. Help me, if you'd like!

# Clients (i.e. Editors)

Currently, the only editor tested and known working with janet-lsp is [Visual Studio Code](https://code.visualstudio.com/), which you can try/take advantage of by installing the [Janet++](https://github.com/CFiggers/vscode-janet-plus-plus) extension [from the VS Code marketplace](https://www.example.com).

Other editors that implement LSP client protocols, either built-in or through editor extensions, include:
- Emacs
- vim/neovim
- Sublime Text
- Helix
- Kakoune

If you get janet-lsp working with any of these options, please let me know!

# Getting Started (for Development)

## Clone this project and Build the stand-alone binary

Requires [Janet](https://github.com/janet-lang/janet) and [jpm](https://github.com/janet-lang/jpm).

```shell
jpm clean && jpm build --lflags=/OPT:NOREF
$ git clone https://github.com/CFiggers/janet-lsp
$ cd janet-lsp
$ jpm deps
$ jpm build
```

## Installing

The following command should copy the `janet-language-server` binary to a location that can be executed via the command line.
The following command will copy the `janet-lsp` binary to a location that can be executed via the command line.

```shell
$ jpm install
```
jpm install
```

# Contributions

Issues and Pull Requests welcome.

# Prior Art

This project is a hard fork from (and with much appreciation to) [JohnDoneth/janet-language-server](https://github.com/JohnDoneth/janet-language-server), which is Copyright (c) 2022 JohnDoneth and contributors.
13 changes: 6 additions & 7 deletions project.janet
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
(declare-project
:name "janet-language-server"
:description "Language Server for the Janet Programming Language"
:version "0.0.0"
:dependencies [
"https://github.com/janet-lang/spork.git"
])
:name "janet-lsp"
:description "A Language Server (LSP) for the Janet Programming Language"
:version "0.0.1"
:dependencies ["https://github.com/janet-lang/spork.git"
"https://github.com/ianthehenry/judge.git"])

(declare-executable
:name "janet-language-server"
:name "janet-lsp"
:entry "src/main.janet"
:install true)
148 changes: 72 additions & 76 deletions src/eval.janet
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
(use judge)

(defn- no-side-effects
(defn- no-side-effects # This seems to always only return true no matter what?
`Check if form may have side effects. If returns true, then the src
must not have side effects, such as calling a C function.`
[src]
(cond
(tuple? src)
(if (= (tuple/type src) :brackets)
(all no-side-effects src))
(array? src)
(all no-side-effects src)
(dictionary? src)
(and (all no-side-effects (keys src))
(all no-side-effects (values src)))
true))

(defn- is-safe-def [x] (no-side-effects (last x)))
(tuple? src) (if (= (tuple/type src) :brackets)
(all no-side-effects src))
(array? src) (all no-side-effects src)
(dictionary? src) (and (all no-side-effects (keys src))
(all no-side-effects (values src)))
true))

(defn- is-safe-def [x]
(no-side-effects (last x)))

(def- safe-forms {'defn true 'varfn true 'defn- true 'defmacro true 'defmacro- true
'def is-safe-def 'var is-safe-def 'def- is-safe-def 'var- is-safe-def
'defglobal is-safe-def 'varglobal is-safe-def})

(def- importers {'import true 'import* true 'dofile true 'require true})

(defn- use-2 [evaluator args]
(each a args (import* (string a) :prefix "" :evaluator evaluator)))

Expand All @@ -31,77 +31,73 @@
[thunk source env where]

(when (tuple? source)
(def head (source 0))
(def safe-check
(or
(safe-forms head)
(if (symbol? head)
(if (string/has-prefix? "define-" head) is-safe-def))))
(cond
# Sometimes safe form
(function? safe-check)
(if (safe-check source) (thunk))
# Always safe form
safe-check
(thunk)
# Use
(= 'use head)
(use-2 flycheck-evaluator (tuple/slice source 1))
# Import-like form
(importers head)
(let [[l c] (tuple/sourcemap source)
newtup (tuple/setmap (tuple ;source :evaluator flycheck-evaluator) l c)]
((compile newtup env where))))))
(let [head (source 0)
safe-check (or (safe-forms head)
(when (and (symbol? head) (string/has-prefix? "define-" head))
is-safe-def))]
(cond
# Sometimes safe form
(function? safe-check) (if (safe-check source) (thunk))
# Always safe form
safe-check (thunk)
# Use
(= 'use head) (use-2 flycheck-evaluator (tuple/slice source 1))
# Import-like form
(importers head) (let [[l c] (tuple/sourcemap source)
newtup (tuple/setmap (tuple ;source :evaluator flycheck-evaluator) l c)]
((compile newtup env where)))))))

(defn eval-buffer [str]
(var state (string str))
(defn chunks [buf _]
(def ret state)
(set state nil)
(when ret
(buffer/push-string buf str)
(buffer/push-string buf "\n")))

(var returnval :ok)

(try
(run-context {:chunks chunks
:on-compile-error (fn compile-error [msg errf where line col]
(set returnval [:error {
:message msg
:location [line col]
}]))

:on-parse-error (fn parse-error [p x]
(set returnval [:error {
:message (parser/error p)
:location (parser/where p)
}])
)

:evaluator flycheck-evaluator

:fiber-flags :i

:source :eval-buffer})
([err]
(set returnval [:error {
:message err
:location [0 0]
}]))
)

returnval)
(var state (string str))
(defn chunks [buf _]
(def ret state)
(set state nil)
(when ret
(buffer/push-string buf str)
(buffer/push-string buf "\n")))

(var returnval :ok)

(try
(run-context {:chunks chunks
:on-compile-error (fn compile-error [msg errf where line col]
(set returnval [:error {:message msg
:location [line col]}]))
:on-parse-error (fn parse-error [p x]
(set returnval [:error {:message (parser/error p)
:location (parser/where p)}]))
:evaluator flycheck-evaluator
:fiber-flags :i
:source :eval-buffer})
([err]
(set returnval [:error {:message err
:location [0 0]}])))

returnval)

# tests

# (pp (eval-buffer "(+ 2 2)"))
(deftest "test eval-buffer: (+ 2 2)"
(test (eval-buffer "(+ 2 2)") :ok))

# (pp (eval-buffer "(2)"))
(deftest "test eval-buffer: (2)"
(test (eval-buffer "(2)")
[:error
{:location [1 1]
:message "2 expects 1 argument, got 0"}]))

# (pp (eval-buffer "(+ 2 2"))
(deftest "test eval-buffer: (+ 2 2"
(test (eval-buffer "(+ 2 2")
[:error
{:location [2 0]
:message "unexpected end of source, ( opened at line 1, column 1"}]))

# check for side effects
# (pp (eval-buffer "(pp 42)"))
(deftest "test eval-buffer: (pp 42)"
(test (eval-buffer "(pp 42)") :ok))

# (pp (eval-buffer "()"))
(deftest "test eval-buffer: ()"
(test (eval-buffer "()")
[:error
{:location [0 0]
:message "expected integer key for tuple in range [0, 0), got 0"}]))
9 changes: 9 additions & 0 deletions src/logging.janet
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(defn init-logger []
(setdyn :out stderr)
(setdyn :logfile (file/open "janetlslogs.txt" :w)))

(defn shutdown-logger []
(file/close (dyn :logfile)))

(defn log [output]
(file/write stderr (string output "\n")))
Loading

0 comments on commit 2b3c046

Please sign in to comment.