[slime-cvs] CVS slime/contrib
heller
heller at common-lisp.net
Sun Mar 2 22:41:45 UTC 2008
Update of /project/slime/cvsroot/slime/contrib
In directory clnet:/tmp/cvs-serv759
Modified Files:
ChangeLog
Added Files:
swank-mit-scheme.scm
Log Message:
* swank-mit-scheme.scm: New file.
--- /project/slime/cvsroot/slime/contrib/ChangeLog 2008/03/02 15:21:52 1.95
+++ /project/slime/cvsroot/slime/contrib/ChangeLog 2008/03/02 22:41:45 1.96
@@ -13,6 +13,10 @@
(slime-presentation-easy-menu): New entry "Find Definition".
(slime-presentations-init): Hook into `slime-edit-definition-hooks'.
+2008-03-02 Helmut Eller <heller at common-lisp.net>
+
+ * swank-mit-scheme.scm: New file.
+
2008-02-21 Tobias C. Rittweiler <tcr at freebits.de>
Having the `slime-presentations' contrib enabled, (princ 10)
--- /project/slime/cvsroot/slime/contrib/swank-mit-scheme.scm 2008/03/02 22:41:45 NONE
+++ /project/slime/cvsroot/slime/contrib/swank-mit-scheme.scm 2008/03/02 22:41:45 1.1
;;; swank-mit-scheme.scm --- SLIME server for MIT Scheme
;;
;; Copyright (C) 2008 Helmut Eller
;;
;; This file is licensed under the terms of the GNU General Public
;; License as distributed with Emacs (press C-h C-c for details).
;;;; Installation:
#|
1. You need MIT Scheme (version 7.7.0 and 7.7.90 seem to work).
2. You also need the `netcat' program to create sockets. MIT Scheme
has some socket functions built-in, but I couldn't figure out how
to access the locat port number of a server socket. We shell out
to netcat to get us started.
3. The Emacs side needs a bit configuration. I have the following in
my .emacs:
(setq slime-lisp-implementations
'((mit-scheme ("mit-scheme") :init mit-scheme-init)))
(defun mit-scheme-init (file encoding)
(format "%S\n\n"
`(begin
(load-option 'format)
(load-option 'sos)
(eval
'(construct-normal-package-from-description
(make-package-description '(swank) '(())
(vector) (vector) (vector) false))
(->environment '(package)))
(load ,(expand-file-name
".../contrib/swank-mit-scheme.scm" ; <-- insert your path
slime-path)
(->environment '(swank)))
(eval '(start-swank ,file) (->environment '(swank))))))
(defun mit-scheme ()
(interactive)
(slime 'mit-scheme))
(defun find-mit-scheme-package ()
(save-excursion
(let ((case-fold-search t))
(and (re-search-backward "^[;]+ package: \\((.+)\\).*$" nil t)
(match-string-no-properties 1)))))
(setq slime-find-buffer-package-function 'find-mit-scheme-package)
The `mit-scheme-init' function first loads the SOS and FORMAT
libraries, then creates a package "(swank)", and loads this file
into that package. Finally it starts the server.
`find-mit-scheme-package' tries to figure out which package the
buffer belongs to, assuming that ";;; package: (FOO)" appears
somewhere in the file. Luckily, this assumption is true for many of
MIT Scheme's own files. Alternatively, you could add Emacs style
-*- slime-buffer-package: "(FOO)" -*- file variables.
4. Start everything with `M-x mit-scheme'.
|#
;;; package: (swank)
(define (swank port)
(accept-connections (or port 4005) #f))
(define (start-swank port-file)
(accept-connections #f port-file))
;;;; Networking
(define (accept-connections port port-file)
(let ((nc (netcat port)))
(format #t "Listening on port: ~s~%" (cadr nc))
(if port-file (write-port-file (cadr nc) port-file))
(dynamic-wind
(lambda () #f)
(lambda () (serve (netcat-accept (car nc))))
(lambda () (close-port (subprocess-input-port (car nc)))))))
(define (netcat port)
(let* ((sh (os/shell-file-name))
(cmd (format #f "exec netcat -s localhost -q 0 -l -v ~a 2>&1"
(if port (format #f "-p ~a" port) "")))
(netcat (start-pipe-subprocess sh
(vector sh "-c" cmd)
scheme-subprocess-environment))
(line (read-line (subprocess-input-port netcat)))
(match (re-string-match "^listening on \\[[^]]+\\] \\([0-9]+\\) ...$"
line)))
(cond ((not match)
(close-port (subprocess-input-port netcat))
(error "netcat:" line))
(else (list netcat
(string->number (re-match-extract line match 1)))))))
(define (netcat-accept nc)
(let* ((rx "^connect to \\[[^]]+\\] from [^ ]+ \\[[^]]+\\] \\([0-9]+\\)$")
(line (read-line (subprocess-input-port nc)))
(match (re-string-match rx line)))
(cond ((not match) (error "netcat:" line))
(else (subprocess-input-port nc)))))
(define (write-port-file portnumber filename)
(call-with-output-file filename (lambda (p) (write portnumber p))))
(define *top-level-restart* #f)
(define (serve socket)
(with-simple-restart
'disconnect "Close connection."
(lambda ()
(with-keyboard-interrupt-handler
(lambda () (main-loop socket))))))
(define (disconnect)
(format #t "Disconnecting ...~%")
(invoke-restart (find-restart 'disconnect)))
(define (main-loop socket)
(do () (#f)
(with-simple-restart
'abort "Return to SLIME top-level."
(lambda ()
(fluid-let ((*top-level-restart* (find-restart 'abort)))
(dispatch (read-packet socket) socket 0))))))
(define (with-keyboard-interrupt-handler fun)
(define (set-^G-handler exp)
(eval `(vector-set! keyboard-interrupt-vector (char->ascii #\G) ,exp)
(->environment '(runtime interrupt-handler))))
(dynamic-wind
(lambda () #f)
(lambda ()
(set-^G-handler
`(lambda (char) (with-simple-restart
'continue "Continue from interrupt."
(lambda () (error "Keyboard Interrupt.")))))
(fun))
(lambda ()
(set-^G-handler '^G-interrupt-handler))))
;;;; Reading/Writing of SLIME packets
(define (read-packet in)
"Read an S-expression from STREAM using the SLIME protocol."
(let* ((len (read-length in))
(buffer (make-string len)))
(fill-buffer! in buffer)
(read-from-string buffer)))
(define (write-packet message out)
(let* ((string (write-to-string message)))
(log-event "WRITE: [~a]~s~%" (string-length string) string)
(write-length (string-length string) out)
(write-string string out)
(flush-output out)))
(define (fill-buffer! in buffer)
(read-string! buffer in))
(define (read-length in)
(if (eof-object? (peek-char in)) (disconnect))
(do ((len 6 (1- len))
(sum 0 (+ (* sum 16) (char->hex-digit (read-char in)))))
((zero? len) sum)))
(define (ldb size position integer)
"LoaD a Byte of SIZE bits at bit position POSITION from INTEGER."
(fix:and (fix:lsh integer (- position))
(1- (fix:lsh 1 size))))
(define (write-length len out)
(do ((pos 20 (- pos 4)))
((< pos 0))
(write-hex-digit (ldb 4 pos len) out)))
(define (write-hex-digit n out)
(write-char (hex-digit->char n) out))
(define (hex-digit->char n)
(digit->char n 16))
(define (char->hex-digit c)
(char->digit c 16))
;;;; Event dispatching
(define (dispatch request socket level)
(log-event "READ: ~s~%" request)
(case (car request)
((:emacs-rex) (apply emacs-rex socket level (cdr request)))))
(define (swank-package)
(or (name->package '(swank))
(name->package '(user))))
(define *buffer-package* #f)
(define (find-buffer-package name)
(if (elisp-false? name)
#f
(let ((v (ignore-errors
(lambda () (name->package (read-from-string name))))))
(and (package? v) v))))
(define swank-env (->environment (swank-package)))
(define (user-env buffer-package)
(cond ((string? buffer-package)
(let ((p (find-buffer-package buffer-package)))
(if (not p) (error "Invalid package name: " buffer-package))
(package/environment p)))
(else (nearest-repl/environment))))
(define (emacs-rex socket level sexp package thread id)
(let ((ok? #f) (result #f))
(dynamic-wind
(lambda () #f)
(lambda ()
(bind-condition-handler
(list condition-type:serious-condition)
(lambda (c) (invoke-sldb socket (1+ level) c))
(lambda ()
(fluid-let ((*buffer-package* package))
(set! result
(eval (cons* (car sexp) socket (cdr sexp))
swank-env))
(set! ok? #t)))))
(lambda ()
(write-packet `(:return ,(if ok? `(:ok ,result) '(:abort))
,id)
socket)))))
(define (swank:connection-info _)
(let ((p (environment->package (user-env #f))))
`(:pid ,(unix/current-pid)
:package (:name ,(write-to-string (package/name p))
:prompt ,(write-to-string (package/name p)))
:lisp-implementation
(:type "MIT Scheme" :version ,(get-subsystem-version-string "release"))
)))
(define (swank:quit-lisp _)
(%exit))
;;;; Evaluation
(define (swank:listener-eval socket string)
;;(call-with-values (lambda () (eval-region string socket))
;; (lambda values `(:values . ,(map write-to-string values))))
`(:values ,(write-to-string (eval-region string socket))))
(define (eval-region string socket)
(let ((sexp (read-from-string string)))
(if (eof-object? exp)
(values)
(with-output-to-repl socket
(lambda () (eval sexp (user-env *buffer-package*)))))))
(define (with-output-to-repl socket fun)
(let ((p (make-port repl-port-type socket)))
(dynamic-wind
(lambda () #f)
(lambda () (with-output-to-port p fun))
(lambda () (flush-output p)))))
(define (swank:interactive-eval socket string)
;;(call-with-values (lambda () (eval-region string)) format-for-echo-area)
(format-values (eval-region string socket))
)
(define (format-values . values)
(if (null? values)
"; No value"
(with-string-output-port
(lambda (out)
(write-string "=> " out)
(do ((vs values (cdr vs))) ((null? vs))
(write (car vs) out)
(if (not (null? (cdr vs)))
(write-string ", " out)))))))
(define (swank:pprint-eval _ string)
(pprint-to-string (eval (read-from-string string)
(user-env *buffer-package*))))
(define (swank:interactive-eval-region socket string)
(format-values (eval-region string socket)))
(define (swank:set-package _ package)
(set-repl/environment! (nearest-repl)
(->environment (read-from-string package)))
(let* ((p (environment->package (user-env #f)))
(n (write-to-string (package/name p))))
(list n n)))
(define (repl-write-substring port string start end)
(cond ((< start end)
(write-packet `(:write-string ,(substring string start end))
(port/state port))))
(- end start))
(define (repl-write-char port char)
(write-packet `(:write-string ,(string char))
(port/state port)))
(define repl-port-type
(make-port-type `((write-substring ,repl-write-substring)
(write-char ,repl-write-char)) #f))
;;;; Compilation
(define (swank:compile-string-for-emacs _ string . x)
(call-compiler
(lambda ()
(let* ((sexps (snarf-string string))
(env (user-env *buffer-package*))
(scode (syntax `(begin , at sexps) env))
(compiled-expression (compile-scode scode #t)))
(scode-eval compiled-expression env)))))
(define (snarf-string string)
(with-input-from-string string
(lambda ()
(let loop ()
(let ((e (read)))
(if (eof-object? e) '() (cons e (loop))))))))
(define (call-compiler fun)
(let ((time #f))
(with-timings fun
(lambda (run-time gc-time real-time)
(set! time real-time)))
(list 'nil (format #f "~a" (internal-time/ticks->seconds time)))))
(define (swank:compiler-notes-for-emacs _) nil)
(define (swank:compile-file-for-emacs socket file load?)
(call-compiler
(lambda ()
(with-output-to-repl socket
(lambda () (compile-file file)))
(cond ((elisp-true? load?)
(load (pathname-new-type file "com")
(user-env *buffer-package*)))))))
(define (swank:load-file socket file)
(with-output-to-repl socket
(lambda () (load file (user-env *buffer-package*)))))
(define (swank:disassemble-symbol _ string)
(with-output-to-string
(lambda ()
(compiler:disassemble
(eval (read-from-string string)
(user-env *buffer-package*))))))
;;; Arglist
(define (swank:operator-arglist socket name pack)
(let ((v (ignore-errors
(lambda ()
(with-output-to-string
(lambda ()
(carefully-pa
(eval (read-from-string name) (user-env pack)))))))))
(if (condition? v) 'nil v)))
(define (carefully-pa o)
(cond ((arity-dispatched-procedure? o)
;; MIT Scheme crashes for (pa /)
(display "arity-dispatched-procedure"))
((procedure? o) (pa o))
(else (error "Not a procedure"))))
;;; Some unimplemented stuff.
(define (swank:buffer-first-change . _) nil)
(define (swank:frame-catch-tags-for-emacs . _) nil)
[457 lines skipped]
More information about the slime-cvs
mailing list