janet-lang / spork

Various Janet utility modules - the official "Contrib" library.
MIT License
122 stars 35 forks source link

Set run-context parser in netrepl/server #33

Closed pyrmont closed 3 years ago

pyrmont commented 3 years ago

This PR:

  1. creates a parser in the netrepl/server function body;
  2. passes this to run-context; and
  3. adds a dynamic reference to the server environment.

It also fixes a bug in test/suite08.janet.

Rationale

At present, netrepl/server doesn't specify the parser to use when it calls run-context. This means that there is no way to manipulate the parser that parses Janet code received from the netrepl client.

The primary reason a client would want to manipulate the parser is so it can set the parser's line and column using parser/where. This is important for editor plugins like Conjure that function as netrepl clients and send code from the editor to the netrepl server. If that code contains an error, the error message will refer to the 'line number' where the error occurred but this 'line number' is not the line number in the file currently being edited. Instead it is the total number of lines that the netrepl client has sent to the netrepl server at the point the error occurred. If an editor client could set the line number before it sent the code to be evaluated, errors produced would refer to the correct line number and be more useful.

Example

An out-of-band command (i.e. a message that beings with the 0xFF) that manipulates the parser can be sent like so:

"\xFF(parser/where (dyn :parser) 120)"

Notes

@bakpakin I'm not sure if using a dynamic reference as I'm doing here is the best approach. Happy to make changes if there's a more appropriate way to do so.

pyrmont commented 3 years ago

One additional point on testing.

Testing

There is currently no test suite for testing the netrepl functionality. I created an example test (included below) based on test/suite03.janet but didn't submit it as part of the PR (yet) because there is no way to silence this line:

https://github.com/janet-lang/spork/blob/b3e8b31454cb56e6d07973fa77121280a08cbe21/spork/netrepl.janet#L107

I don't know if that's a deal breaker.

(use ../spork/test)
(import ../spork/msg)
(import ../spork/netrepl)

(start-suite 9)

(defn wrk [m]
  (with-dyns [:out @""]
    (netrepl/server "localhost" "8000")))

(def wt (thread/new wrk 1 :h)) # we need heavy thread for the assert

(os/sleep 0.1) # give server thread little time to start

(defer (:close wt)
  (def s (net/connect "localhost" "8000"))
  (def recv (msg/make-recv s))
  (def send (msg/make-send s))
  (send "test")
  (assert (= (recv) "test:1: ") "Prompt")
  (send "(+ 1 2)")
  (assert (= (recv) "\e[32m3\e[0m\n") "Result"))

(end-suite)