buffer-io.sl 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % Buffer-IO.SL - PSL I/O to and from NMODE buffers
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 26 August 1982
  8. % Revised: 18 February 1983
  9. %
  10. % Adapted from Will Galway's EMODE
  11. %
  12. % 18-Feb-83 Alan Snyder
  13. % Fix to adjust an exposed window when displaying output.
  14. % 16-Feb-83 Alan Snyder
  15. % Recode using objects; add output cache for efficiency.
  16. % Remove time-since-last-redisplay check (it causes a 2X slowdown);
  17. % now display output only after Newline or cache full.
  18. % Declare -> Declare-Flavor.
  19. % 30-Dec-82 Alan Snyder
  20. % Add declarations for buffers and windows; use fast-vectors (for efficiency).
  21. % 27-Dec-82 Alan Snyder
  22. % Use generic arithmetic for Time (for portability); reformat.
  23. %
  24. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  25. (CompileTime (load objects fast-vectors))
  26. (fluid '(nmode-current-window *nmode-init-running))
  27. (DefConst MaxChannels 32) % Maximum number of channels supported by PSL.
  28. (defflavor buffer-channel
  29. (
  30. (editor-function NIL) % NIL or a function to obtain new input
  31. (input-buffer NIL) % NIL or a buffer to obtain input from
  32. (input-position NIL) % the current read pointer
  33. (output-buffer NIL) % NIL or a buffer to send output to
  34. (output-cache NIL) % cache of output (for efficiency)
  35. output-cache-pos % pointer into output cache
  36. )
  37. ()
  38. (settable-instance-variables)
  39. )
  40. (fluid '(buffer-channel-vector))
  41. (when (or (not (BoundP 'buffer-channel-vector)) (null buffer-channel-vector))
  42. (setf buffer-channel-vector (MkVect (const MaxChannels)))
  43. )
  44. (fluid '(*outwindow % T => expose output window on output
  45. ))
  46. (setf *outwindow T)
  47. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  48. (declare-flavor text-buffer input-buffer output-buffer)
  49. (declare-flavor buffer-window w)
  50. (declare-flavor buffer-channel bc)
  51. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  52. (de OpenBufferChannel (input-buffer output-buffer Editor)
  53. % Open a channel for buffer I/O. Input-Buffer and Output-Buffer may be buffer
  54. % objects or NIL. Input will be read from the current location in the Input
  55. % Buffer. Output will be inserted at the current location in the Output
  56. % Buffer. Editor may be a function object (ID) or NIL. The Editor function
  57. % can be used if you want something to "happen" every time a reader begins to
  58. % read from the channel. If Editor is NIL, then the reader will simply
  59. % continue reading from the current location in the input buffer.
  60. (setf SpecialWriteFunction* 'buffer-print-character)
  61. (setf SpecialReadFunction* 'buffer-read-character)
  62. (setf SpecialCloseFunction* 'buffer-channel-close)
  63. (let ((chn (open "buffers" 'SPECIAL))
  64. (bc (make-instance 'buffer-channel))
  65. )
  66. (vector-store buffer-channel-vector chn bc)
  67. (=> bc set-input-buffer input-buffer)
  68. (=> bc set-input-position (and input-buffer (=> input-buffer position)))
  69. (=> bc set-output-buffer output-buffer)
  70. (=> bc set-editor-function Editor)
  71. chn
  72. ))
  73. (de buffer-channel-close (chn)
  74. % Close up an NMODE buffer channel.
  75. (vector-store buffer-channel-vector chn NIL)
  76. )
  77. (de buffer-channel-set-input-buffer (chn input-buffer)
  78. (let ((bc (vector-fetch buffer-channel-vector chn)))
  79. (when bc
  80. (=> bc set-input-buffer input-buffer)
  81. (=> bc set-input-position (=> input-buffer position))
  82. )))
  83. (de buffer-channel-set-input-position (chn bp)
  84. (let ((bc (vector-fetch buffer-channel-vector chn)))
  85. (when bc
  86. (=> bc set-input-position bp)
  87. )))
  88. (de buffer-channel-set-output-buffer (chn output-buffer)
  89. (let ((bc (vector-fetch buffer-channel-vector chn)))
  90. (when bc
  91. (=> bc set-output-buffer output-buffer)
  92. )))
  93. (de buffer-print-character (chn ch)
  94. (let ((bc (vector-fetch buffer-channel-vector chn)))
  95. (when bc
  96. (=> bc putc ch)
  97. )))
  98. (de buffer-channel-flush (chn)
  99. (let ((bc (vector-fetch buffer-channel-vector chn)))
  100. (when bc
  101. (=> bc flush)
  102. )))
  103. (defmethod (buffer-channel flush) ()
  104. % If there is output lingering in the output cache, then append it to the
  105. % output buffer and return T. Otherwise return NIL.
  106. (when (and output-buffer output-cache (> output-cache-pos 0))
  107. (let ((old-pos (=> output-buffer position)))
  108. (=> output-buffer move-to-buffer-end)
  109. (=> output-buffer insert-string
  110. (substring output-cache 0 output-cache-pos))
  111. (=> output-buffer set-position old-pos)
  112. (setf output-cache-pos 0)
  113. T
  114. )))
  115. (defmethod (buffer-channel refresh) ()
  116. % If this channel is being used for output, then refresh the display of that
  117. % output. The buffer will automatically be exposed in a window (if
  118. % requested by the *OutWindow flag), the output cache will be flushed, the
  119. % display window will be adjusted, and the screen refreshed.
  120. (when output-buffer
  121. (if (and *OutWindow
  122. (not *nmode-init-running)
  123. (not (buffer-is-displayed? output-buffer)))
  124. (nmode-expose-output-buffer output-buffer))
  125. (let ((window-list (find-buffer-in-exposed-windows output-buffer)))
  126. (when window-list
  127. (=> self flush)
  128. (nmode-adjust-output-window (car window-list))
  129. ))))
  130. (defmethod (buffer-channel put-newline) ()
  131. (=> self flush)
  132. (let ((old-pos (=> output-buffer position)))
  133. (=> output-buffer move-to-buffer-end)
  134. (=> output-buffer insert-eol)
  135. (=> output-buffer set-position old-pos)
  136. )
  137. (=> self refresh)
  138. )
  139. (defmethod (buffer-channel putc) (ch)
  140. % "Print" character CH by appending it to the output buffer.
  141. (if (= ch #\EOL)
  142. (=> self put-newline)
  143. (when output-buffer
  144. (when (null output-cache)
  145. (setf output-cache (make-string 200 #\space))
  146. (setf output-cache-pos 0)
  147. )
  148. (string-store output-cache output-cache-pos ch)
  149. (setf output-cache-pos (+ output-cache-pos 1))
  150. (when (>= output-cache-pos 200)
  151. (=> self flush)
  152. (=> self refresh)
  153. ))))
  154. (de nmode-adjust-output-window (w)
  155. (let ((output-buffer (=> w buffer)))
  156. (=> w set-position (=> output-buffer buffer-end-position))
  157. (nmode-adjust-window w)
  158. (if (=> w exposed?) (nmode-refresh))
  159. ))
  160. (de buffer-read-character (chn)
  161. (let ((bc (vector-fetch buffer-channel-vector chn)))
  162. (when bc
  163. (=> bc getc)
  164. )))
  165. (defmethod (buffer-channel getc) ()
  166. % Read a character from the input buffer; advance over that character.
  167. % Return End Of File if at end of buffer or if no buffer. If the "read
  168. % point" equals the "buffer cursor", then the "buffer cursor" will be
  169. % advanced also.
  170. (if (not input-buffer)
  171. #\EOF
  172. % Otherwise (there is an input buffer)
  173. (let* ((old-position (=> input-buffer position))
  174. (was-at-cursor (buffer-position-equal input-position old-position))
  175. result
  176. )
  177. (=> input-buffer set-position input-position)
  178. (if (=> input-buffer at-buffer-end?)
  179. (setf result #\EOF)
  180. % Otherwise (not at end of buffer)
  181. (setf result (=> input-buffer next-character))
  182. (=> input-buffer move-forward)
  183. (setf input-position (=> input-buffer position))
  184. )
  185. (if (not was-at-cursor)
  186. (=> input-buffer set-position old-position))
  187. (if *ECHO (=> self putc result))
  188. result
  189. )))
  190. (de MakeInputAvailable ()
  191. % THIS IS THE MAGIC FUNCTION invoked by READ, and other "reader functions".
  192. % IN* is a FLUID (actually GLOBAL) variable.
  193. (let ((bc (vector-fetch buffer-channel-vector IN*)))
  194. (when bc
  195. (=> bc run-editor)
  196. )))
  197. (defmethod (buffer-channel run-editor) ()
  198. (if editor-function (apply editor-function (list IN*)))
  199. NIL
  200. )
  201. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  202. (undeclare-flavor input-buffer output-buffer)
  203. (undeclare-flavor w)
  204. (undeclare-flavor bc)