AtlatestRepositorysigil-nrepl
sigil-nrepl / treeREADME.md
1
# sigil-nrepl3
Network REPL server for4
[Sigil](https://codeberg.org/sigil/sigil) — provides a JSON-RPC-style5
nREPL endpoint that editors and live-development tools connect to.6
Built on `(sigil repl)` for prompt rendering and command parsing, and7
on `(sigil socket)` for transport.9
Long-running Sigil apps (live-crafter, cinder-cantata, game servers,10
etc.) embed an nREPL server so the developer can evaluate code, switch11
modules, inspect state, and iterate on running code without restarting12
the process.14
## Modules16
| Module | Purpose |17
|------------------------|------------------------------------------------------------------------------|18
| `(sigil nrepl)` | nREPL server: connection handling, session state, op dispatch (eval/doc/...)|19
| `(sigil nrepl client)` | nREPL client: connect, send requests, named-connection registry |21
## Wire protocol23
Messages are length-prefixed S-expressions:25
```26
<length:u32-be><sexp>27
```29
Request format: `(request :id <string> :op <symbol> [:module <string>] [...params])`31
Response format: `(response :id <string> :status <symbol> [...results])`33
Ops supported: `eval`, `abort` (alias `interrupt`), `complete`, `doc`,34
`describe`, `macroexpand`, `switch-module`, `modules`, plus the debug-protocol35
ops (`debug-policy`, `debug-state`, `debug-frames`, `debug-restarts`,36
`debug-quit`).38
### Interrupt / abort40
Expression evals run cooperatively — one preemptive-yield slice per41
`nrepl-process-pending` — so a CPU-bound eval (e.g. `(let loop () (loop))`) does42
not freeze the host's loop. Interrupt one from a second connection:44
```45
(request :id <abort-id> :op abort :target-id <eval-request-id>)46
```48
The abort responder gets `:status ok :aborted <eval-request-id>`; the49
interrupted eval receives `:status error :code "interrupted"`; the session50
survives and evaluates normally afterward. (A single top-level form that mixes51
a top-level `define` with a long loop runs on the immediate, non-abortable path52
— define at top level, then run, as separate requests.)54
### Output streaming56
Output written during an eval is streamed back incrementally as it happens,57
before the final response, carrying the original eval request id:59
```60
(response :id <eval-id> :status out :out <string>) ; stdout61
(response :id <eval-id> :status err :err <string>) ; stderr62
```64
followed by the normal terminal `(response :id <eval-id> :status ok :value …)`.65
The bundled `(sigil nrepl client)` transparently drains these frames and returns66
the terminal response from `nrepl-eval`.68
## Embedding an nREPL server70
```scheme71
(import (sigil nrepl))73
(define server (nrepl-start port: 7888))75
;; In your app's main loop, drain pending requests:76
(nrepl-process-pending server)78
;; On shutdown:79
(nrepl-stop server)80
```82
## Connecting from a client84
```scheme85
(import (sigil nrepl client))87
(define conn (nrepl-connect "127.0.0.1" 7888))88
(nrepl-eval conn "(+ 1 2)") ; => ((status . ok) (value . "3"))89
(nrepl-switch-module conn "(my app)")90
(nrepl-disconnect conn)91
```93
## Build and test95
```96
sigil deps install97
sigil build98
sigil test --report99
```101
Local development against an unreleased sigil monorepo or against a102
local sigil-repl checkout:104
```105
sigil build --redirects ./dev-redirects.sgl106
```108
## License110
BSD-3-Clause. See `LICENSE` in the sigil monorepo for the canonical copy.