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.

207 lines
6.5 KiB

4 years ago
  1. ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
  2. ;;;
  3. ;;; swank-gray.lisp --- Gray stream based IO redirection.
  4. ;;;
  5. ;;; Created 2003
  6. ;;;
  7. ;;; This code has been placed in the Public Domain. All warranties
  8. ;;; are disclaimed.
  9. ;;;
  10. (in-package swank/backend)
  11. #.(progn
  12. (defvar *gray-stream-symbols*
  13. '(fundamental-character-output-stream
  14. stream-write-char
  15. stream-write-string
  16. stream-fresh-line
  17. stream-force-output
  18. stream-finish-output
  19. fundamental-character-input-stream
  20. stream-read-char
  21. stream-peek-char
  22. stream-read-line
  23. stream-listen
  24. stream-unread-char
  25. stream-clear-input
  26. stream-line-column
  27. stream-read-char-no-hang))
  28. nil)
  29. (defpackage swank/gray
  30. (:use cl swank/backend)
  31. (:import-from #.(gray-package-name) . #.*gray-stream-symbols*)
  32. (:export . #.*gray-stream-symbols*))
  33. (in-package swank/gray)
  34. (defclass slime-output-stream (fundamental-character-output-stream)
  35. ((output-fn :initarg :output-fn)
  36. (buffer :initform (make-string 8000))
  37. (fill-pointer :initform 0)
  38. (column :initform 0)
  39. (lock :initform (make-lock :name "buffer write lock"))
  40. (flush-thread :initarg :flush-thread
  41. :initform nil
  42. :accessor flush-thread)
  43. (flush-scheduled :initarg :flush-scheduled
  44. :initform nil
  45. :accessor flush-scheduled)))
  46. (defun maybe-schedule-flush (stream)
  47. (when (and (flush-thread stream)
  48. (not (flush-scheduled stream)))
  49. (setf (flush-scheduled stream) t)
  50. (send (flush-thread stream) t)))
  51. (defmacro with-slime-output-stream (stream &body body)
  52. `(with-slots (lock output-fn buffer fill-pointer column) ,stream
  53. (call-with-lock-held lock (lambda () ,@body))))
  54. (defmethod stream-write-char ((stream slime-output-stream) char)
  55. (with-slime-output-stream stream
  56. (setf (schar buffer fill-pointer) char)
  57. (incf fill-pointer)
  58. (incf column)
  59. (when (char= #\newline char)
  60. (setf column 0))
  61. (if (= fill-pointer (length buffer))
  62. (finish-output stream)
  63. (maybe-schedule-flush stream)))
  64. char)
  65. (defmethod stream-write-string ((stream slime-output-stream) string
  66. &optional start end)
  67. (with-slime-output-stream stream
  68. (let* ((start (or start 0))
  69. (end (or end (length string)))
  70. (len (length buffer))
  71. (count (- end start))
  72. (free (- len fill-pointer)))
  73. (when (>= count free)
  74. (stream-finish-output stream))
  75. (cond ((< count len)
  76. (replace buffer string :start1 fill-pointer
  77. :start2 start :end2 end)
  78. (incf fill-pointer count)
  79. (maybe-schedule-flush stream))
  80. (t
  81. (funcall output-fn (subseq string start end))))
  82. (let ((last-newline (position #\newline string :from-end t
  83. :start start :end end)))
  84. (setf column (if last-newline
  85. (- end last-newline 1)
  86. (+ column count))))))
  87. string)
  88. (defmethod stream-line-column ((stream slime-output-stream))
  89. (with-slime-output-stream stream column))
  90. (defmethod stream-finish-output ((stream slime-output-stream))
  91. (with-slime-output-stream stream
  92. (unless (zerop fill-pointer)
  93. (funcall output-fn (subseq buffer 0 fill-pointer))
  94. (setf fill-pointer 0))
  95. (setf (flush-scheduled stream) nil))
  96. nil)
  97. #+(and sbcl sb-thread)
  98. (defmethod stream-force-output :around ((stream slime-output-stream))
  99. ;; Workaround for deadlocks between the world-lock and auto-flush-thread
  100. ;; buffer write lock.
  101. ;;
  102. ;; Another alternative would be to grab the world-lock here, but that's less
  103. ;; future-proof, and could introduce other lock-ordering issues in the
  104. ;; future.
  105. (handler-case
  106. (sb-sys:with-deadline (:seconds 0.1)
  107. (call-next-method))
  108. (sb-sys:deadline-timeout ()
  109. nil)))
  110. (defmethod stream-force-output ((stream slime-output-stream))
  111. (stream-finish-output stream))
  112. (defmethod stream-fresh-line ((stream slime-output-stream))
  113. (with-slime-output-stream stream
  114. (cond ((zerop column) nil)
  115. (t (terpri stream) t))))
  116. (defclass slime-input-stream (fundamental-character-input-stream)
  117. ((input-fn :initarg :input-fn)
  118. (buffer :initform "") (index :initform 0)
  119. (lock :initform (make-lock :name "buffer read lock"))))
  120. (defmethod stream-read-char ((s slime-input-stream))
  121. (call-with-lock-held
  122. (slot-value s 'lock)
  123. (lambda ()
  124. (with-slots (buffer index input-fn) s
  125. (when (= index (length buffer))
  126. (let ((string (funcall input-fn)))
  127. (cond ((zerop (length string))
  128. (return-from stream-read-char :eof))
  129. (t
  130. (setf buffer string)
  131. (setf index 0)))))
  132. (assert (plusp (length buffer)))
  133. (prog1 (aref buffer index) (incf index))))))
  134. (defmethod stream-listen ((s slime-input-stream))
  135. (call-with-lock-held
  136. (slot-value s 'lock)
  137. (lambda ()
  138. (with-slots (buffer index) s
  139. (< index (length buffer))))))
  140. (defmethod stream-unread-char ((s slime-input-stream) char)
  141. (call-with-lock-held
  142. (slot-value s 'lock)
  143. (lambda ()
  144. (with-slots (buffer index) s
  145. (decf index)
  146. (cond ((eql (aref buffer index) char)
  147. (setf (aref buffer index) char))
  148. (t
  149. (warn "stream-unread-char: ignoring ~S (expected ~S)"
  150. char (aref buffer index)))))))
  151. nil)
  152. (defmethod stream-clear-input ((s slime-input-stream))
  153. (call-with-lock-held
  154. (slot-value s 'lock)
  155. (lambda ()
  156. (with-slots (buffer index) s
  157. (setf buffer ""
  158. index 0))))
  159. nil)
  160. (defmethod stream-line-column ((s slime-input-stream))
  161. nil)
  162. (defmethod stream-read-char-no-hang ((s slime-input-stream))
  163. (call-with-lock-held
  164. (slot-value s 'lock)
  165. (lambda ()
  166. (with-slots (buffer index) s
  167. (when (< index (length buffer))
  168. (prog1 (aref buffer index) (incf index)))))))
  169. ;;;
  170. (defimplementation make-auto-flush-thread (stream)
  171. (if (typep stream 'slime-output-stream)
  172. (setf (flush-thread stream)
  173. (spawn (lambda () (auto-flush-loop stream 0.08 t))
  174. :name "auto-flush-thread"))
  175. (spawn (lambda () (auto-flush-loop stream *auto-flush-interval*))
  176. :name "auto-flush-thread")))
  177. (defimplementation make-output-stream (write-string)
  178. (make-instance 'slime-output-stream :output-fn write-string))
  179. (defimplementation make-input-stream (read-string)
  180. (make-instance 'slime-input-stream :input-fn read-string))