123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- ;;;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 2.1 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;;;
- ;;;; The author can be reached at djurfeldt@nada.kth.se
- ;;;; Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
- ;;;; (I didn't write this!)
- ;;;;
- ;;; *********************************************************************
- ;;; * This is the Guile side of the Emacs interface *
- ;;; * Experimental hACK---the real version will be coming soon (almost) *
- ;;; *********************************************************************
- ;;; {Session support for Emacs}
- ;;;
- (define-module (ice-9 emacs)
- :use-module (ice-9 debug)
- :use-module (ice-9 threads)
- :use-module (ice-9 session)
- :no-backtrace)
- (define emacs-escape-character #\sub)
- (define emacs-output-port (current-output-port))
- (define (make-emacs-command char)
- (let ((cmd (list->string (list emacs-escape-character char))))
- (lambda ()
- (display cmd emacs-output-port))))
- (define enter-input-wait (make-emacs-command #\s))
- (define exit-input-wait (make-emacs-command #\f))
- (define enter-read-character #\r)
- (define sending-error (make-emacs-command #\F))
- (define sending-backtrace (make-emacs-command #\B))
- (define sending-result (make-emacs-command #\x))
- (define end-of-text (make-emacs-command #\.))
- (define no-stack (make-emacs-command #\S))
- (define no-source (make-emacs-command #\R))
- ;; {Error handling}
- ;;
- (add-hook! before-backtrace-hook sending-backtrace)
- (add-hook! after-backtrace-hook end-of-text)
- (add-hook! before-error-hook sending-error)
- (add-hook! after-error-hook end-of-text)
- ;; {Repl}
- ;;
- (set-current-error-port emacs-output-port)
- (add-hook! before-read-hook
- (lambda ()
- (enter-input-wait)
- (force-output emacs-output-port)))
- (add-hook! after-read-hook
- (lambda ()
- (exit-input-wait)
- (force-output emacs-output-port)))
- ;;; {Misc.}
- (define (make-emacs-load-port orig-port)
- (letrec ((read-char-fn (lambda args
- (let ((c (read-char orig-port)))
- (if (eq? c #\soh)
- (throw 'end-of-chunk)
- c)))))
-
- (make-soft-port
- (vector #f #f #f
- read-char-fn
- (lambda () (close-port orig-port)))
- "r")))
- (set-current-input-port (make-emacs-load-port (current-input-port)))
- (define (result-to-emacs exp)
- (sending-result)
- (write exp emacs-output-port)
- (end-of-text)
- (force-output emacs-output-port))
- (define load-acknowledge (make-emacs-command #\l))
- (define load-port (current-input-port))
- (define (flush-line port)
- (let loop ((c (read-char port)))
- (if (not (eq? c #\nl))
- (loop (read-char port)))))
- (define whitespace-chars (list #\space #\tab #\nl #\np))
- (define (flush-whitespace port)
- (catch 'end-of-chunk
- (lambda ()
- (let loop ((c (read-char port)))
- (cond ((eq? c the-eof-object)
- (error "End of file while receiving Emacs data"))
- ((memq c whitespace-chars) (loop (read-char port)))
- ((eq? c #\;) (flush-line port) (loop (read-char port)))
- (else (unread-char c port))))
- #f)
- (lambda args
- (read-char port) ; Read final newline
- #t)))
- (define (emacs-load filename linum colnum module interactivep)
- (define (read-and-eval! port)
- (let ((x (read port)))
- (if (eof-object? x)
- (throw 'end-of-file)
- (primitive-eval x))))
- (set-port-filename! %%load-port filename)
- (set-port-line! %%load-port linum)
- (set-port-column! %%load-port colnum)
- (lazy-catch #t
- (lambda ()
- (let loop ((endp (flush-whitespace %%load-port)))
- (if (not endp)
- (begin
- (save-module-excursion
- (lambda ()
- (if module
- (set-current-module (resolve-module module #f)))
- (let ((result
- (start-stack read-and-eval!
- (read-and-eval! %%load-port))))
- (if interactivep
- (result-to-emacs result)))))
- (loop (flush-whitespace %%load-port)))
- (begin
- (load-acknowledge)))
- (set-port-filename! %%load-port #f))) ;reset port filename
- (lambda (key . args)
- (set-port-filename! %%load-port #f)
- (cond ((eq? key 'end-of-chunk)
- (fluid-set! the-last-stack #f)
- (set! stack-saved? #t)
- (scm-error 'misc-error
- #f
- "Incomplete expression"
- '()
- '()))
- ((eq? key 'exit))
- (else
- (save-stack 2)
- (catch 'end-of-chunk
- (lambda ()
- (let loop ()
- (read-char %%load-port)
- (loop)))
- (lambda args
- #f))
- (apply throw key args))))))
- (define (emacs-eval-request form)
- (result-to-emacs (eval form (interaction-environment))))
- ;;*fixme* Not necessary to use flags no-stack and no-source
- (define (get-frame-source frame)
- (if (or (not (fluid-ref the-last-stack))
- (>= frame (stack-length (fluid-ref the-last-stack))))
- (begin
- (no-stack)
- #f)
- (let* ((frame (stack-ref (fluid-ref the-last-stack)
- (frame-number->index frame)))
- (source (frame-source frame)))
- (or source
- (begin (no-source)
- #f)))))
- (define (emacs-select-frame frame)
- (let ((source (get-frame-source frame)))
- (if source
- (let ((fname (source-property source 'filename))
- (line (source-property source 'line))
- (column (source-property source 'column)))
- (if (and fname line column)
- (list fname line column)
- (begin (no-source)
- '())))
- '())))
- (define (object->string x . method)
- (with-output-to-string
- (lambda ()
- ((if (null? method)
- write
- (car method))
- x))))
- (define (format template . rest)
- (let loop ((chars (string->list template))
- (result '())
- (rest rest))
- (cond ((null? chars) (list->string (reverse result)))
- ((char=? (car chars) #\%)
- (loop (cddr chars)
- (append (reverse
- (string->list
- (case (cadr chars)
- ((#\S) (object->string (car rest)))
- ((#\s) (object->string (car rest) display)))))
- result)
- (cdr rest)))
- (else (loop (cdr chars) (cons (car chars) result) rest)))))
- (define (error-args->string args)
- (let ((msg (apply format (caddr args) (cadddr args))))
- (if (symbol? (cadr args))
- (string-append (symbol->string (cadr args))
- ": "
- msg)
- msg)))
- (define (emacs-frame-eval frame form)
- (let ((source (get-frame-source frame)))
- (if source
- (catch #t
- (lambda ()
- (list 'result
- (object->string
- (local-eval (with-input-from-string form read)
- (memoized-environment source)))))
- (lambda args
- (list (car args)
- (error-args->string args))))
- (begin
- (no-source)
- '()))))
- (define (emacs-symdoc symbol)
- (if (or (not (module-bound? (current-module) symbol))
- (not (procedure? (eval symbol (interaction-environment)))))
- 'nil
- (procedure-documentation (eval symbol (interaction-environment)))))
- ;;; A fix to get the emacs interface to work together with the module system.
- ;;;
- (for-each (lambda (name value)
- (module-define! the-root-module name value))
- '(%%load-port
- %%emacs-load
- %%emacs-eval-request
- %%emacs-select-frame
- %%emacs-frame-eval
- %%emacs-symdoc
- %%apropos-internal)
- (list load-port
- emacs-load
- emacs-eval-request
- emacs-select-frame
- emacs-frame-eval
- emacs-symdoc
- apropos-internal))
|