Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.6 KiB

пре 5 година
  1. ;;; swank-mrepl.lisp
  2. ;;
  3. ;; Licence: public domain
  4. (in-package :swank)
  5. (eval-when (:compile-toplevel :load-toplevel :execute)
  6. (let ((api '(
  7. *emacs-connection*
  8. channel
  9. channel-id
  10. define-channel-method
  11. defslimefun
  12. dcase
  13. log-event
  14. process-requests
  15. send-to-remote-channel
  16. use-threads-p
  17. wait-for-event
  18. with-bindings
  19. with-connection
  20. with-top-level-restart
  21. with-slime-interrupts
  22. )))
  23. (eval `(defpackage #:swank-api
  24. (:use)
  25. (:import-from #:swank . ,api)
  26. (:export . ,api)))))
  27. (defpackage :swank-mrepl
  28. (:use :cl :swank-api)
  29. (:export #:create-mrepl))
  30. (in-package :swank-mrepl)
  31. (defclass listener-channel (channel)
  32. ((remote :initarg :remote)
  33. (env :initarg :env)
  34. (mode :initform :eval)
  35. (tag :initform nil)))
  36. (defun package-prompt (package)
  37. (reduce (lambda (x y) (if (<= (length x) (length y)) x y))
  38. (cons (package-name package) (package-nicknames package))))
  39. (defslimefun create-mrepl (remote)
  40. (let* ((pkg *package*)
  41. (conn *emacs-connection*)
  42. (thread (if (use-threads-p)
  43. (spawn-listener-thread conn)
  44. nil))
  45. (ch (make-instance 'listener-channel :remote remote :thread thread)))
  46. (setf (slot-value ch 'env) (initial-listener-env ch))
  47. (when thread
  48. (swank/backend:send thread `(:serve-channel ,ch)))
  49. (list (channel-id ch)
  50. (swank/backend:thread-id (or thread (swank/backend:current-thread)))
  51. (package-name pkg)
  52. (package-prompt pkg))))
  53. (defun initial-listener-env (listener)
  54. `((*package* . ,*package*)
  55. (*standard-output* . ,(make-listener-output-stream listener))
  56. (*standard-input* . ,(make-listener-input-stream listener))))
  57. (defun spawn-listener-thread (connection)
  58. (swank/backend:spawn
  59. (lambda ()
  60. (with-connection (connection)
  61. (dcase (swank/backend:receive)
  62. ((:serve-channel c)
  63. (loop
  64. (with-top-level-restart (connection (drop-unprocessed-events c))
  65. (process-requests nil)))))))
  66. :name "mrepl thread"))
  67. (defun drop-unprocessed-events (channel)
  68. (with-slots (mode) channel
  69. (let ((old-mode mode))
  70. (setf mode :drop)
  71. (unwind-protect
  72. (process-requests t)
  73. (setf mode old-mode)))
  74. (send-prompt channel)))
  75. (define-channel-method :process ((c listener-channel) string)
  76. (log-event ":process ~s~%" string)
  77. (with-slots (mode remote) c
  78. (ecase mode
  79. (:eval (mrepl-eval c string))
  80. (:read (mrepl-read c string))
  81. (:drop))))
  82. (defun mrepl-eval (channel string)
  83. (with-slots (remote env) channel
  84. (let ((aborted t))
  85. (with-bindings env
  86. (unwind-protect
  87. (let ((result (with-slime-interrupts (read-eval-print string))))
  88. (send-to-remote-channel remote `(:write-result ,result))
  89. (setq aborted nil))
  90. (setf env (loop for (sym) in env
  91. collect (cons sym (symbol-value sym))))
  92. (cond (aborted
  93. (send-to-remote-channel remote `(:evaluation-aborted)))
  94. (t
  95. (send-prompt channel))))))))
  96. (defun send-prompt (channel)
  97. (with-slots (env remote) channel
  98. (let ((pkg (or (cdr (assoc '*package* env)) *package*))
  99. (out (cdr (assoc '*standard-output* env)))
  100. (in (cdr (assoc '*standard-input* env))))
  101. (when out (force-output out))
  102. (when in (clear-input in))
  103. (send-to-remote-channel remote `(:prompt ,(package-name pkg)
  104. ,(package-prompt pkg))))))
  105. (defun mrepl-read (channel string)
  106. (with-slots (tag) channel
  107. (assert tag)
  108. (throw tag string)))
  109. (defun read-eval-print (string)
  110. (with-input-from-string (in string)
  111. (setq / ())
  112. (loop
  113. (let* ((form (read in nil in)))
  114. (cond ((eq form in) (return))
  115. (t (setq / (multiple-value-list (eval (setq + form))))))))
  116. (force-output)
  117. (if /
  118. (format nil "~{~s~%~}" /)
  119. "; No values")))
  120. (defun make-listener-output-stream (channel)
  121. (let ((remote (slot-value channel 'remote)))
  122. (swank/backend:make-output-stream
  123. (lambda (string)
  124. (send-to-remote-channel remote `(:write-string ,string))))))
  125. (defun make-listener-input-stream (channel)
  126. (swank/backend:make-input-stream (lambda () (read-input channel))))
  127. (defun set-mode (channel new-mode)
  128. (with-slots (mode remote) channel
  129. (unless (eq mode new-mode)
  130. (send-to-remote-channel remote `(:set-read-mode ,new-mode)))
  131. (setf mode new-mode)))
  132. (defun read-input (channel)
  133. (with-slots (mode tag remote) channel
  134. (force-output)
  135. (let ((old-mode mode)
  136. (old-tag tag))
  137. (setf tag (cons nil nil))
  138. (set-mode channel :read)
  139. (unwind-protect
  140. (catch tag (process-requests nil))
  141. (setf tag old-tag)
  142. (set-mode channel old-mode)))))
  143. (provide :swank-mrepl)