summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Antonio Ortega Ruiz <jao@gnu.org>2010-11-09 21:35:50 +0100
committerJose Antonio Ortega Ruiz <jao@gnu.org>2010-11-09 21:35:50 +0100
commitf2bf4b2cda05fe8c32ee74ce3b5cce743d81de61 (patch)
tree81250c2797eac0a594a393f361287c6fb0fd4688
parent512fa06fec02b7dc8ce11684313f7a0ab56bef6b (diff)
downloadgeiser-chez-f2bf4b2cda05fe8c32ee74ce3b5cce743d81de61.tar.gz
geiser-chez-f2bf4b2cda05fe8c32ee74ce3b5cce743d81de61.tar.bz2
Racket: remote REPLs
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am2
-rw-r--r--bin/Makefile.am15
-rwxr-xr-xbin/geiser-racket.sh19
-rw-r--r--configure.ac1
-rw-r--r--doc/repl.texi60
-rw-r--r--elisp/geiser-connection.el57
-rw-r--r--elisp/geiser-racket.el12
-rw-r--r--scheme/racket/geiser/server.rkt24
9 files changed, 138 insertions, 53 deletions
diff --git a/.gitignore b/.gitignore
index 15ac980..444b523 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@
/doc/geiser.info
/doc/texinfo.tex
/autom4te.cache/
+/bin/Makefile.in
diff --git a/Makefile.am b/Makefile.am
index 0ef180e..4f5a16b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . elisp scheme doc
+SUBDIRS = . elisp scheme bin doc
EXTRA_DIST = THANKS
diff --git a/bin/Makefile.am b/bin/Makefile.am
new file mode 100644
index 0000000..9f6ee2b
--- /dev/null
+++ b/bin/Makefile.am
@@ -0,0 +1,15 @@
+EXTRA_DIST = geiser-racket.sh
+dist_bin_SCRIPTS = geiser-racket
+noinst_SCRIPTS = geiser-racket-noinst
+
+CLEANFILES = $(dist_bin_SCRIPTS) $(noinst_SCRIPTS)
+
+geiser-racket: $(srcdir)/geiser-racket.sh
+ @sed -e "s|top=\".*\"|top=$(datarootdir)/geiser|" \
+ $(srcdir)/geiser-racket.sh >$@
+ @chmod +x $@
+
+geiser-racket-noinst: $(srcdir)/geiser-racket.sh
+ @sed -e "s|top=\".*\"|top=$(abs_top_srcdir)/scheme|" \
+ $(srcdir)/geiser-racket.sh >$@
+ @chmod +x $@
diff --git a/bin/geiser-racket.sh b/bin/geiser-racket.sh
new file mode 100755
index 0000000..4f16383
--- /dev/null
+++ b/bin/geiser-racket.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#|
+top="$(dirname $0)/../scheme"
+exec racket -i -S "$top/racket" -l errortrace -cu "$0" ${1+"$@"}
+|#
+
+#lang racket/base
+
+(require (lib "cmdline.rkt"))
+
+(define port (make-parameter 1969))
+
+(command-line
+ "run-racket.sh" (current-command-line-arguments)
+ (once-each
+ (("-p" "--port") p "Geiser server port" (port (string->number p)))))
+
+(and ((dynamic-require 'geiser/server 'start-geiser) (port))
+ (printf "Geiser server running at port ~a~%" (port)))
diff --git a/configure.ac b/configure.ac
index 1a70214..ddeec3f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,6 +25,7 @@ elisp/Makefile
elisp/geiser-version.el
elisp/geiser-load.el
scheme/Makefile
+bin/Makefile
doc/Makefile
])
diff --git a/doc/repl.texi b/doc/repl.texi
index e707e61..03fb42a 100644
--- a/doc/repl.texi
+++ b/doc/repl.texi
@@ -45,27 +45,49 @@ evaluation when they're complete, and will indent new lines properly
until then. It will also keep track of your input, maintaining a history
file that will be reloaded whenever you restart the REPL.
+@subsubheading Connecting to an external Scheme
@cindex remote REPL
@cindex connect to server
-If you use Guile, there's an alternative way of starting a Geiser REPL:
-you can connect to a remote Guile process, provided the latter is
-running a REPL server. For that to happen, you just need to start your
-Guile process (outside Emacs) passing to it the flag @code{--listen}.
-Then, come back to Emacs and execute @kbd{M-x connect-to-guile}. You'll
-be asked for a host and a port, with suitable default values (Guile's
-@code{--listen} flag accepts an optional port as argument (as in
-@code{--listen=1969}), if you don't want to use the default). And voila,
-you'll have a Geiser REPL that is served by the remote Guile process in
-a dedicated thread, meaning that your Guile can go on doing whatever it
-was doing while you tinker with it from Emacs. Note, however,
-that all Guile threads share the heap, so that you'll be able to
-interact with those other threads in the running scheme from Emacs in a
-variety of ways. For starters, all you (re)defintions will be visible
-everywhere. That's dangerous, but will come in handy when you need to
-debug your running webserver.
-
-Nothing that fanciful this far, but there's more to Geiser's REPL. On
-to the next section!
+There's an alternative way of starting a Geiser REPL: you can connect to
+an external Scheme process, provided it's running a REPL server at some
+known port. How to make that happen depends on the Scheme implementation.
+
+@cindex Guile's REPL server
+If you use Guile, you just need to start your Guile process (possibly
+outside Emacs) passing to it the flag @code{--listen}. This flag accepts
+an optional port as argument (as in @code{--listen=1969}), if you don't
+want to use the default.
+
+@cindex Racket's REPL server
+In Racket, you have to use the REPL server that comes with Geiser. To
+that end, put Geiser's Racket scheme directory in the Racket's
+collection search path and invoke @code{start-geiser} (a procedure in
+the module @code{geiser/server}) somewhere in your program, passing it
+the desired port. This procedure will start the REPL server in a
+separate thread. For an example of how to do that, see the script
+@file{bin/geiser-racket.sh} in the source distribution, or, if you've
+compiled Geiser, @file{bin/geiser-racket-noinst} in the build directory,
+or, if you've installed Geiser, @file{geiser-racket} in
+@file{<installation-prefix>/bin}. These scripts start a new interactive
+Racket that is also running a REPL server (they also load the errortrace
+library to provide better diagnostics, but that's not strictly needed).
+
+With your external Scheme process running and serving, come back to
+Emacs and execute @kbd{M-x geiser-connect}, @kbd{M-x connect-to-guile}
+or @kbd{M-x connect-to-racket}. You'll be asked for a host and a port,
+and, voila, you'll have a Geiser REPL that is served by the remote
+Scheme process in a dedicated thread, meaning that your external program
+can go on doing whatever it was doing while you tinker with it from
+Emacs. Note, however, that all Scheme threads share the heap, so that
+you'll be able to interact with those other threads in the running
+scheme from Emacs in a variety of ways. For starters, all your
+(re)defintions will be visible everywhere. That's dangerous, but will
+come in handy when you need to debug your running webserver.
+
+@cindex remote connections
+The connection between Emacs and the Scheme process goes over TCP, so it
+can be as remote as you need, perhaps with the intervention of an SSH
+tunnel.
@node First aids, Switching context, Starting the REPL, The REPL
@section First aids
diff --git a/elisp/geiser-connection.el b/elisp/geiser-connection.el
index f146563..dc669aa 100644
--- a/elisp/geiser-connection.el
+++ b/elisp/geiser-connection.el
@@ -159,15 +159,17 @@ By default, Geiser uses the prompt regexp.")
(make-variable-buffer-local
(defvar geiser-con--debugging-preamble-regexp nil))
-(defun geiser-con--is-debugging ()
- (and geiser-con--debugging-prompt-regexp
- geiser-con--debugging-inhibits-eval
- comint-last-prompt-overlay
- (string-match-p geiser-con--debugging-prompt-regexp
- (buffer-substring (overlay-start
- comint-last-prompt-overlay)
- (overlay-end
- comint-last-prompt-overlay)))))
+(defun geiser-con--is-debugging (&optional con)
+ (with-current-buffer (or (and con (geiser-con--connection-buffer con))
+ (current-buffer))
+ (and geiser-con--debugging-prompt-regexp
+ geiser-con--debugging-inhibits-eval
+ comint-last-prompt-overlay
+ (string-match-p geiser-con--debugging-prompt-regexp
+ (buffer-substring (overlay-start
+ comint-last-prompt-overlay)
+ (overlay-end
+ comint-last-prompt-overlay))))))
(defsubst geiser-con--has-entered-debugger (con)
(with-current-buffer (geiser-con--connection-buffer con)
@@ -278,35 +280,24 @@ By default, Geiser uses the prompt regexp.")
(defvar geiser-connection-timeout 30000
"Time limit, in msecs, blocking on synchronous evaluation requests")
-(defun geiser-con--send-string/wait (buffer/proc str cont
- &optional timeout sbuf)
+(defun geiser-con--send-string/wait (b/p str cont &optional timeout sbuf)
(save-current-buffer
- (let* ((con (geiser-con--get-connection buffer/proc))
+ (let* ((con (geiser-con--get-connection b/p))
(proc (and con (geiser-con--connection-process con))))
- (unless proc
- (error geiser-con--error-message))
- (with-current-buffer (geiser-con--connection-buffer con)
- (when (geiser-con--is-debugging)
- (error "Geiser REPL is in debug mode")))
+ (unless proc (error geiser-con--error-message))
+ (when (geiser-con--is-debugging con) (error "REPL is in debug mode"))
(let* ((req (geiser-con--make-request con str cont sbuf))
- (id (and req (geiser-con--request-id req)))
- (time (or timeout geiser-connection-timeout))
- (step 100)
- (waitsecs (/ step 1000.0)))
- (when id
- (geiser-con--connection-add-request con req)
- (geiser-con--process-next con)
+ (id (geiser-con--request-id req))
+ (timeout (/ (or timeout geiser-connection-timeout) 1000.0))
+ (waitsecs 0.1))
+ (geiser-con--connection-add-request con req)
+ (with-timeout (timeout (geiser-con--request-deactivate req))
(condition-case nil
- (while (and (> time 0)
- (geiser-con--connection-process con)
+ (while (and (geiser-con--connection-process con)
(not (geiser-con--connection-completed-p con id)))
- (unless (accept-process-output nil waitsecs nil nil)
- (geiser-con--process-next con)
- (setq time (- time step))))
- (error (setq time 0)))
- (or (> time 0)
- (geiser-con--request-deactivate req)
- nil))))))
+ (geiser-con--process-next con)
+ (accept-process-output proc waitsecs nil t))
+ (error (geiser-con--request-deactivate req))))))))
(provide 'geiser-connection)
diff --git a/elisp/geiser-racket.el b/elisp/geiser-racket.el
index 18ed2eb..8c66e67 100644
--- a/elisp/geiser-racket.el
+++ b/elisp/geiser-racket.el
@@ -223,6 +223,18 @@ This function uses `geiser-racket-init-file' if it exists."
(geiser-racket--explicit-module)))
+;;; Remote REPLs
+
+(defun connect-to-racket ()
+ "Start a Racket REPL connected to a remote process.
+
+The remote process needs to be running a REPL server started
+using start-geiser, a procedure in the geiser/server module."
+ (interactive)
+ (geiser-connect 'racket))
+
+
+
;;; Implementation definition:
(define-geiser-implementation racket
diff --git a/scheme/racket/geiser/server.rkt b/scheme/racket/geiser/server.rkt
new file mode 100644
index 0000000..cf86b2c
--- /dev/null
+++ b/scheme/racket/geiser/server.rkt
@@ -0,0 +1,24 @@
+;;; server.rkt -- REPL server
+
+;; Copyright (c) 2010 Jose Antonio Ortega Ruiz
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the Modified BSD License. You should
+;; have received a copy of the license along with this program. If
+;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>.
+
+;; Start date: Sat Nov 06, 2010 15:15
+
+#lang racket/base
+
+(require geiser/user mzlib/thread)
+(provide run-geiser-server start-geiser)
+
+(define (run-geiser-server port enforce-module-constants)
+ (run-server port
+ (lambda (in out)
+ (run-geiser-repl in out enforce-module-constants))
+ #f))
+
+(define (start-geiser (port 1969) (enforce-module-constants #f))
+ (thread (lambda () (run-geiser-server port enforce-module-constants))))