perq.sl 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % PERQ.SL - Terminal Interface
  4. %
  5. % Author: Robert Kessler, U of Utah
  6. % Date: 27 Jan 1983
  7. % based on teleray.SL by G.Q.Maguire,Jr.
  8. % U of Utah
  9. % 3 November 1982
  10. % based on VT52X.SL by Alan Snyder
  11. % Hewlett-Packard/CRC
  12. % 6 October 1982
  13. %
  14. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  15. (BothTimes (load objects))
  16. (CompileTime (load display-char fast-int fast-vectors))
  17. (defflavor perq (
  18. (height 70) % number of rows (0 indexed)
  19. (maxrow 69) % highest numbered row
  20. (width 84) % number of columns (0 indexed)
  21. (maxcol 83) % highest numbered column
  22. (cursor-row 0) % cursor position
  23. (cursor-column 0) % cursor position
  24. (raw-mode NIL)
  25. (terminal-enhancement 0) % current enhancement (applies to most output)
  26. (terminal-blank #\space) % character used by ClearEOL
  27. )
  28. ()
  29. (gettable-instance-variables height width maxrow maxcol raw-mode)
  30. )
  31. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  32. (CompileTime
  33. (defmacro out-n (n)
  34. `(progn
  35. (if (> ,n 9)
  36. (PBOUT (+ (char 0) (/ ,n 10))))
  37. (PBOUT (+ (char 0) (// ,n 10))))))
  38. (CompileTime
  39. (defmacro out-char (ch)
  40. `(PBOUT (char ,ch))))
  41. (CompileTime
  42. (dm out-chars (form)
  43. (for (in ch (cdr form))
  44. (with L)
  45. (collect (list 'out-char ch) L)
  46. (returns (cons 'progn L)))))
  47. (CompileTime
  48. (defmacro out-move (row col)
  49. `(progn
  50. (out-chars ESC Y)
  51. (PBOUT (+ ,row 32))
  52. (PBOUT (+ ,col 32)))))
  53. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  54. (defmethod (perq get-character) ()
  55. (& (PBIN) 8#377)
  56. )
  57. (defmethod (perq ring-bell) ()
  58. (out-char BELL)
  59. )
  60. (defmethod (perq move-cursor) (row column)
  61. (cond ((< row 0) (setf row 0))
  62. ((>= row height) (setf row maxrow)))
  63. (cond ((< column 0) (setf column 0))
  64. ((>= column width) (setf column maxcol)))
  65. (cond ((and (= row cursor-row) (= column cursor-column))) % no action needed
  66. ((and (= row 0) (= column 0))
  67. (out-chars ESC H)) % cursor HOME
  68. ((= row cursor-row) % movement on current row
  69. (cond ((= column 0)
  70. (out-char CR)) % move to left margin
  71. ((= column (- cursor-column 1))
  72. (out-chars ESC D)) % move LEFT
  73. ((= column (+ cursor-column 1))
  74. (out-chars ESC C)) % move RIGHT
  75. (t (out-move row column))))
  76. ((= column cursor-column) % movement on same column
  77. (cond ((= row (- cursor-row 1))
  78. (out-chars ESC A)) % move UP
  79. ((= row (+ cursor-row 1))
  80. (out-char LF)) % move DOWN
  81. (t (out-move row column))))
  82. (t % arbitrary movement
  83. (out-move row column)))
  84. (setf cursor-row row)
  85. (setf cursor-column column)
  86. )
  87. (defmethod (perq enter-raw-mode) ()
  88. (when (not raw-mode)
  89. (EchoOff)
  90. % Enable Keypad?
  91. (setf raw-mode T)))
  92. (defmethod (perq leave-raw-mode) ()
  93. (when raw-mode
  94. (=> self &set-terminal-enhancement 0)
  95. (setf raw-mode NIL)
  96. % Disable Keypad?
  97. (EchoOn)))
  98. (defmethod (perq erase) ()
  99. % This method should be invoked to initialize the screen to a known state.
  100. (out-chars ESC H ESC J)
  101. (setf cursor-row 0)
  102. (setf cursor-column 0)
  103. (setf terminal-enhancement NIL) % force resetting when needed
  104. )
  105. (defmethod (perq clear-line) ()
  106. (out-chars ESC K)
  107. )
  108. (defmethod (perq convert-character) (ch)
  109. (setq ch (& ch (display-character-cons
  110. (dc-make-enhancement-mask INVERSE-VIDEO
  111. BLINK
  112. UNDERLINE
  113. INTENSIFY)
  114. (dc-make-font-mask 0)
  115. 16#FF)))
  116. (let ((code (dc-character-code ch)))
  117. (if (or (< code #\space) (= code (char rubout)))
  118. (setq ch #\space)))
  119. ch)
  120. (defmethod (perq normal-enhancement) ()
  121. (dc-make-enhancement-mask)
  122. )
  123. (defmethod (perq highlighted-enhancement) ()
  124. (dc-make-enhancement-mask)
  125. )
  126. (defmethod (perq supported-enhancements) ()
  127. (dc-make-enhancement-mask)
  128. )
  129. (defmethod (perq update-line) (row old-line new-line columns)
  130. % Old-Line is updated.
  131. (let ((first-col (car columns))
  132. (last-col (cdr columns))
  133. (last-nonblank-column NIL)
  134. )
  135. % Find out the minimal actual bounds:
  136. (while (and (<= first-col last-col)
  137. (= (vector-fetch new-line last-col)
  138. (vector-fetch old-line last-col)))
  139. (setf last-col (- last-col 1))
  140. )
  141. (while (and (<= first-col last-col)
  142. (= (vector-fetch new-line first-col)
  143. (vector-fetch old-line first-col)))
  144. (setf first-col (+ first-col 1))
  145. )
  146. % The purpose of the following code is to determine whether or not to use
  147. % ClearEOL. If we decide to use ClearEOL, then we will set the variable
  148. % LAST-NONBLANK-COLUMN to the obvious index; otherwise, we will set it to
  149. % NIL. If we decide to use ClearEOL, then we will clear out the OLD-LINE
  150. % now, but do the actual ClearEOL later.
  151. % Use of ClearEOL is appropriate if the rightmost changed character has
  152. % been changed to a space, and the remainder of the line is blank. It
  153. % is appropriate only if it replaces writing at least 3 blanks.
  154. (when (= (vector-fetch new-line last-col) terminal-blank)
  155. (setf last-nonblank-column (vector-upper-bound new-line))
  156. (while (and (>= last-nonblank-column 0)
  157. (= (vector-fetch new-line last-nonblank-column)
  158. terminal-blank)
  159. )
  160. (setf last-nonblank-column (- last-nonblank-column 1))
  161. )
  162. % We have computed the column containing the rightmost non-blank
  163. % character. Now, we can decide whether we want to do a ClearEOL or not.
  164. (if (and (< last-nonblank-column (- last-col 2)))
  165. % then
  166. (while (> last-col last-nonblank-column)
  167. (vector-store old-line last-col terminal-blank)
  168. (setf last-col (- last-col 1))
  169. )
  170. % else
  171. (setf last-nonblank-column NIL)
  172. ))
  173. % Output all changed characters (except those ClearEOL will do):
  174. (if (not (and (= cursor-row row) (<= cursor-column first-col)))
  175. (=> self move-cursor row first-col))
  176. % The VT52X will scroll if we write to the bottom right position.
  177. % This (hopefully temporary) hack will avoid writing there.
  178. (if (and (= row maxrow) (= last-col maxcol))
  179. (setf last-col (- maxcol 1))
  180. )
  181. (for (from col first-col last-col)
  182. (do
  183. (let ((old (vector-fetch old-line col))
  184. (new (vector-fetch new-line col))
  185. )
  186. (when (~= old new)
  187. (let ((new-enhancement (dc-enhancement-mask new))
  188. (new-code (dc-character-code new))
  189. )
  190. % Do we need to change the terminal enhancement?
  191. (if (~= terminal-enhancement new-enhancement)
  192. (=> self &set-terminal-enhancement new-enhancement)
  193. )
  194. (=> self &move-cursor-forward col old-line)
  195. (PBOUT new-code)
  196. (setf cursor-column (+ cursor-column 1))
  197. (when (> cursor-column maxcol)
  198. (setf cursor-column 0)
  199. (setf cursor-row (+ cursor-row 1))
  200. (if (> cursor-row maxrow)
  201. (=> self move-cursor 0 0)
  202. ))
  203. (vector-store old-line col new)
  204. )))))
  205. % Do the ClearEOL, if that's what we decided to do.
  206. (when last-nonblank-column
  207. (=> self &move-cursor-forward (+ last-nonblank-column 1) old-line)
  208. (=> self clear-line)
  209. )
  210. ))
  211. % The following methods are provided for INTERNAL use only!
  212. (defmethod (perq init) ()
  213. )
  214. (defmethod (perq &move-cursor-forward) (column line)
  215. (cond ((> (- column cursor-column) 4)
  216. (out-move cursor-row column)
  217. (setf cursor-column column))
  218. (t (while (< cursor-column column)
  219. (PBOUT (dc-character-code (vector-fetch line cursor-column)))
  220. (setf cursor-column (+ cursor-column 1))
  221. ))))
  222. (defmethod (perq &set-terminal-enhancement) (enh)
  223. )