| 1 | ;;; -*- Log: hemlock.log; Package: hemlock-internals -*-
|
|---|
| 2 | ;;;
|
|---|
| 3 | ;;; **********************************************************************
|
|---|
| 4 | ;;; This code was written as part of the CMU Common Lisp project at
|
|---|
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain.
|
|---|
| 6 | ;;;
|
|---|
| 7 | #+CMU (ext:file-comment
|
|---|
| 8 | "$Header$")
|
|---|
| 9 | ;;;
|
|---|
| 10 | ;;; **********************************************************************
|
|---|
| 11 | ;;;
|
|---|
| 12 | ;;; Written by Bill Chiles.
|
|---|
| 13 | ;;;
|
|---|
| 14 |
|
|---|
| 15 | (in-package :hemlock-internals)
|
|---|
| 16 |
|
|---|
| 17 | |
|---|
| 18 |
|
|---|
| 19 | ;;;; Terminal init and exit methods.
|
|---|
| 20 |
|
|---|
| 21 | (defvar *hemlock-input-handler*)
|
|---|
| 22 |
|
|---|
| 23 | (defun init-tty-device (device)
|
|---|
| 24 | (setf *hemlock-input-handler*
|
|---|
| 25 | (system:add-fd-handler 0 :input #'get-editor-tty-input))
|
|---|
| 26 | (standard-device-init)
|
|---|
| 27 | (device-write-string (tty-device-init-string device))
|
|---|
| 28 | (redisplay-all))
|
|---|
| 29 |
|
|---|
| 30 | (defun exit-tty-device (device)
|
|---|
| 31 | (cursor-motion device 0 (1- (tty-device-lines device)))
|
|---|
| 32 | ;; Can't call the clear-to-eol method since we don't have a hunk to
|
|---|
| 33 | ;; call it on, and you can't count on the bottom hunk being the echo area.
|
|---|
| 34 | ;;
|
|---|
| 35 | (if (tty-device-clear-to-eol-string device)
|
|---|
| 36 | (device-write-string (tty-device-clear-to-eol-string device))
|
|---|
| 37 | (dotimes (i (tty-device-columns device)
|
|---|
| 38 | (cursor-motion device 0 (1- (tty-device-lines device))))
|
|---|
| 39 | (tty-write-char #\space)))
|
|---|
| 40 | (device-write-string (tty-device-cm-end-string device))
|
|---|
| 41 | (when (device-force-output device)
|
|---|
| 42 | (funcall (device-force-output device)))
|
|---|
| 43 | (when *hemlock-input-handler*
|
|---|
| 44 | (system:remove-fd-handler *hemlock-input-handler*)
|
|---|
| 45 | (setf *hemlock-input-handler* nil))
|
|---|
| 46 | (standard-device-exit))
|
|---|
| 47 |
|
|---|
| 48 | |
|---|
| 49 |
|
|---|
| 50 | ;;;; Get terminal attributes:
|
|---|
| 51 |
|
|---|
| 52 | (defvar *terminal-baud-rate* nil)
|
|---|
| 53 | (declaim (type (or (unsigned-byte 24) null) *terminal-baud-rate*))
|
|---|
| 54 |
|
|---|
| 55 | ;;; GET-TERMINAL-ATTRIBUTES -- Interface
|
|---|
| 56 | ;;;
|
|---|
| 57 | ;;; Get terminal attributes from Unix. Return as values, the lines,
|
|---|
| 58 | ;;; columns and speed. If any value is inaccessible, return NIL for that
|
|---|
| 59 | ;;; value. We also sleazily cache the speed in *terminal-baud-rate*, since I
|
|---|
| 60 | ;;; don't want to figure out how to get my hands on the TTY-DEVICE at the place
|
|---|
| 61 | ;;; where I need it. Currently, there really can only be one TTY anyway, since
|
|---|
| 62 | ;;; the buffer is in a global.
|
|---|
| 63 | ;;;
|
|---|
| 64 | (defun get-terminal-attributes (&optional (fd 1))
|
|---|
| 65 | (alien:with-alien ((winsize (alien:struct unix:winsize))
|
|---|
| 66 | #-(or glibc2 bsd)
|
|---|
| 67 | (sgtty (alien:struct unix:sgttyb))
|
|---|
| 68 | #+bsd ; termios
|
|---|
| 69 | (tios (alien:struct unix:termios)))
|
|---|
| 70 | (let ((size-win (unix:unix-ioctl fd unix:TIOCGWINSZ
|
|---|
| 71 | (alien:alien-sap winsize)))
|
|---|
| 72 | #-(or glibc2 bsd)
|
|---|
| 73 | (speed-win (unix:unix-ioctl fd unix:TIOCGETP
|
|---|
| 74 | (alien:alien-sap sgtty)))
|
|---|
| 75 | #+bsd
|
|---|
| 76 | (speed-win (unix:unix-tcgetattr fd (alien:alien-sap tios))))
|
|---|
| 77 | (flet ((frob (val)
|
|---|
| 78 | (if (and size-win (not (zerop val)))
|
|---|
| 79 | val
|
|---|
| 80 | nil)))
|
|---|
| 81 | (values
|
|---|
| 82 | (frob (alien:slot winsize 'unix:ws-row))
|
|---|
| 83 | (frob (alien:slot winsize 'unix:ws-col))
|
|---|
| 84 | #-(or glibc2 bsd)
|
|---|
| 85 | (and speed-win
|
|---|
| 86 | (setq *terminal-baud-rate*
|
|---|
| 87 | (svref unix:terminal-speeds
|
|---|
| 88 | (alien:slot sgtty 'unix:sg-ospeed))))
|
|---|
| 89 | #+bsd
|
|---|
| 90 | (and speed-win
|
|---|
| 91 | (setq *terminal-baud-rate* (unix:unix-cfgetospeed tios)))
|
|---|
| 92 | #+glibc2
|
|---|
| 93 | 4800)))))
|
|---|
| 94 |
|
|---|
| 95 | |
|---|
| 96 |
|
|---|
| 97 | ;;;; Output routines and buffering.
|
|---|
| 98 |
|
|---|
| 99 | (defconstant redisplay-output-buffer-length 256)
|
|---|
| 100 |
|
|---|
| 101 | (defvar *redisplay-output-buffer*
|
|---|
| 102 | (make-string redisplay-output-buffer-length))
|
|---|
| 103 | (declaim (simple-string *redisplay-output-buffer*))
|
|---|
| 104 |
|
|---|
| 105 | (defvar *redisplay-output-buffer-index* 0)
|
|---|
| 106 | (declaim (fixnum *redisplay-output-buffer-index*))
|
|---|
| 107 |
|
|---|
| 108 | ;;; WRITE-AND-MAYBE-WAIT -- Internal
|
|---|
| 109 | ;;;
|
|---|
| 110 | ;;; Write the first Count characters in the redisplay output buffer. If
|
|---|
| 111 | ;;; *terminal-baud-rate* is set, then sleep for long enough to allow the
|
|---|
| 112 | ;;; written text to be displayed. We multiply by 10 to get the baud-per-byte
|
|---|
| 113 | ;;; conversion, which assumes 7 character bits + 1 start bit + 2 stop bits, no
|
|---|
| 114 | ;;; parity.
|
|---|
| 115 | ;;;
|
|---|
| 116 | (defun write-and-maybe-wait (count)
|
|---|
| 117 | (declare (fixnum count))
|
|---|
| 118 | (unix:unix-write 1 *redisplay-output-buffer* 0 count)
|
|---|
| 119 | (let ((speed *terminal-baud-rate*))
|
|---|
| 120 | (when speed
|
|---|
| 121 | (sleep (/ (* (float count) 10.0) (float speed))))))
|
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 | ;;; TTY-WRITE-STRING blasts the string into the redisplay output buffer.
|
|---|
| 125 | ;;; If the string overflows the buffer, then segments of the string are
|
|---|
| 126 | ;;; blasted into the buffer, dumping the buffer, until the last piece of
|
|---|
| 127 | ;;; the string is stored in the buffer. The buffer is always dumped if
|
|---|
| 128 | ;;; it is full, even if the last piece of the string just fills the buffer.
|
|---|
| 129 | ;;;
|
|---|
| 130 | (defun tty-write-string (string start length)
|
|---|
| 131 | (declare (fixnum start length))
|
|---|
| 132 | (let ((buffer-space (- redisplay-output-buffer-length
|
|---|
| 133 | *redisplay-output-buffer-index*)))
|
|---|
| 134 | (declare (fixnum buffer-space))
|
|---|
| 135 | (cond ((<= length buffer-space)
|
|---|
| 136 | (let ((dst-index (+ *redisplay-output-buffer-index* length)))
|
|---|
| 137 | (%primitive byte-blt string start *redisplay-output-buffer*
|
|---|
| 138 | *redisplay-output-buffer-index* dst-index)
|
|---|
| 139 | (cond ((= length buffer-space)
|
|---|
| 140 | (write-and-maybe-wait redisplay-output-buffer-length)
|
|---|
| 141 | (setf *redisplay-output-buffer-index* 0))
|
|---|
| 142 | (t
|
|---|
| 143 | (setf *redisplay-output-buffer-index* dst-index)))))
|
|---|
| 144 | (t
|
|---|
| 145 | (let ((remaining (- length buffer-space)))
|
|---|
| 146 | (declare (fixnum remaining))
|
|---|
| 147 | (loop
|
|---|
| 148 | (%primitive byte-blt string start *redisplay-output-buffer*
|
|---|
| 149 | *redisplay-output-buffer-index*
|
|---|
| 150 | redisplay-output-buffer-length)
|
|---|
| 151 | (write-and-maybe-wait redisplay-output-buffer-length)
|
|---|
| 152 | (when (< remaining redisplay-output-buffer-length)
|
|---|
| 153 | (%primitive byte-blt string (+ start buffer-space)
|
|---|
| 154 | *redisplay-output-buffer* 0 remaining)
|
|---|
| 155 | (setf *redisplay-output-buffer-index* remaining)
|
|---|
| 156 | (return t))
|
|---|
| 157 | (incf start buffer-space)
|
|---|
| 158 | (setf *redisplay-output-buffer-index* 0)
|
|---|
| 159 | (setf buffer-space redisplay-output-buffer-length)
|
|---|
| 160 | (decf remaining redisplay-output-buffer-length)))))))
|
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 | ;;; TTY-WRITE-CHAR stores a character in the redisplay output buffer,
|
|---|
| 164 | ;;; dumping the buffer if it becomes full.
|
|---|
| 165 | ;;;
|
|---|
| 166 | (defun tty-write-char (char)
|
|---|
| 167 | (setf (schar *redisplay-output-buffer* *redisplay-output-buffer-index*)
|
|---|
| 168 | char)
|
|---|
| 169 | (incf *redisplay-output-buffer-index*)
|
|---|
| 170 | (when (= *redisplay-output-buffer-index* redisplay-output-buffer-length)
|
|---|
| 171 | (write-and-maybe-wait redisplay-output-buffer-length)
|
|---|
| 172 | (setf *redisplay-output-buffer-index* 0)))
|
|---|
| 173 |
|
|---|
| 174 |
|
|---|
| 175 | ;;; TTY-FORCE-OUTPUT dumps the redisplay output buffer. This is called
|
|---|
| 176 | ;;; out of terminal device structures in multiple places -- the device
|
|---|
| 177 | ;;; exit method, random typeout methods, out of tty-hunk-stream methods,
|
|---|
| 178 | ;;; after calls to REDISPLAY or REDISPLAY-ALL.
|
|---|
| 179 | ;;;
|
|---|
| 180 | (defun tty-force-output ()
|
|---|
| 181 | (unless (zerop *redisplay-output-buffer-index*)
|
|---|
| 182 | (write-and-maybe-wait *redisplay-output-buffer-index*)
|
|---|
| 183 | (setf *redisplay-output-buffer-index* 0)))
|
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 | ;;; TTY-FINISH-OUTPUT simply dumps output.
|
|---|
| 187 | ;;;
|
|---|
| 188 | (defun tty-finish-output (device window)
|
|---|
| 189 | (declare (ignore window))
|
|---|
| 190 | (let ((force-output (device-force-output device)))
|
|---|
| 191 | (when force-output
|
|---|
| 192 | (funcall force-output))))
|
|---|
| 193 |
|
|---|
| 194 |
|
|---|
| 195 | |
|---|
| 196 |
|
|---|
| 197 | ;;;; Screen image line hacks.
|
|---|
| 198 |
|
|---|
| 199 | (defmacro replace-si-line (dst-string src-string src-start dst-start dst-end)
|
|---|
| 200 | `(%primitive byte-blt ,src-string ,src-start ,dst-string ,dst-start ,dst-end))
|
|---|