~akarle/fisl

3e6652310186a1debf0710fa1d071a4a7c876deb — Alex Karle 1 year, 11 months ago 517e4a7
repl: Add threads and nrepl for live image updates

This was a deep rabbit hole, mostly because (read-line) is blocking I/O
and _all_ threads block when blocking I/O is hit (except tcp). This was
counterintuitive (isn't the whole point of threads to swap when on I/O?)
but nevertheless, I got it to work!

Here's my setup:

1. Start the CHICKEN interpreter via the executable (drops into Lox
   interpreter):

$ ./fisl.scm
> print 1 + 1;
2
>

2. In another tmux split, create a fifo and connect to the 1234 nrepl
   port (credit: http://www.foldling.org/hacking.html#2012-08-05):

$ mkfifo repl
$ cat > repl & nc localhost 1234 < repl

3. Lastly, in Vim, run the following to send the current paragraph to
   the repl on C-c C-c:

:nnoremap <C-c><C-c> vap:w >> repl<CR>

---

Demo:

* Go to (prompt), update s/display "> "/display ">> "/
* C-c C-c
* Hit enter in fisl -- notice prompt is changed!
1 files changed, 26 insertions(+), 9 deletions(-)

M fisl.scm
M fisl.scm => fisl.scm +26 -9
@@ 1,6 1,9 @@
#!/usr/local/bin/chicken-csi -ss
;; fisl -- fisl is scheme lox
(import (chicken io)
(import srfi-18
        nrepl
        (chicken io)
        (chicken repl)
        (chicken base)
        (chicken format))



@@ 16,14 19,25 @@
	  (if stmts
	      (interpret stmts))))))

(define (run-prompt)
(define (prompt)
  ;; HACK: srfi-18 blocks for IO, so having run-prompt
  ;; use read-line means that nrepl just doesn't work :(
  ;; the "solution" is to set the i/o to non-blocking
  ;; (adapted from the srfi-18 egg itself)
  (display "> ")
  (let ((l (read-line)))
    (if (not (or (eof-object? l) (equal? l ",q")))
      (begin
        (run l "repl")
        (clear-err!)
        (run-prompt)))))
  (flush-output)
  (##sys#thread-block-for-i/o! ##sys#current-thread 0 #:input)
  (thread-yield!))

(define (run-prompt)
  (parameterize ((repl-prompt "> "))
    (prompt)
    (let ((l (read-line)))
      (if (not (or (eof-object? l) (equal? l ",q")))
        (begin
          (run l "repl")
          (clear-err!)
          (run-prompt))))))

(define (run-file fname)
  (call-with-input-file fname (lambda (p)


@@ 33,6 47,9 @@
(define (main args)
  (let ((argc (length args)))
    (cond
      ((eq? argc 0) (run-prompt) (exit 0))
      ((eq? argc 0)
       (thread-start! (lambda () (run-prompt) (exit 0)))
       (print "starting the repl")
       (nrepl 1234))
      ((eq? argc 1) (run-file (car args)))
      (else (die "Too many arguments. Usage: fisl [FILE]")))))