emacs.scm 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. ;;;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2006 Free Software Foundation, Inc.
  2. ;;;;
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 2.1 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;;;
  17. ;;;; The author can be reached at djurfeldt@nada.kth.se
  18. ;;;; Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN
  19. ;;;; (I didn't write this!)
  20. ;;;;
  21. ;;; *********************************************************************
  22. ;;; * This is the Guile side of the Emacs interface *
  23. ;;; * Experimental hACK---the real version will be coming soon (almost) *
  24. ;;; *********************************************************************
  25. ;;; {Session support for Emacs}
  26. ;;;
  27. (define-module (ice-9 emacs)
  28. :use-module (ice-9 debug)
  29. :use-module (ice-9 threads)
  30. :use-module (ice-9 session)
  31. :no-backtrace)
  32. (define emacs-escape-character #\sub)
  33. (define emacs-output-port (current-output-port))
  34. (define (make-emacs-command char)
  35. (let ((cmd (list->string (list emacs-escape-character char))))
  36. (lambda ()
  37. (display cmd emacs-output-port))))
  38. (define enter-input-wait (make-emacs-command #\s))
  39. (define exit-input-wait (make-emacs-command #\f))
  40. (define enter-read-character #\r)
  41. (define sending-error (make-emacs-command #\F))
  42. (define sending-backtrace (make-emacs-command #\B))
  43. (define sending-result (make-emacs-command #\x))
  44. (define end-of-text (make-emacs-command #\.))
  45. (define no-stack (make-emacs-command #\S))
  46. (define no-source (make-emacs-command #\R))
  47. ;; {Error handling}
  48. ;;
  49. (add-hook! before-backtrace-hook sending-backtrace)
  50. (add-hook! after-backtrace-hook end-of-text)
  51. (add-hook! before-error-hook sending-error)
  52. (add-hook! after-error-hook end-of-text)
  53. ;; {Repl}
  54. ;;
  55. (set-current-error-port emacs-output-port)
  56. (add-hook! before-read-hook
  57. (lambda ()
  58. (enter-input-wait)
  59. (force-output emacs-output-port)))
  60. (add-hook! after-read-hook
  61. (lambda ()
  62. (exit-input-wait)
  63. (force-output emacs-output-port)))
  64. ;;; {Misc.}
  65. (define (make-emacs-load-port orig-port)
  66. (letrec ((read-char-fn (lambda args
  67. (let ((c (read-char orig-port)))
  68. (if (eq? c #\soh)
  69. (throw 'end-of-chunk)
  70. c)))))
  71. (make-soft-port
  72. (vector #f #f #f
  73. read-char-fn
  74. (lambda () (close-port orig-port)))
  75. "r")))
  76. (set-current-input-port (make-emacs-load-port (current-input-port)))
  77. (define (result-to-emacs exp)
  78. (sending-result)
  79. (write exp emacs-output-port)
  80. (end-of-text)
  81. (force-output emacs-output-port))
  82. (define load-acknowledge (make-emacs-command #\l))
  83. (define load-port (current-input-port))
  84. (define (flush-line port)
  85. (let loop ((c (read-char port)))
  86. (if (not (eq? c #\nl))
  87. (loop (read-char port)))))
  88. (define whitespace-chars (list #\space #\tab #\nl #\np))
  89. (define (flush-whitespace port)
  90. (catch 'end-of-chunk
  91. (lambda ()
  92. (let loop ((c (read-char port)))
  93. (cond ((eq? c the-eof-object)
  94. (error "End of file while receiving Emacs data"))
  95. ((memq c whitespace-chars) (loop (read-char port)))
  96. ((eq? c #\;) (flush-line port) (loop (read-char port)))
  97. (else (unread-char c port))))
  98. #f)
  99. (lambda args
  100. (read-char port) ; Read final newline
  101. #t)))
  102. (define (emacs-load filename linum colnum module interactivep)
  103. (define (read-and-eval! port)
  104. (let ((x (read port)))
  105. (if (eof-object? x)
  106. (throw 'end-of-file)
  107. (primitive-eval x))))
  108. (set-port-filename! %%load-port filename)
  109. (set-port-line! %%load-port linum)
  110. (set-port-column! %%load-port colnum)
  111. (lazy-catch #t
  112. (lambda ()
  113. (let loop ((endp (flush-whitespace %%load-port)))
  114. (if (not endp)
  115. (begin
  116. (save-module-excursion
  117. (lambda ()
  118. (if module
  119. (set-current-module (resolve-module module #f)))
  120. (let ((result
  121. (start-stack read-and-eval!
  122. (read-and-eval! %%load-port))))
  123. (if interactivep
  124. (result-to-emacs result)))))
  125. (loop (flush-whitespace %%load-port)))
  126. (begin
  127. (load-acknowledge)))
  128. (set-port-filename! %%load-port #f))) ;reset port filename
  129. (lambda (key . args)
  130. (set-port-filename! %%load-port #f)
  131. (cond ((eq? key 'end-of-chunk)
  132. (fluid-set! the-last-stack #f)
  133. (set! stack-saved? #t)
  134. (scm-error 'misc-error
  135. #f
  136. "Incomplete expression"
  137. '()
  138. '()))
  139. ((eq? key 'exit))
  140. (else
  141. (save-stack 2)
  142. (catch 'end-of-chunk
  143. (lambda ()
  144. (let loop ()
  145. (read-char %%load-port)
  146. (loop)))
  147. (lambda args
  148. #f))
  149. (apply throw key args))))))
  150. (define (emacs-eval-request form)
  151. (result-to-emacs (eval form (interaction-environment))))
  152. ;;*fixme* Not necessary to use flags no-stack and no-source
  153. (define (get-frame-source frame)
  154. (if (or (not (fluid-ref the-last-stack))
  155. (>= frame (stack-length (fluid-ref the-last-stack))))
  156. (begin
  157. (no-stack)
  158. #f)
  159. (let* ((frame (stack-ref (fluid-ref the-last-stack)
  160. (frame-number->index frame)))
  161. (source (frame-source frame)))
  162. (or source
  163. (begin (no-source)
  164. #f)))))
  165. (define (emacs-select-frame frame)
  166. (let ((source (get-frame-source frame)))
  167. (if source
  168. (let ((fname (source-property source 'filename))
  169. (line (source-property source 'line))
  170. (column (source-property source 'column)))
  171. (if (and fname line column)
  172. (list fname line column)
  173. (begin (no-source)
  174. '())))
  175. '())))
  176. (define (object->string x . method)
  177. (with-output-to-string
  178. (lambda ()
  179. ((if (null? method)
  180. write
  181. (car method))
  182. x))))
  183. (define (format template . rest)
  184. (let loop ((chars (string->list template))
  185. (result '())
  186. (rest rest))
  187. (cond ((null? chars) (list->string (reverse result)))
  188. ((char=? (car chars) #\%)
  189. (loop (cddr chars)
  190. (append (reverse
  191. (string->list
  192. (case (cadr chars)
  193. ((#\S) (object->string (car rest)))
  194. ((#\s) (object->string (car rest) display)))))
  195. result)
  196. (cdr rest)))
  197. (else (loop (cdr chars) (cons (car chars) result) rest)))))
  198. (define (error-args->string args)
  199. (let ((msg (apply format (caddr args) (cadddr args))))
  200. (if (symbol? (cadr args))
  201. (string-append (symbol->string (cadr args))
  202. ": "
  203. msg)
  204. msg)))
  205. (define (emacs-frame-eval frame form)
  206. (let ((source (get-frame-source frame)))
  207. (if source
  208. (catch #t
  209. (lambda ()
  210. (list 'result
  211. (object->string
  212. (local-eval (with-input-from-string form read)
  213. (memoized-environment source)))))
  214. (lambda args
  215. (list (car args)
  216. (error-args->string args))))
  217. (begin
  218. (no-source)
  219. '()))))
  220. (define (emacs-symdoc symbol)
  221. (if (or (not (module-bound? (current-module) symbol))
  222. (not (procedure? (eval symbol (interaction-environment)))))
  223. 'nil
  224. (procedure-documentation (eval symbol (interaction-environment)))))
  225. ;;; A fix to get the emacs interface to work together with the module system.
  226. ;;;
  227. (for-each (lambda (name value)
  228. (module-define! the-root-module name value))
  229. '(%%load-port
  230. %%emacs-load
  231. %%emacs-eval-request
  232. %%emacs-select-frame
  233. %%emacs-frame-eval
  234. %%emacs-symdoc
  235. %%apropos-internal)
  236. (list load-port
  237. emacs-load
  238. emacs-eval-request
  239. emacs-select-frame
  240. emacs-frame-eval
  241. emacs-symdoc
  242. apropos-internal))