| 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 | (export '(redisplay redisplay-all define-tty-font))
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 | |
|---|
| 21 |
|
|---|
| 22 | ;;;; Macros.
|
|---|
| 23 |
|
|---|
| 24 | (eval-when (:compile-toplevel :execute)
|
|---|
| 25 | (defmacro tty-hunk-modeline-pos (hunk)
|
|---|
| 26 | `(tty-hunk-text-height ,hunk))
|
|---|
| 27 | ) ;eval-when
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 | (defvar *currently-selected-hunk* nil)
|
|---|
| 31 | (defvar *hunk-top-line*)
|
|---|
| 32 |
|
|---|
| 33 | (declaim (fixnum *hunk-top-line*))
|
|---|
| 34 |
|
|---|
| 35 | (eval-when (:compile-toplevel :execute)
|
|---|
| 36 | (defmacro select-hunk (hunk)
|
|---|
| 37 | `(unless (eq ,hunk *currently-selected-hunk*)
|
|---|
| 38 | (setf *currently-selected-hunk* ,hunk)
|
|---|
| 39 | (setf *hunk-top-line*
|
|---|
| 40 | (the fixnum
|
|---|
| 41 | (1+ (the fixnum
|
|---|
| 42 | (- (the fixnum
|
|---|
| 43 | (tty-hunk-text-position ,hunk))
|
|---|
| 44 | (the fixnum
|
|---|
| 45 | (tty-hunk-text-height ,hunk)))))))))
|
|---|
| 46 | ) ;eval-when
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 | ;;; Screen image lines.
|
|---|
| 50 | ;;;
|
|---|
| 51 | (defstruct (si-line (:print-function print-screen-image-line)
|
|---|
| 52 | (:constructor %make-si-line (chars)))
|
|---|
| 53 | (chars nil :type simple-string)
|
|---|
| 54 | (length 0)
|
|---|
| 55 | (fonts nil :type list))
|
|---|
| 56 |
|
|---|
| 57 | (defun make-si-line (n)
|
|---|
| 58 | (%make-si-line (make-string n)))
|
|---|
| 59 |
|
|---|
| 60 | (defun print-screen-image-line (obj str n)
|
|---|
| 61 | (declare (ignore n))
|
|---|
| 62 | (write-string "#<Screen Image Line \"" str)
|
|---|
| 63 | (write-string (si-line-chars obj) str :end (si-line-length obj))
|
|---|
| 64 | (write-string "\">" str))
|
|---|
| 65 |
|
|---|
| 66 |
|
|---|
| 67 | (defun find-identical-prefix (dis-line dis-line-fonts si-line)
|
|---|
| 68 | (declare (type dis-line dis-line)
|
|---|
| 69 | (type list dis-line-fonts)
|
|---|
| 70 | (type si-line si-line))
|
|---|
| 71 | (let* ((dl-chars (dis-line-chars dis-line))
|
|---|
| 72 | (dl-len (dis-line-length dis-line))
|
|---|
| 73 | (si-chars (si-line-chars si-line))
|
|---|
| 74 | (si-len (si-line-length si-line))
|
|---|
| 75 | (okay-until 0))
|
|---|
| 76 | (declare (type simple-string dl-chars si-chars)
|
|---|
| 77 | (type (and unsigned-byte fixnum) dl-len si-len)
|
|---|
| 78 | (type (and unsigned-byte fixnum) okay-until))
|
|---|
| 79 | (do ((dl-fonts dis-line-fonts (cdr dis-line-fonts))
|
|---|
| 80 | (si-fonts (si-line-fonts si-line) (cdr si-fonts)))
|
|---|
| 81 | ((or (null dl-fonts) (null si-fonts))
|
|---|
| 82 | (let ((next-font (car (or dl-fonts si-fonts))))
|
|---|
| 83 | (if next-font
|
|---|
| 84 | (let ((end (min dl-len si-len (cadr next-font))))
|
|---|
| 85 | (or (string/= dl-chars si-chars
|
|---|
| 86 | :start1 okay-until :start2 okay-until
|
|---|
| 87 | :end1 end :end2 end)
|
|---|
| 88 | end))
|
|---|
| 89 | (let ((end (min dl-len si-len)))
|
|---|
| 90 | (or (string/= dl-chars si-chars
|
|---|
| 91 | :start1 okay-until :start2 okay-until
|
|---|
| 92 | :end1 end :end2 end)
|
|---|
| 93 | (if (= dl-len si-len) nil end))))))
|
|---|
| 94 | (let ((dl-font (caar dl-fonts))
|
|---|
| 95 | (dl-start (cadar dl-fonts))
|
|---|
| 96 | (dl-stop (cddar dl-fonts))
|
|---|
| 97 | (si-font (caar si-fonts))
|
|---|
| 98 | (si-start (cadar si-fonts))
|
|---|
| 99 | (si-stop (cddar si-fonts)))
|
|---|
| 100 | (unless (and (= dl-font si-font)
|
|---|
| 101 | (= dl-start si-start))
|
|---|
| 102 | (let ((font-lossage (min dl-start si-start)))
|
|---|
| 103 | (return (or (string/= dl-chars si-chars
|
|---|
| 104 | :start1 okay-until :start2 okay-until
|
|---|
| 105 | :end1 font-lossage :end2 font-lossage)
|
|---|
| 106 | font-lossage))))
|
|---|
| 107 | (unless (= dl-stop si-stop)
|
|---|
| 108 | (let ((font-lossage (min dl-stop si-stop)))
|
|---|
| 109 | (return (or (string/= dl-chars si-chars
|
|---|
| 110 | :start1 okay-until :start2 okay-until
|
|---|
| 111 | :end1 font-lossage :end2 font-lossage)
|
|---|
| 112 | font-lossage))))
|
|---|
| 113 | (let ((mismatch (string/= dl-chars si-chars
|
|---|
| 114 | :start1 okay-until :start2 okay-until
|
|---|
| 115 | :end1 dl-stop :end2 si-stop)))
|
|---|
| 116 | (if mismatch
|
|---|
| 117 | (return mismatch)
|
|---|
| 118 | (setf okay-until dl-stop)))))))
|
|---|
| 119 |
|
|---|
| 120 |
|
|---|
| 121 | (defun find-identical-suffix (dis-line dis-line-fonts si-line)
|
|---|
| 122 | (declare (type dis-line dis-line)
|
|---|
| 123 | (type list dis-line-fonts)
|
|---|
| 124 | (type si-line si-line))
|
|---|
| 125 | (let* ((dl-chars (dis-line-chars dis-line))
|
|---|
| 126 | (dl-len (dis-line-length dis-line))
|
|---|
| 127 | (si-chars (si-line-chars si-line))
|
|---|
| 128 | (si-len (si-line-length si-line))
|
|---|
| 129 | (count (dotimes (i (min dl-len si-len) i)
|
|---|
| 130 | (when (char/= (schar dl-chars (- dl-len i 1))
|
|---|
| 131 | (schar si-chars (- si-len i 1)))
|
|---|
| 132 | (return i)))))
|
|---|
| 133 | (declare (type simple-string dl-chars si-chars)
|
|---|
| 134 | (type (and unsigned-byte fixnum) dl-len si-len))
|
|---|
| 135 | (do ((dl-fonts (reverse dis-line-fonts) (cdr dis-line-fonts))
|
|---|
| 136 | (si-fonts (reverse (si-line-fonts si-line)) (cdr si-fonts)))
|
|---|
| 137 | ((or (null dl-fonts) (null si-fonts))
|
|---|
| 138 | (cond (dl-fonts
|
|---|
| 139 | (min (- dl-len (cddar dl-fonts)) count))
|
|---|
| 140 | (si-fonts
|
|---|
| 141 | (min (- si-len (cddar si-fonts)) count))
|
|---|
| 142 | (t
|
|---|
| 143 | count)))
|
|---|
| 144 | (let ((dl-font (caar dl-fonts))
|
|---|
| 145 | (dl-start (- dl-len (cadar dl-fonts)))
|
|---|
| 146 | (dl-stop (- dl-len (cddar dl-fonts)))
|
|---|
| 147 | (si-font (caar si-fonts))
|
|---|
| 148 | (si-start (- si-len (cadar si-fonts)))
|
|---|
| 149 | (si-stop (- si-len (cddar si-fonts))))
|
|---|
| 150 | (unless (and (= dl-font si-font)
|
|---|
| 151 | (= dl-stop si-stop))
|
|---|
| 152 | (return (min dl-stop si-stop count)))
|
|---|
| 153 | (unless (= dl-start si-start)
|
|---|
| 154 | (return (min dl-start si-start count)))
|
|---|
| 155 | (when (<= count dl-start)
|
|---|
| 156 | (return count))))))
|
|---|
| 157 |
|
|---|
| 158 |
|
|---|
| 159 | (defmacro si-line (screen-image n)
|
|---|
| 160 | `(svref ,screen-image ,n))
|
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 | |
|---|
| 164 |
|
|---|
| 165 | ;;; Font support.
|
|---|
| 166 |
|
|---|
| 167 | (defvar *tty-font-strings* (make-array font-map-size :initial-element nil)
|
|---|
| 168 | "Array of (start-string . end-string) for fonts, or NIL if no such font.")
|
|---|
| 169 |
|
|---|
| 170 | (defun define-tty-font (font-id &rest stuff)
|
|---|
| 171 | (unless (<= 0 font-id (1- font-map-size))
|
|---|
| 172 | (error "Bogus font-id: ~S" font-id))
|
|---|
| 173 | (cond ((every #'keywordp stuff)
|
|---|
| 174 | (error "Can't extract font strings from the termcap entry yet."))
|
|---|
| 175 | ((and (= (length stuff) 2)
|
|---|
| 176 | (stringp (car stuff))
|
|---|
| 177 | (stringp (cadr stuff)))
|
|---|
| 178 | (setf (aref *tty-font-strings* font-id)
|
|---|
| 179 | (cons (car stuff) (cadr stuff))))
|
|---|
| 180 | (t
|
|---|
| 181 | (error "Bogus font spec: ~S~%Must be either a list of keywords or ~
|
|---|
| 182 | a list of the start string and end string."))))
|
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 | (defun compute-font-usages (dis-line)
|
|---|
| 186 | (do ((results nil)
|
|---|
| 187 | (change (dis-line-font-changes dis-line) (font-change-next change))
|
|---|
| 188 | (prev nil change))
|
|---|
| 189 | ((null change)
|
|---|
| 190 | (when prev
|
|---|
| 191 | (let ((font (font-change-font prev)))
|
|---|
| 192 | (when (and (not (zerop font))
|
|---|
| 193 | (aref *tty-font-strings* font))
|
|---|
| 194 | (push (list* (font-change-font prev)
|
|---|
| 195 | (font-change-x prev)
|
|---|
| 196 | (dis-line-length dis-line))
|
|---|
| 197 | results))))
|
|---|
| 198 | (nreverse results))
|
|---|
| 199 | (when prev
|
|---|
| 200 | (let ((font (font-change-font prev)))
|
|---|
| 201 | (when (and (not (zerop font))
|
|---|
| 202 | (aref *tty-font-strings* font))
|
|---|
| 203 | (push (list* (font-change-font prev)
|
|---|
| 204 | (font-change-x prev)
|
|---|
| 205 | (font-change-x change))
|
|---|
| 206 | results))))))
|
|---|
| 207 |
|
|---|
| 208 | |
|---|
| 209 |
|
|---|
| 210 | ;;;; Dumb window redisplay.
|
|---|
| 211 |
|
|---|
| 212 | (defmacro tty-dumb-line-redisplay (device hunk dis-line &optional y)
|
|---|
| 213 | (let ((dl (gensym)) (dl-chars (gensym)) (dl-fonts (gensym)) (dl-len (gensym))
|
|---|
| 214 | (dl-pos (gensym)) (screen-image-line (gensym)))
|
|---|
| 215 | `(let* ((,dl ,dis-line)
|
|---|
| 216 | (,dl-chars (dis-line-chars ,dl))
|
|---|
| 217 | (,dl-fonts (compute-font-usages ,dis-line))
|
|---|
| 218 | (,dl-len (dis-line-length ,dl))
|
|---|
| 219 | (,dl-pos ,(or y `(dis-line-position ,dl))))
|
|---|
| 220 | (funcall (tty-device-display-string ,device)
|
|---|
| 221 | ,hunk 0 ,dl-pos ,dl-chars ,dl-fonts 0 ,dl-len)
|
|---|
| 222 | (setf (dis-line-flags ,dl) unaltered-bits)
|
|---|
| 223 | (setf (dis-line-delta ,dl) 0)
|
|---|
| 224 | (select-hunk ,hunk)
|
|---|
| 225 | (let ((,screen-image-line (si-line (tty-device-screen-image ,device)
|
|---|
| 226 | (+ *hunk-top-line* ,dl-pos))))
|
|---|
| 227 | (replace-si-line (si-line-chars ,screen-image-line) ,dl-chars
|
|---|
| 228 | 0 0 ,dl-len)
|
|---|
| 229 | (setf (si-line-length ,screen-image-line) ,dl-len)
|
|---|
| 230 | (setf (si-line-fonts ,screen-image-line) ,dl-fonts)))))
|
|---|
| 231 |
|
|---|
| 232 | (defun tty-dumb-window-redisplay (window)
|
|---|
| 233 | (let* ((first (window-first-line window))
|
|---|
| 234 | (hunk (window-hunk window))
|
|---|
| 235 | (device (device-hunk-device hunk))
|
|---|
| 236 | (screen-image (tty-device-screen-image device)))
|
|---|
| 237 | (funcall (tty-device-clear-to-eow device) hunk 0 0)
|
|---|
| 238 | (do ((i 0 (1+ i))
|
|---|
| 239 | (dl (cdr first) (cdr dl)))
|
|---|
| 240 | ((eq dl the-sentinel)
|
|---|
| 241 | (setf (window-old-lines window) (1- i))
|
|---|
| 242 | (select-hunk hunk)
|
|---|
| 243 | (do ((last (tty-hunk-text-position hunk))
|
|---|
| 244 | (i (+ *hunk-top-line* i) (1+ i)))
|
|---|
| 245 | ((> i last))
|
|---|
| 246 | (declare (fixnum i last))
|
|---|
| 247 | (let ((si-line (si-line screen-image i)))
|
|---|
| 248 | (setf (si-line-length si-line) 0)
|
|---|
| 249 | (setf (si-line-fonts si-line) nil))))
|
|---|
| 250 | (tty-dumb-line-redisplay device hunk (car dl) i))
|
|---|
| 251 | (setf (window-first-changed window) the-sentinel
|
|---|
| 252 | (window-last-changed window) first)
|
|---|
| 253 | (when (window-modeline-buffer window)
|
|---|
| 254 | (let ((dl (window-modeline-dis-line window))
|
|---|
| 255 | (y (tty-hunk-modeline-pos hunk)))
|
|---|
| 256 | (unwind-protect
|
|---|
| 257 | (progn
|
|---|
| 258 | (funcall (tty-device-standout-init device) hunk)
|
|---|
| 259 | (funcall (tty-device-clear-to-eol device) hunk 0 y)
|
|---|
| 260 | (tty-dumb-line-redisplay device hunk dl y))
|
|---|
| 261 | (funcall (tty-device-standout-end device) hunk))
|
|---|
| 262 | (setf (dis-line-flags dl) unaltered-bits)))))
|
|---|
| 263 |
|
|---|
| 264 |
|
|---|
| 265 | |
|---|
| 266 |
|
|---|
| 267 | ;;;; Dumb redisplay top n lines of a window.
|
|---|
| 268 |
|
|---|
| 269 | (defun tty-redisplay-n-lines (window n)
|
|---|
| 270 | (let* ((hunk (window-hunk window))
|
|---|
| 271 | (device (device-hunk-device hunk)))
|
|---|
| 272 | (funcall (tty-device-clear-lines device) hunk 0 0 n)
|
|---|
| 273 | (do ((n n (1- n))
|
|---|
| 274 | (dl (cdr (window-first-line window)) (cdr dl)))
|
|---|
| 275 | ((or (zerop n) (eq dl the-sentinel)))
|
|---|
| 276 | (tty-dumb-line-redisplay device hunk (car dl)))))
|
|---|
| 277 |
|
|---|
| 278 |
|
|---|
| 279 | |
|---|
| 280 |
|
|---|
| 281 | ;;;; Semi dumb window redisplay
|
|---|
| 282 |
|
|---|
| 283 | ;;; This is for terminals without opening and deleting lines.
|
|---|
| 284 |
|
|---|
| 285 | ;;; TTY-SEMI-DUMB-WINDOW-REDISPLAY is a lot like TTY-SMART-WINDOW-REDISPLAY,
|
|---|
| 286 | ;;; but it calls different line redisplay functions.
|
|---|
| 287 | ;;;
|
|---|
| 288 | (defun tty-semi-dumb-window-redisplay (window)
|
|---|
| 289 | (let* ((hunk (window-hunk window))
|
|---|
| 290 | (device (device-hunk-device hunk)))
|
|---|
| 291 | (let ((first-changed (window-first-changed window))
|
|---|
| 292 | (last-changed (window-last-changed window)))
|
|---|
| 293 | ;; Is there anything to do?
|
|---|
| 294 | (unless (eq first-changed the-sentinel)
|
|---|
| 295 | (if ;; One line-changed.
|
|---|
| 296 | (and (eq first-changed last-changed)
|
|---|
| 297 | (zerop (dis-line-delta (car first-changed))))
|
|---|
| 298 | (tty-semi-dumb-line-redisplay device hunk (car first-changed))
|
|---|
| 299 | ;; More lines changed.
|
|---|
| 300 | (do-semi-dumb-line-writes first-changed last-changed hunk))
|
|---|
| 301 | ;; Set the bounds so we know we displayed...
|
|---|
| 302 | (setf (window-first-changed window) the-sentinel
|
|---|
| 303 | (window-last-changed window) (window-first-line window))))
|
|---|
| 304 | ;;
|
|---|
| 305 | ;; Clear any extra lines at the end of the window.
|
|---|
| 306 | (let ((pos (dis-line-position (car (window-last-line window)))))
|
|---|
| 307 | (when (< pos (1- (window-height window)))
|
|---|
| 308 | (tty-smart-clear-to-eow hunk (1+ pos)))
|
|---|
| 309 | (setf (window-old-lines window) pos))
|
|---|
| 310 | ;;
|
|---|
| 311 | ;; Update the modeline if needed.
|
|---|
| 312 | (when (window-modeline-buffer window)
|
|---|
| 313 | (let ((dl (window-modeline-dis-line window)))
|
|---|
| 314 | (when (/= (dis-line-flags dl) unaltered-bits)
|
|---|
| 315 | (unwind-protect
|
|---|
| 316 | (progn
|
|---|
| 317 | (funcall (tty-device-standout-init device) hunk)
|
|---|
| 318 | (tty-smart-line-redisplay device hunk dl
|
|---|
| 319 | (tty-hunk-modeline-pos hunk)))
|
|---|
| 320 | (funcall (tty-device-standout-end device) hunk)))))))
|
|---|
| 321 |
|
|---|
| 322 | ;;; NEXT-DIS-LINE is used in DO-SEMI-DUMB-LINE-WRITES and
|
|---|
| 323 | ;;; COMPUTE-TTY-CHANGES.
|
|---|
| 324 | ;;;
|
|---|
| 325 | (eval-when (:compile-toplevel :execute)
|
|---|
| 326 | (defmacro next-dis-line ()
|
|---|
| 327 | `(progn
|
|---|
| 328 | (setf prev dl)
|
|---|
| 329 | (setf dl (cdr dl))
|
|---|
| 330 | (setf flags (dis-line-flags (car dl)))))
|
|---|
| 331 | ) ;eval-when
|
|---|
| 332 |
|
|---|
| 333 | ;;; DO-SEMI-DUMB-LINE-WRITES does what it says until it hits the last
|
|---|
| 334 | ;;; changed line. The commented out code was a gratuitous optimization,
|
|---|
| 335 | ;;; especially if the first-changed line really is the first changes line.
|
|---|
| 336 | ;;; Anyway, this had to be removed because of this function's use in
|
|---|
| 337 | ;;; TTY-SMART-WINDOW-REDISPLAY, which was punting line moves due to
|
|---|
| 338 | ;;; "Scroll Redraw Ratio". However, these supposedly moved lines had their
|
|---|
| 339 | ;;; bits set to unaltered bits in COMPUTE-TTY-CHANGES because it was
|
|---|
| 340 | ;;; assuming TTY-SMART-WINDOW-REDISPLAY guaranteed to do line moves.
|
|---|
| 341 | ;;;
|
|---|
| 342 | (defun do-semi-dumb-line-writes (first-changed last-changed hunk)
|
|---|
| 343 | (let* ((dl first-changed)
|
|---|
| 344 | flags ;(dis-line-flags (car dl))) flags bound for NEXT-DIS-LINE.
|
|---|
| 345 | prev)
|
|---|
| 346 | ;;
|
|---|
| 347 | ;; Skip old, unchanged, unmoved lines.
|
|---|
| 348 | ;; (loop
|
|---|
| 349 | ;; (unless (zerop flags) (return))
|
|---|
| 350 | ;; (next-dis-line))
|
|---|
| 351 | ;;
|
|---|
| 352 | ;; Write every remaining line.
|
|---|
| 353 | (let* ((device (device-hunk-device hunk))
|
|---|
| 354 | (force-output (device-force-output device)))
|
|---|
| 355 | (loop
|
|---|
| 356 | (tty-semi-dumb-line-redisplay device hunk (car dl))
|
|---|
| 357 | (when force-output (funcall force-output))
|
|---|
| 358 | (next-dis-line)
|
|---|
| 359 | (when (eq prev last-changed) (return))))))
|
|---|
| 360 |
|
|---|
| 361 | ;;; TTY-SEMI-DUMB-LINE-REDISPLAY finds the first different character
|
|---|
| 362 | ;;; comparing the display line and the screen image line, writes out the
|
|---|
| 363 | ;;; rest of the display line, and clears to end-of-line as necessary.
|
|---|
| 364 | ;;;
|
|---|
| 365 | (defun tty-semi-dumb-line-redisplay (device hunk dl
|
|---|
| 366 | &optional (dl-pos (dis-line-position dl)))
|
|---|
| 367 | (declare (fixnum dl-pos))
|
|---|
| 368 | (let* ((dl-chars (dis-line-chars dl))
|
|---|
| 369 | (dl-len (dis-line-length dl))
|
|---|
| 370 | (dl-fonts (compute-font-usages dl)))
|
|---|
| 371 | (declare (fixnum dl-len) (simple-string dl-chars))
|
|---|
| 372 | (when (listen-editor-input *editor-input*)
|
|---|
| 373 | (throw 'redisplay-catcher :editor-input))
|
|---|
| 374 | (select-hunk hunk)
|
|---|
| 375 | (let* ((screen-image-line (si-line (tty-device-screen-image device)
|
|---|
| 376 | (+ *hunk-top-line* dl-pos)))
|
|---|
| 377 | (si-line-chars (si-line-chars screen-image-line))
|
|---|
| 378 | (si-line-length (si-line-length screen-image-line))
|
|---|
| 379 | (findex (find-identical-prefix dl dl-fonts screen-image-line)))
|
|---|
| 380 | (declare (type (or fixnum null) findex) (simple-string si-line-chars))
|
|---|
| 381 | ;;
|
|---|
| 382 | ;; When the dis-line and screen chars are not string=.
|
|---|
| 383 | (when findex
|
|---|
| 384 | (cond
|
|---|
| 385 | ;; See if the screen shows an initial substring of the dis-line.
|
|---|
| 386 | ((= findex si-line-length)
|
|---|
| 387 | (funcall (tty-device-display-string device)
|
|---|
| 388 | hunk findex dl-pos dl-chars dl-fonts findex dl-len)
|
|---|
| 389 | (replace-si-line si-line-chars dl-chars findex findex dl-len))
|
|---|
| 390 | ;; When the dis-line is an initial substring of what's on the screen.
|
|---|
| 391 | ((= findex dl-len)
|
|---|
| 392 | (funcall (tty-device-clear-to-eol device) hunk dl-len dl-pos))
|
|---|
| 393 | ;; Otherwise, blast dl-chars and clear to eol as necessary.
|
|---|
| 394 | (t (funcall (tty-device-display-string device)
|
|---|
| 395 | hunk findex dl-pos dl-chars dl-fonts findex dl-len)
|
|---|
| 396 | (when (< dl-len si-line-length)
|
|---|
| 397 | (funcall (tty-device-clear-to-eol device) hunk dl-len dl-pos))
|
|---|
| 398 | (replace-si-line si-line-chars dl-chars findex findex dl-len)))
|
|---|
| 399 | (setf (si-line-length screen-image-line) dl-len)
|
|---|
| 400 | (setf (si-line-fonts screen-image-line) dl-fonts)))
|
|---|
| 401 | (setf (dis-line-flags dl) unaltered-bits)
|
|---|
| 402 | (setf (dis-line-delta dl) 0)))
|
|---|
| 403 |
|
|---|
| 404 |
|
|---|
| 405 | |
|---|
| 406 |
|
|---|
| 407 | ;;;; Smart window redisplay -- operation queues and internal screen image.
|
|---|
| 408 |
|
|---|
| 409 | ;;; This is used for creating temporary smart redisplay structures.
|
|---|
| 410 | ;;;
|
|---|
| 411 | (defconstant tty-hunk-height-limit 100)
|
|---|
| 412 |
|
|---|
| 413 |
|
|---|
| 414 | ;;; Queues for redisplay operations and access macros.
|
|---|
| 415 | ;;;
|
|---|
| 416 | (defvar *tty-line-insertions* (make-array (* 2 tty-hunk-height-limit)))
|
|---|
| 417 |
|
|---|
| 418 | (defvar *tty-line-deletions* (make-array (* 2 tty-hunk-height-limit)))
|
|---|
| 419 |
|
|---|
| 420 | (defvar *tty-line-writes* (make-array tty-hunk-height-limit))
|
|---|
| 421 |
|
|---|
| 422 | (defvar *tty-line-moves* (make-array tty-hunk-height-limit))
|
|---|
| 423 |
|
|---|
| 424 | (eval-when (:compile-toplevel :execute)
|
|---|
| 425 |
|
|---|
| 426 | (defmacro queue (value queue ptr)
|
|---|
| 427 | `(progn
|
|---|
| 428 | (setf (svref ,queue ,ptr) ,value)
|
|---|
| 429 | (the fixnum (incf (the fixnum ,ptr)))))
|
|---|
| 430 |
|
|---|
| 431 | (defmacro dequeue (queue ptr)
|
|---|
| 432 | `(prog1
|
|---|
| 433 | (svref ,queue ,ptr)
|
|---|
| 434 | (the fixnum (incf (the fixnum ,ptr)))))
|
|---|
| 435 |
|
|---|
| 436 | ) ;eval-when
|
|---|
| 437 |
|
|---|
| 438 | ;;; INSERT-LINE-COUNT is used in TTY-SMART-WINDOW-REDISPLAY. The counting is
|
|---|
| 439 | ;;; based on calls to QUEUE in COMPUTE-TTY-CHANGES.
|
|---|
| 440 | ;;;
|
|---|
| 441 | (defun insert-line-count (ins)
|
|---|
| 442 | (do ((i 1 (+ i 2))
|
|---|
| 443 | (count 0 (+ count (svref *tty-line-insertions* i))))
|
|---|
| 444 | ((> i ins) count)))
|
|---|
| 445 |
|
|---|
| 446 |
|
|---|
| 447 | ;;; Temporary storage for screen-image lines and accessing macros.
|
|---|
| 448 | ;;;
|
|---|
| 449 | (defvar *screen-image-temp* (make-array tty-hunk-height-limit))
|
|---|
| 450 |
|
|---|
| 451 | (eval-when (:compile-toplevel :execute)
|
|---|
| 452 |
|
|---|
| 453 | ;;; DELETE-SI-LINES is used in DO-LINE-DELETIONS to simulate what's
|
|---|
| 454 | ;;; happening to the screen in a device's screen-image. At y, num
|
|---|
| 455 | ;;; lines are deleted and saved in *screen-image-temp*; fsil is the
|
|---|
| 456 | ;;; end of the free screen image lines saved here. Also, we must
|
|---|
| 457 | ;;; move lines up in the screen-image structure. In the outer loop
|
|---|
| 458 | ;;; we save lines in the temp storage and move lines up at the same
|
|---|
| 459 | ;;; time. In the termination/inner loop we move any lines that still
|
|---|
| 460 | ;;; need to be moved up. The screen-length is adjusted by the fsil
|
|---|
| 461 | ;;; because any time a deletion is in progress, there are fsil bogus
|
|---|
| 462 | ;;; lines at the bottom of the screen image from lines being moved
|
|---|
| 463 | ;;; up previously.
|
|---|
| 464 | ;;;
|
|---|
| 465 | (defmacro delete-si-lines (screen-image y num fsil screen-length)
|
|---|
| 466 | (let ((do-screen-image (gensym)) (delete-index (gensym))
|
|---|
| 467 | (free-lines (gensym)) (source-index (gensym)) (target-index (gensym))
|
|---|
| 468 | (n (gensym)) (do-screen-length (gensym)) (do-y (gensym)))
|
|---|
| 469 | `(let ((,do-screen-image ,screen-image)
|
|---|
| 470 | (,do-screen-length (- ,screen-length fsil))
|
|---|
| 471 | (,do-y ,y))
|
|---|
| 472 | (declare (fixnum ,do-screen-length ,do-y))
|
|---|
| 473 | (do ((,delete-index ,do-y (1+ ,delete-index))
|
|---|
| 474 | (,free-lines ,fsil (1+ ,free-lines))
|
|---|
| 475 | (,source-index (+ ,do-y ,num) (1+ ,source-index))
|
|---|
| 476 | (,n ,num (1- ,n)))
|
|---|
| 477 | ((zerop ,n)
|
|---|
| 478 | (do ((,target-index ,delete-index (1+ ,target-index))
|
|---|
| 479 | (,source-index ,source-index (1+ ,source-index)))
|
|---|
| 480 | ((>= ,source-index ,do-screen-length))
|
|---|
| 481 | (declare (fixnum ,target-index ,source-index))
|
|---|
| 482 | (setf (si-line ,do-screen-image ,target-index)
|
|---|
| 483 | (si-line ,do-screen-image ,source-index))))
|
|---|
| 484 | (declare (fixnum ,delete-index ,free-lines ,source-index ,n))
|
|---|
| 485 | (setf (si-line *screen-image-temp* ,free-lines)
|
|---|
| 486 | (si-line ,do-screen-image ,delete-index))
|
|---|
| 487 | (when (< ,source-index ,do-screen-length)
|
|---|
| 488 | (setf (si-line ,do-screen-image ,delete-index)
|
|---|
| 489 | (si-line ,do-screen-image ,source-index)))))))
|
|---|
| 490 |
|
|---|
| 491 |
|
|---|
| 492 | ;;; INSERT-SI-LINES is used in DO-LINE-INSERTIONS to simulate what's
|
|---|
| 493 | ;;; happening to the screen in a device's screen-image. At y, num free
|
|---|
| 494 | ;;; lines are inserted from *screen-image-temp*; fsil is the end of the
|
|---|
| 495 | ;;; free lines. When copying lines down in screen-image, we must start
|
|---|
| 496 | ;;; with the lower lines and end with the higher ones, so we don't trash
|
|---|
| 497 | ;;; any lines. The outer loop does all the copying, and the termination/
|
|---|
| 498 | ;;; inner loop inserts the free screen image lines, setting their length
|
|---|
| 499 | ;;; to zero.
|
|---|
| 500 | ;;;
|
|---|
| 501 | (defmacro insert-si-lines (screen-image y num fsil screen-length)
|
|---|
| 502 | (let ((do-screen-image (gensym)) (source-index (gensym))
|
|---|
| 503 | (target-index (gensym)) (target-terminus (gensym))
|
|---|
| 504 | (do-screen-length (gensym)) (temp (gensym)) (do-y (gensym))
|
|---|
| 505 | (insert-index (gensym)) (free-lines-index (gensym))
|
|---|
| 506 | (n (gensym)))
|
|---|
| 507 | `(let ((,do-screen-length ,screen-length)
|
|---|
| 508 | (,do-screen-image ,screen-image)
|
|---|
| 509 | (,do-y ,y))
|
|---|
| 510 | (do ((,target-terminus (1- (+ ,do-y ,num))) ; (1- target-start)
|
|---|
| 511 | (,source-index (- ,do-screen-length ,fsil 1) ; (1- source-end)
|
|---|
| 512 | (1- ,source-index))
|
|---|
| 513 | (,target-index (- (+ ,do-screen-length ,num)
|
|---|
| 514 | ,fsil 1) ; (1- target-end)
|
|---|
| 515 | (1- ,target-index)))
|
|---|
| 516 | ((= ,target-index ,target-terminus)
|
|---|
| 517 | (do ((,insert-index ,do-y (1+ ,insert-index))
|
|---|
| 518 | (,free-lines-index (1- ,fsil) (1- ,free-lines-index))
|
|---|
| 519 | (,n ,num (1- ,n)))
|
|---|
| 520 | ((zerop ,n))
|
|---|
| 521 | (declare (fixnum ,insert-index ,free-lines-index ,n))
|
|---|
| 522 | (let ((,temp (si-line *screen-image-temp* ,free-lines-index)))
|
|---|
| 523 | (setf (si-line-length ,temp) 0)
|
|---|
| 524 | (setf (si-line-fonts ,temp) nil)
|
|---|
| 525 | (setf (si-line ,do-screen-image ,insert-index) ,temp)))
|
|---|
| 526 | (decf ,fsil ,num))
|
|---|
| 527 | (declare (fixnum ,target-terminus ,source-index ,target-index))
|
|---|
| 528 | (setf (si-line ,do-screen-image ,target-index)
|
|---|
| 529 | (si-line ,do-screen-image ,source-index))))))
|
|---|
| 530 |
|
|---|
| 531 | ) ;eval-when
|
|---|
| 532 |
|
|---|
| 533 |
|
|---|
| 534 | |
|---|
| 535 |
|
|---|
| 536 | ;;;; Smart window redisplay -- the function.
|
|---|
| 537 |
|
|---|
| 538 | ;;; TTY-SMART-WINDOW-REDISPLAY sees if only one line changed after
|
|---|
| 539 | ;;; some preliminary processing. If more than one line changed,
|
|---|
| 540 | ;;; then we compute changes to make to the screen in the form of
|
|---|
| 541 | ;;; line insertions, deletions, and writes. Deletions must be done
|
|---|
| 542 | ;;; first, so lines are not lost off the bottom of the screen by
|
|---|
| 543 | ;;; inserting lines.
|
|---|
| 544 | ;;;
|
|---|
| 545 | (defun tty-smart-window-redisplay (window)
|
|---|
| 546 | (let* ((hunk (window-hunk window))
|
|---|
| 547 | (device (device-hunk-device hunk)))
|
|---|
| 548 | (let ((first-changed (window-first-changed window))
|
|---|
| 549 | (last-changed (window-last-changed window)))
|
|---|
| 550 | ;; Is there anything to do?
|
|---|
| 551 | (unless (eq first-changed the-sentinel)
|
|---|
| 552 | (if (and (eq first-changed last-changed)
|
|---|
| 553 | (zerop (dis-line-delta (car first-changed))))
|
|---|
| 554 | ;; One line-changed.
|
|---|
| 555 | (tty-smart-line-redisplay device hunk (car first-changed))
|
|---|
| 556 | ;; More lines changed.
|
|---|
| 557 | (multiple-value-bind (ins outs writes moves)
|
|---|
| 558 | (compute-tty-changes
|
|---|
| 559 | first-changed last-changed
|
|---|
| 560 | (tty-hunk-modeline-pos hunk))
|
|---|
| 561 | (let ((ratio (variable-value 'hemlock::scroll-redraw-ratio)))
|
|---|
| 562 | (cond ((and ratio
|
|---|
| 563 | (> (/ (insert-line-count ins)
|
|---|
| 564 | (tty-hunk-text-height hunk))
|
|---|
| 565 | ratio))
|
|---|
| 566 | (do-semi-dumb-line-writes first-changed last-changed
|
|---|
| 567 | hunk))
|
|---|
| 568 | (t
|
|---|
| 569 | (do-line-insertions hunk ins
|
|---|
| 570 | (do-line-deletions hunk outs))
|
|---|
| 571 | (note-line-moves moves)
|
|---|
| 572 | (do-line-writes hunk writes))))))
|
|---|
| 573 | ;; Set the bounds so we know we displayed...
|
|---|
| 574 | (setf (window-first-changed window) the-sentinel
|
|---|
| 575 | (window-last-changed window) (window-first-line window))))
|
|---|
| 576 | ;;
|
|---|
| 577 | ;; Clear any extra lines at the end of the window.
|
|---|
| 578 | (let ((pos (dis-line-position (car (window-last-line window)))))
|
|---|
| 579 | (when (< pos (1- (window-height window)))
|
|---|
| 580 | (tty-smart-clear-to-eow hunk (1+ pos)))
|
|---|
| 581 | (setf (window-old-lines window) pos))
|
|---|
| 582 | ;;
|
|---|
| 583 | ;; Update the modeline if needed.
|
|---|
| 584 | (when (window-modeline-buffer window)
|
|---|
| 585 | (let ((dl (window-modeline-dis-line window)))
|
|---|
| 586 | (when (/= (dis-line-flags dl) unaltered-bits)
|
|---|
| 587 | (unwind-protect
|
|---|
| 588 | (progn
|
|---|
| 589 | (funcall (tty-device-standout-init device) hunk)
|
|---|
| 590 | (tty-smart-line-redisplay device hunk dl
|
|---|
| 591 | (tty-hunk-modeline-pos hunk)))
|
|---|
| 592 | (funcall (tty-device-standout-end device) hunk)))))))
|
|---|
| 593 |
|
|---|
| 594 |
|
|---|
| 595 | |
|---|
| 596 |
|
|---|
| 597 | ;;;; Smart window redisplay -- computing changes to the display.
|
|---|
| 598 |
|
|---|
| 599 | ;;; There is a lot of documentation here to help since this code is not
|
|---|
| 600 | ;;; obviously correct. The code is not that cryptic, but the correctness
|
|---|
| 601 | ;;; of the algorithm is somewhat. Most of the complexity is in handling
|
|---|
| 602 | ;;; lines that moved on the screen which the introduction deals with.
|
|---|
| 603 | ;;; Also, the block of documentation immediately before the function
|
|---|
| 604 | ;;; COMPUTE-TTY-CHANGES has its largest portion dedicated to this part of
|
|---|
| 605 | ;;; the function which is the largest block of code in the function.
|
|---|
| 606 |
|
|---|
| 607 | ;;; The window image dis-lines are annotated with the difference between
|
|---|
| 608 | ;;; their current intended locations and their previous locations in the
|
|---|
| 609 | ;;; window. This delta (distance moved) is negative for an upward move and
|
|---|
| 610 | ;;; positive for a downward move. To determine what to do with moved
|
|---|
| 611 | ;;; groups of lines, we consider the transition (or difference in deltas)
|
|---|
| 612 | ;;; between two adjacent groups as we look at the window's dis-lines moving
|
|---|
| 613 | ;;; down the window image, disregarding whether they are contiguous (having
|
|---|
| 614 | ;;; moved only by a different delta) or separated by some lines (such as
|
|---|
| 615 | ;;; lines that are new and unmoved).
|
|---|
| 616 | ;;;
|
|---|
| 617 | ;;; Considering the transition between moved groups makes sense because a
|
|---|
| 618 | ;;; given group's delta affects all the lines below it since the dis-lines
|
|---|
| 619 | ;;; reflect the window's buffer's actual lines which are all connected in
|
|---|
| 620 | ;;; series. Therefore, if the previous group moved up some delta number of
|
|---|
| 621 | ;;; lines because of line deletions, then the lines below this group (down
|
|---|
| 622 | ;;; to the last line of the window image) moved up by the same delta too,
|
|---|
| 623 | ;;; unless one of the following is true:
|
|---|
| 624 | ;;; 1] The lines below the group moved up by a greater delta, possibly
|
|---|
| 625 | ;;; due to multiple disjoint buffer line deletions.
|
|---|
| 626 | ;;; 2] The lines below the group moved up by a lesser delta, possibly
|
|---|
| 627 | ;;; due to a number (less than the previous delta) of new line
|
|---|
| 628 | ;;; insertions below the group that moved up.
|
|---|
| 629 | ;;; 3] The lines below the group moved down, possibly due to a number
|
|---|
| 630 | ;;; (greater than the previous delta) of new line insertions below
|
|---|
| 631 | ;;; the group that moved up.
|
|---|
| 632 | ;;; Similarly, if the previous group moved down some delta number of lines
|
|---|
| 633 | ;;; because of new line insertions, then the lines below this group (down
|
|---|
| 634 | ;;; to the last line of the window image not to fall off the window's lower
|
|---|
| 635 | ;;; edge) moved down by the same delta too, unless one of the following is
|
|---|
| 636 | ;;; true:
|
|---|
| 637 | ;;; 1] The lines below the group moved down by a greater delta, possibly
|
|---|
| 638 | ;;; due to multiple disjoint buffer line insertions.
|
|---|
| 639 | ;;; 2] The lines below the group moved down by a lesser delta, possibly
|
|---|
| 640 | ;;; due to a number (less than the previous delta) of line deletions
|
|---|
| 641 | ;;; below the group that moved down.
|
|---|
| 642 | ;;; 3] The lines below the group moved up, possibly due to a number
|
|---|
| 643 | ;;; (greater than the previous delta) of line deletions below the
|
|---|
| 644 | ;;; group that moved down.
|
|---|
| 645 | ;;;
|
|---|
| 646 | ;;; Now we can see how the first moved group affects the window image below
|
|---|
| 647 | ;;; it except where there is a lower group of lines that have moved a
|
|---|
| 648 | ;;; different delta due to separate operations on the buffer's lines viewed
|
|---|
| 649 | ;;; through a window. We can see that this different delta is the expected
|
|---|
| 650 | ;;; effect throughout the window image below the second group, unless
|
|---|
| 651 | ;;; something lower down again has affected the window image. Also, in the
|
|---|
| 652 | ;;; case of a last group of lines that moved up, the group will never
|
|---|
| 653 | ;;; reflect all of the lines in the window image from the first line to
|
|---|
| 654 | ;;; move down to the bottom of the window image because somewhere down below
|
|---|
| 655 | ;;; the group that moved up are some new lines that have just been drawn up
|
|---|
| 656 | ;;; into the window's image.
|
|---|
| 657 | ;;;
|
|---|
| 658 |
|
|---|
| 659 | ;;; COMPUTE-TTY-CHANGES is used once in TTY-SMART-WINDOW-REDISPLAY.
|
|---|
| 660 | ;;; It goes through all the display lines for a window recording where
|
|---|
| 661 | ;;; lines need to be inserted, deleted, or written to make the screen
|
|---|
| 662 | ;;; consistent with the internal image of the screen. Pointers to
|
|---|
| 663 | ;;; the insertions, deletions, and writes that have to be done are
|
|---|
| 664 | ;;; returned.
|
|---|
| 665 | ;;;
|
|---|
| 666 | ;;; If a line is new, then simply queue it to be written.
|
|---|
| 667 | ;;;
|
|---|
| 668 | ;;; If a line is moved and/or changed, then we compute the difference
|
|---|
| 669 | ;;; between the last block of lines that moved with the same delta and the
|
|---|
| 670 | ;;; current block of lines that moved with the current delta. If this
|
|---|
| 671 | ;;; difference is positive, then some lines need to be deleted. Since we
|
|---|
| 672 | ;;; do all the line deletions first to prevent line insertions from
|
|---|
| 673 | ;;; dropping lines off the bottom of the screen, we have to compute the
|
|---|
| 674 | ;;; position of line deletions using the cumulative insertions
|
|---|
| 675 | ;;; (cum-inserts). Without any insertions, deletions may be done right at
|
|---|
| 676 | ;;; the dis-line's new position. With insertions needed above a given
|
|---|
| 677 | ;;; deletion point combined with the fact that deletions are all done
|
|---|
| 678 | ;;; first, the location for the deletion is higher than it would be without
|
|---|
| 679 | ;;; the insertions being done above the deletions. The location of the
|
|---|
| 680 | ;;; deletion is higher by the number of insertions we have currently put
|
|---|
| 681 | ;;; off. When computing the position of line insertions (a negative delta
|
|---|
| 682 | ;;; transition), we do not need to consider the cumulative insertions or
|
|---|
| 683 | ;;; cumulative deletions since everything above the point of insertion
|
|---|
| 684 | ;;; (both deletions and insertions) has been done. Because of the screen
|
|---|
| 685 | ;;; state being correct above the point of an insertion, the screen is only
|
|---|
| 686 | ;;; off by the delta transition number of lines. After determining the
|
|---|
| 687 | ;;; line insertions or deletions, loop over contiguous lines with the same
|
|---|
| 688 | ;;; delta queuing any changed ones to be written. The delta and flag
|
|---|
| 689 | ;;; fields are initialized according to the need to be written; since
|
|---|
| 690 | ;;; redisplay may be interrupted by more user input after moves have been
|
|---|
| 691 | ;;; done to the screen, we save the changed bit on, so the line will be
|
|---|
| 692 | ;;; queued to be written after redisplay is re-entered.
|
|---|
| 693 | ;;;
|
|---|
| 694 | ;;; If the line is changed or new, then queue it to be written. Since we can
|
|---|
| 695 | ;;; abort out of the actual dislpay at any time (due to pending input), we
|
|---|
| 696 | ;;; don't clear the flags or delta here. A dis-line may be groveled many times
|
|---|
| 697 | ;;; by this function before it actually makes it to the screen, so we may have
|
|---|
| 698 | ;;; odd combinations of bits such as both new and changed.
|
|---|
| 699 | ;;;
|
|---|
| 700 | ;;; Otherwise, get the next display line, loop, and see if it's
|
|---|
| 701 | ;;; interesting.
|
|---|
| 702 | ;;;
|
|---|
| 703 | (defun compute-tty-changes (first-changed last-changed modeline-pos)
|
|---|
| 704 | (declare (fixnum modeline-pos))
|
|---|
| 705 | (let* ((dl first-changed)
|
|---|
| 706 | (flags (dis-line-flags (car dl)))
|
|---|
| 707 | (ins 0) (outs 0) (writes 0) (moves 0)
|
|---|
| 708 | (prev-delta 0) (cum-deletes 0) (net-delta 0) (cum-inserts 0)
|
|---|
| 709 | prev)
|
|---|
| 710 | (declare (fixnum flags ins outs writes moves prev-delta cum-deletes
|
|---|
| 711 | net-delta cum-inserts))
|
|---|
| 712 | (loop
|
|---|
| 713 | (cond
|
|---|
| 714 | ((logtest flags new-bit)
|
|---|
| 715 | (queue (car dl) *tty-line-writes* writes)
|
|---|
| 716 | (next-dis-line))
|
|---|
| 717 | ((logtest flags moved-bit)
|
|---|
| 718 | (let* ((start-dl (car dl))
|
|---|
| 719 | (start-pos (dis-line-position start-dl))
|
|---|
| 720 | (curr-delta (dis-line-delta start-dl))
|
|---|
| 721 | (delta-delta (- prev-delta curr-delta))
|
|---|
| 722 | (car-dl start-dl))
|
|---|
| 723 | (declare (fixnum start-pos curr-delta delta-delta))
|
|---|
| 724 | (cond ((plusp delta-delta)
|
|---|
| 725 | (queue (the fixnum (- start-pos cum-inserts))
|
|---|
| 726 | *tty-line-deletions* outs)
|
|---|
| 727 | (queue delta-delta *tty-line-deletions* outs)
|
|---|
| 728 | (incf cum-deletes delta-delta)
|
|---|
| 729 | (decf net-delta delta-delta))
|
|---|
| 730 | ((minusp delta-delta)
|
|---|
| 731 | (let ((eff-pos (the fixnum (+ start-pos delta-delta)))
|
|---|
| 732 | (num (the fixnum (- delta-delta))))
|
|---|
| 733 | (queue eff-pos *tty-line-insertions* ins)
|
|---|
| 734 | (queue num *tty-line-insertions* ins)
|
|---|
| 735 | (incf net-delta num)
|
|---|
| 736 | (incf cum-inserts num))))
|
|---|
| 737 | (loop
|
|---|
| 738 | (if (logtest flags (logior changed-bit new-bit))
|
|---|
| 739 | (queue car-dl *tty-line-writes* writes)
|
|---|
| 740 | (queue car-dl *tty-line-moves* moves))
|
|---|
| 741 | (next-dis-line)
|
|---|
| 742 | (setf car-dl (car dl))
|
|---|
| 743 | (when (or (eq prev last-changed)
|
|---|
| 744 | (/= (the fixnum (dis-line-delta car-dl)) curr-delta))
|
|---|
| 745 | (setf prev-delta curr-delta)
|
|---|
| 746 | (return)))))
|
|---|
| 747 | ((logtest flags (logior changed-bit new-bit))
|
|---|
| 748 | (queue (car dl) *tty-line-writes* writes)
|
|---|
| 749 | (next-dis-line))
|
|---|
| 750 | (t
|
|---|
| 751 | (next-dis-line)))
|
|---|
| 752 |
|
|---|
| 753 | (when (eq prev last-changed)
|
|---|
| 754 | (unless (zerop net-delta)
|
|---|
| 755 | (cond ((plusp net-delta)
|
|---|
| 756 | (queue (the fixnum (- modeline-pos cum-deletes net-delta))
|
|---|
| 757 | *tty-line-deletions* outs)
|
|---|
| 758 | (queue net-delta *tty-line-deletions* outs))
|
|---|
| 759 | (t (queue (the fixnum (+ modeline-pos net-delta))
|
|---|
| 760 | *tty-line-insertions* ins)
|
|---|
| 761 | (queue (the fixnum (- net-delta))
|
|---|
| 762 | *tty-line-insertions* ins))))
|
|---|
| 763 | (return (values ins outs writes moves))))))
|
|---|
| 764 |
|
|---|
| 765 | |
|---|
| 766 |
|
|---|
| 767 | ;;;; Smart window redisplay -- operation methods.
|
|---|
| 768 |
|
|---|
| 769 | ;;; TTY-SMART-CLEAR-TO-EOW clears lines y through the last text line of hunk.
|
|---|
| 770 | ;;; It takes care not to clear a line unless it really has some characters
|
|---|
| 771 | ;;; displayed on it. It also maintains the device's screen image lines.
|
|---|
| 772 | ;;;
|
|---|
| 773 | (defun tty-smart-clear-to-eow (hunk y)
|
|---|
| 774 | (let* ((device (device-hunk-device hunk))
|
|---|
| 775 | (screen-image (tty-device-screen-image device))
|
|---|
| 776 | (clear-to-eol (tty-device-clear-to-eol device)))
|
|---|
| 777 | (select-hunk hunk)
|
|---|
| 778 | (do ((y y (1+ y))
|
|---|
| 779 | (si-idx (+ *hunk-top-line* y) (1+ si-idx))
|
|---|
| 780 | (last (tty-hunk-text-position hunk)))
|
|---|
| 781 | ((> si-idx last))
|
|---|
| 782 | (declare (fixnum y si-idx last))
|
|---|
| 783 | (let ((si-line (si-line screen-image si-idx)))
|
|---|
| 784 | (unless (zerop (si-line-length si-line))
|
|---|
| 785 | (funcall clear-to-eol hunk 0 y)
|
|---|
| 786 | (setf (si-line-length si-line) 0)
|
|---|
| 787 | (setf (si-line-fonts si-line) nil))))))
|
|---|
| 788 |
|
|---|
| 789 | ;;; NOTE-LINE-MOVES -- Internal
|
|---|
| 790 | ;;;
|
|---|
| 791 | ;;; Clear out the flags and delta of lines that have been moved.
|
|---|
| 792 | ;;;
|
|---|
| 793 | (defun note-line-moves (moves)
|
|---|
| 794 | (let ((i 0))
|
|---|
| 795 | (loop
|
|---|
| 796 | (when (= i moves) (return))
|
|---|
| 797 | (let ((dl (dequeue *tty-line-moves* i)))
|
|---|
| 798 | (setf (dis-line-flags dl) unaltered-bits)
|
|---|
| 799 | (setf (dis-line-delta dl) 0)))))
|
|---|
| 800 |
|
|---|
| 801 | ;;; DO-LINE-DELETIONS pops elements off the *tty-lines-deletions* queue,
|
|---|
| 802 | ;;; deleting lines from hunk's area of the screen. The internal screen
|
|---|
| 803 | ;;; image is updated, and the total number of lines deleted is returned.
|
|---|
| 804 | ;;;
|
|---|
| 805 | (defun do-line-deletions (hunk outs)
|
|---|
| 806 | (declare (fixnum outs))
|
|---|
| 807 | (let* ((i 0)
|
|---|
| 808 | (device (device-hunk-device hunk))
|
|---|
| 809 | (fun (tty-device-delete-line device))
|
|---|
| 810 | (fsil 0)) ;free-screen-image-lines
|
|---|
| 811 | (declare (fixnum i fsil))
|
|---|
| 812 | (loop
|
|---|
| 813 | (when (= i outs) (return fsil))
|
|---|
| 814 | (let ((y (dequeue *tty-line-deletions* i))
|
|---|
| 815 | (num (dequeue *tty-line-deletions* i)))
|
|---|
| 816 | (declare (fixnum y num))
|
|---|
| 817 | (funcall fun hunk 0 y num)
|
|---|
| 818 | (select-hunk hunk)
|
|---|
| 819 | (delete-si-lines (tty-device-screen-image device)
|
|---|
| 820 | (+ *hunk-top-line* y) num fsil
|
|---|
| 821 | (tty-device-lines device))
|
|---|
| 822 | (incf fsil num)))))
|
|---|
| 823 |
|
|---|
| 824 | ;;; DO-LINE-INSERTIONS pops elements off the *tty-line-insertions* queue,
|
|---|
| 825 | ;;; inserting lines into hunk's area of the screen. The internal screen
|
|---|
| 826 | ;;; image is updated using free screen image lines pointed to by fsil.
|
|---|
| 827 | ;;;
|
|---|
| 828 | (defun do-line-insertions (hunk ins fsil)
|
|---|
| 829 | (declare (fixnum ins fsil))
|
|---|
| 830 | (let* ((i 0)
|
|---|
| 831 | (device (device-hunk-device hunk))
|
|---|
| 832 | (fun (tty-device-open-line device)))
|
|---|
| 833 | (declare (fixnum i))
|
|---|
| 834 | (loop
|
|---|
| 835 | (when (= i ins) (return))
|
|---|
| 836 | (let ((y (dequeue *tty-line-insertions* i))
|
|---|
| 837 | (num (dequeue *tty-line-insertions* i)))
|
|---|
| 838 | (declare (fixnum y num))
|
|---|
| 839 | (funcall fun hunk 0 y num)
|
|---|
| 840 | (select-hunk hunk)
|
|---|
| 841 | (insert-si-lines (tty-device-screen-image device)
|
|---|
| 842 | (+ *hunk-top-line* y) num fsil
|
|---|
| 843 | (tty-device-lines device))))))
|
|---|
| 844 |
|
|---|
| 845 | ;;; DO-LINE-WRITES pops elements off the *tty-line-writes* queue, displaying
|
|---|
| 846 | ;;; these dis-lines with TTY-SMART-LINE-REDISPLAY. We force output after
|
|---|
| 847 | ;;; each line, so the user can see how far we've gotten in case he chooses
|
|---|
| 848 | ;;; to give more editor commands which will abort redisplay until there's no
|
|---|
| 849 | ;;; more input.
|
|---|
| 850 | ;;;
|
|---|
| 851 | (defun do-line-writes (hunk writes)
|
|---|
| 852 | (declare (fixnum writes))
|
|---|
| 853 | (let* ((i 0)
|
|---|
| 854 | (device (device-hunk-device hunk))
|
|---|
| 855 | (force-output (device-force-output device)))
|
|---|
| 856 | (declare (fixnum i))
|
|---|
| 857 | (loop
|
|---|
| 858 | (when (= i writes) (return))
|
|---|
| 859 | (tty-smart-line-redisplay device hunk (dequeue *tty-line-writes* i))
|
|---|
| 860 | (when force-output (funcall force-output)))))
|
|---|
| 861 |
|
|---|
| 862 | ;;; TTY-SMART-LINE-REDISPLAY uses an auxiliary screen image structure to
|
|---|
| 863 | ;;; try to do minimal character shipping to the terminal. Roughly, we find
|
|---|
| 864 | ;;; the first different character when comparing what's on the screen and
|
|---|
| 865 | ;;; what should be there; we will start altering the line after this same
|
|---|
| 866 | ;;; initial substring. Then we find, from the end, the first character
|
|---|
| 867 | ;;; that is different, blasting out characters to the lesser of the two
|
|---|
| 868 | ;;; indexes. If the dis-line index is lesser, we have some characters to
|
|---|
| 869 | ;;; delete from the screen, and if the screen index is lesser, we have some
|
|---|
| 870 | ;;; additional dis-line characters to insert. There are a few special
|
|---|
| 871 | ;;; cases that allow us to punt out of the above algorithm sketch. If the
|
|---|
| 872 | ;;; terminal doesn't have insert mode or delete mode, we have blast out to
|
|---|
| 873 | ;;; the end of the dis-line and possibly clear to the end of the screen's
|
|---|
| 874 | ;;; line, as appropriate. Sometimes we don't use insert or delete mode
|
|---|
| 875 | ;;; because of the overhead cost in characters; it simply is cheaper to
|
|---|
| 876 | ;;; blast out characters and clear to eol.
|
|---|
| 877 | ;;;
|
|---|
| 878 | (defun tty-smart-line-redisplay (device hunk dl
|
|---|
| 879 | &optional (dl-pos (dis-line-position dl)))
|
|---|
| 880 | (declare (fixnum dl-pos))
|
|---|
| 881 | (let* ((dl-chars (dis-line-chars dl))
|
|---|
| 882 | (dl-len (dis-line-length dl))
|
|---|
| 883 | (dl-fonts (compute-font-usages dl)))
|
|---|
| 884 | (declare (fixnum dl-len) (simple-string dl-chars))
|
|---|
| 885 | (when (listen-editor-input *editor-input*)
|
|---|
| 886 | (throw 'redisplay-catcher :editor-input))
|
|---|
| 887 | (select-hunk hunk)
|
|---|
| 888 | (let* ((screen-image-line (si-line (tty-device-screen-image device)
|
|---|
| 889 | (+ *hunk-top-line* dl-pos)))
|
|---|
| 890 | (si-line-chars (si-line-chars screen-image-line))
|
|---|
| 891 | (si-line-length (si-line-length screen-image-line))
|
|---|
| 892 | (findex (find-identical-prefix dl dl-fonts screen-image-line)))
|
|---|
| 893 | (declare (type (or fixnum null) findex) (simple-string si-line-chars))
|
|---|
| 894 | ;;
|
|---|
| 895 | ;; When the dis-line and screen chars are not string=.
|
|---|
| 896 | (when findex
|
|---|
| 897 | (block tslr-main-body
|
|---|
| 898 | ;;
|
|---|
| 899 | ;; See if the screen shows an initial substring of the dis-line.
|
|---|
| 900 | (when (= findex si-line-length)
|
|---|
| 901 | (funcall (tty-device-display-string device)
|
|---|
| 902 | hunk findex dl-pos dl-chars dl-fonts findex dl-len)
|
|---|
| 903 | (replace-si-line si-line-chars dl-chars findex findex dl-len)
|
|---|
| 904 | (return-from tslr-main-body t))
|
|---|
| 905 | ;;
|
|---|
| 906 | ;; When the dis-line is an initial substring of what's on the screen.
|
|---|
| 907 | (when (= findex dl-len)
|
|---|
| 908 | (funcall (tty-device-clear-to-eol device) hunk dl-len dl-pos)
|
|---|
| 909 | (return-from tslr-main-body t))
|
|---|
| 910 | ;;
|
|---|
| 911 | ;; Find trailing substrings that are the same.
|
|---|
| 912 | (multiple-value-bind
|
|---|
| 913 | (sindex dindex)
|
|---|
| 914 | (let ((count (find-identical-suffix dl dl-fonts
|
|---|
| 915 | screen-image-line)))
|
|---|
| 916 | (values (- si-line-length count)
|
|---|
| 917 | (- dl-len count)))
|
|---|
| 918 | (declare (fixnum sindex dindex))
|
|---|
| 919 | ;;
|
|---|
| 920 | ;; No trailing substrings -- blast and clear to eol.
|
|---|
| 921 | (when (= dindex dl-len)
|
|---|
| 922 | (funcall (tty-device-display-string device)
|
|---|
| 923 | hunk findex dl-pos dl-chars dl-fonts findex dl-len)
|
|---|
| 924 | (when (< dindex sindex)
|
|---|
| 925 | (funcall (tty-device-clear-to-eol device)
|
|---|
| 926 | hunk dl-len dl-pos))
|
|---|
| 927 | (replace-si-line si-line-chars dl-chars findex findex dl-len)
|
|---|
| 928 | (return-from tslr-main-body t))
|
|---|
| 929 | (let ((lindex (min sindex dindex)))
|
|---|
| 930 | (cond ((< lindex findex)
|
|---|
| 931 | ;; This can happen in funny situations -- believe me!
|
|---|
| 932 | (setf lindex findex))
|
|---|
| 933 | (t
|
|---|
| 934 | (funcall (tty-device-display-string device)
|
|---|
| 935 | hunk findex dl-pos dl-chars dl-fonts
|
|---|
| 936 | findex lindex)
|
|---|
| 937 | (replace-si-line si-line-chars dl-chars
|
|---|
| 938 | findex findex lindex)))
|
|---|
| 939 | (cond
|
|---|
| 940 | ((= dindex sindex))
|
|---|
| 941 | ((< dindex sindex)
|
|---|
| 942 | (let ((delete-char-num (- sindex dindex)))
|
|---|
| 943 | (cond ((and (tty-device-delete-char device)
|
|---|
| 944 | (worth-using-delete-mode
|
|---|
| 945 | device delete-char-num (- si-line-length dl-len)))
|
|---|
| 946 | (funcall (tty-device-delete-char device)
|
|---|
| 947 | hunk dindex dl-pos delete-char-num))
|
|---|
| 948 | (t
|
|---|
| 949 | (funcall (tty-device-display-string device)
|
|---|
| 950 | hunk dindex dl-pos dl-chars dl-fonts
|
|---|
| 951 | dindex dl-len)
|
|---|
| 952 | (funcall (tty-device-clear-to-eol device)
|
|---|
| 953 | hunk dl-len dl-pos)))))
|
|---|
| 954 | (t
|
|---|
| 955 | (if (and (tty-device-insert-string device)
|
|---|
| 956 | (worth-using-insert-mode device (- dindex sindex)
|
|---|
| 957 | (- dl-len sindex)))
|
|---|
| 958 | (funcall (tty-device-insert-string device)
|
|---|
| 959 | hunk sindex dl-pos dl-chars sindex dindex)
|
|---|
| 960 | (funcall (tty-device-display-string device)
|
|---|
| 961 | hunk sindex dl-pos dl-chars dl-fonts
|
|---|
| 962 | sindex dl-len))))
|
|---|
| 963 | (replace-si-line si-line-chars dl-chars
|
|---|
| 964 | lindex lindex dl-len))))
|
|---|
| 965 | (setf (si-line-length screen-image-line) dl-len)
|
|---|
| 966 | (setf (si-line-fonts screen-image-line) dl-fonts)))
|
|---|
| 967 | (setf (dis-line-flags dl) unaltered-bits)
|
|---|
| 968 | (setf (dis-line-delta dl) 0)))
|
|---|
| 969 |
|
|---|
| 970 |
|
|---|
| 971 | |
|---|
| 972 |
|
|---|
| 973 | ;;;; Device methods
|
|---|
| 974 |
|
|---|
| 975 | ;;; Initializing and exiting the device (DEVICE-INIT and DEVICE-EXIT functions).
|
|---|
| 976 | ;;; These can be found in Tty-Display-Rt.Lisp.
|
|---|
| 977 |
|
|---|
| 978 |
|
|---|
| 979 | ;;; Clearing the device (DEVICE-CLEAR functions).
|
|---|
| 980 |
|
|---|
| 981 | (defun clear-device (device)
|
|---|
| 982 | (device-write-string (tty-device-clear-string device))
|
|---|
| 983 | (cursor-motion device 0 0)
|
|---|
| 984 | (setf (tty-device-cursor-x device) 0)
|
|---|
| 985 | (setf (tty-device-cursor-y device) 0))
|
|---|
| 986 |
|
|---|
| 987 |
|
|---|
| 988 | ;;; Moving the cursor around (DEVICE-PUT-CURSOR)
|
|---|
| 989 |
|
|---|
| 990 | ;;; TTY-PUT-CURSOR makes sure the coordinates are mapped from the hunk's
|
|---|
| 991 | ;;; axis to the screen's and determines the minimal cost cursor motion
|
|---|
| 992 | ;;; sequence. Currently, it does no cost analysis of relative motion
|
|---|
| 993 | ;;; compared to absolute motion but simply makes sure the cursor isn't
|
|---|
| 994 | ;;; already where we want it.
|
|---|
| 995 | ;;;
|
|---|
| 996 | (defun tty-put-cursor (hunk x y)
|
|---|
| 997 | (declare (fixnum x y))
|
|---|
| 998 | (select-hunk hunk)
|
|---|
| 999 | (let ((y (the fixnum (+ *hunk-top-line* y)))
|
|---|
| 1000 | (device (device-hunk-device hunk)))
|
|---|
| 1001 | (declare (fixnum y))
|
|---|
| 1002 | (unless (and (= (the fixnum (tty-device-cursor-x device)) x)
|
|---|
| 1003 | (= (the fixnum (tty-device-cursor-y device)) y))
|
|---|
| 1004 | (cursor-motion device x y)
|
|---|
| 1005 | (setf (tty-device-cursor-x device) x)
|
|---|
| 1006 | (setf (tty-device-cursor-y device) y))))
|
|---|
| 1007 |
|
|---|
| 1008 | ;;; UPDATE-CURSOR is used in device redisplay methods to make sure the
|
|---|
| 1009 | ;;; cursor is where it should be.
|
|---|
| 1010 | ;;;
|
|---|
| 1011 | (eval-when (:compile-toplevel :execute)
|
|---|
| 1012 | (defmacro update-cursor (hunk x y)
|
|---|
| 1013 | `(funcall (device-put-cursor (device-hunk-device ,hunk)) ,hunk ,x ,y))
|
|---|
| 1014 | ) ;eval-when
|
|---|
| 1015 |
|
|---|
| 1016 | ;;; CURSOR-MOTION takes two coordinates on the screen's axis,
|
|---|
| 1017 | ;;; moving the cursor to that location. X is the column index,
|
|---|
| 1018 | ;;; and y is the line index, but Unix and Termcap believe that
|
|---|
| 1019 | ;;; the default order of indexes is first the line and then the
|
|---|
| 1020 | ;;; column or (y,x). Because of this, when reversep is non-nil,
|
|---|
| 1021 | ;;; we send first x and then y.
|
|---|
| 1022 | ;;;
|
|---|
| 1023 | (defun cursor-motion (device x y)
|
|---|
| 1024 | (let ((x-add-char (tty-device-cm-x-add-char device))
|
|---|
| 1025 | (y-add-char (tty-device-cm-y-add-char device))
|
|---|
| 1026 | (x-condx-add (tty-device-cm-x-condx-char device))
|
|---|
| 1027 | (y-condx-add (tty-device-cm-y-condx-char device))
|
|---|
| 1028 | (one-origin (tty-device-cm-one-origin device)))
|
|---|
| 1029 | (when x-add-char (incf x x-add-char))
|
|---|
| 1030 | (when (and x-condx-add (> x x-condx-add))
|
|---|
| 1031 | (incf x (tty-device-cm-x-condx-add-char device)))
|
|---|
| 1032 | (when y-add-char (incf y y-add-char))
|
|---|
| 1033 | (when (and y-condx-add (> y y-condx-add))
|
|---|
| 1034 | (incf y (tty-device-cm-y-condx-add-char device)))
|
|---|
| 1035 | (when one-origin (incf x) (incf y)))
|
|---|
| 1036 | (device-write-string (tty-device-cm-string1 device))
|
|---|
| 1037 | (let ((reversep (tty-device-cm-reversep device))
|
|---|
| 1038 | (x-pad (tty-device-cm-x-pad device))
|
|---|
| 1039 | (y-pad (tty-device-cm-y-pad device)))
|
|---|
| 1040 | (if reversep
|
|---|
| 1041 | (cm-output-coordinate x x-pad)
|
|---|
| 1042 | (cm-output-coordinate y y-pad))
|
|---|
| 1043 | (device-write-string (tty-device-cm-string2 device))
|
|---|
| 1044 | (if reversep
|
|---|
| 1045 | (cm-output-coordinate y y-pad)
|
|---|
| 1046 | (cm-output-coordinate x x-pad))
|
|---|
| 1047 | (device-write-string (tty-device-cm-string3 device))))
|
|---|
| 1048 |
|
|---|
| 1049 | ;;; CM-OUTPUT-COORDINATE outputs the coordinate with respect to the pad. If
|
|---|
| 1050 | ;;; there is a pad, then the coordinate needs to be sent as digit-char's (for
|
|---|
| 1051 | ;;; each digit in the coordinate), and if there is no pad, the coordinate needs
|
|---|
| 1052 | ;;; to be converted into a character. Using CODE-CHAR here is not really
|
|---|
| 1053 | ;;; portable. With a pad, the coordinate buffer is filled from the end as we
|
|---|
| 1054 | ;;; truncate the coordinate by 10, generating ones digits.
|
|---|
| 1055 | ;;;
|
|---|
| 1056 | (defconstant cm-coordinate-buffer-len 5)
|
|---|
| 1057 | (defvar *cm-coordinate-buffer* (make-string cm-coordinate-buffer-len))
|
|---|
| 1058 | ;;;
|
|---|
| 1059 | (defun cm-output-coordinate (coordinate pad)
|
|---|
| 1060 | (cond (pad
|
|---|
| 1061 | (let ((i (1- cm-coordinate-buffer-len)))
|
|---|
| 1062 | (loop
|
|---|
| 1063 | (when (= i -1) (error "Terminal has too many lines!"))
|
|---|
| 1064 | (multiple-value-bind (tens ones)
|
|---|
| 1065 | (truncate coordinate 10)
|
|---|
| 1066 | (setf (schar *cm-coordinate-buffer* i) (digit-char ones))
|
|---|
| 1067 | (when (zerop tens)
|
|---|
| 1068 | (dotimes (n (- pad (- cm-coordinate-buffer-len i)))
|
|---|
| 1069 | (decf i)
|
|---|
| 1070 | (setf (schar *cm-coordinate-buffer* i) #\0))
|
|---|
| 1071 | (device-write-string *cm-coordinate-buffer* i
|
|---|
| 1072 | cm-coordinate-buffer-len)
|
|---|
| 1073 | (return))
|
|---|
| 1074 | (decf i)
|
|---|
| 1075 | (setf coordinate tens)))))
|
|---|
| 1076 | (t (tty-write-char (code-char coordinate)))))
|
|---|
| 1077 |
|
|---|
| 1078 |
|
|---|
| 1079 | ;;; Writing strings (TTY-DEVICE-DISPLAY-STRING functions)
|
|---|
| 1080 |
|
|---|
| 1081 | ;;; DISPLAY-STRING is used to put a string at (x,y) on the device.
|
|---|
| 1082 | ;;;
|
|---|
| 1083 | (defun display-string (hunk x y string font-info
|
|---|
| 1084 | &optional (start 0) (end (strlen string)))
|
|---|
| 1085 | (declare (fixnum x y start end))
|
|---|
| 1086 | (update-cursor hunk x y)
|
|---|
| 1087 | ;; Ignore font info for chars before the start of the string.
|
|---|
| 1088 | (loop
|
|---|
| 1089 | (if (or (null font-info)
|
|---|
| 1090 | (< start (cddar font-info)))
|
|---|
| 1091 | (return)
|
|---|
| 1092 | (pop font-info)))
|
|---|
| 1093 | (let ((posn start))
|
|---|
| 1094 | (dolist (next-font font-info)
|
|---|
| 1095 | (let ((font (car next-font))
|
|---|
| 1096 | (start (cadr next-font))
|
|---|
| 1097 | (stop (cddr next-font)))
|
|---|
| 1098 | (when (<= end start)
|
|---|
| 1099 | (return))
|
|---|
| 1100 | (when (< posn start)
|
|---|
| 1101 | (device-write-string string posn start)
|
|---|
| 1102 | (setf posn start))
|
|---|
| 1103 | (let ((new-posn (min stop end))
|
|---|
| 1104 | (font-strings (aref *tty-font-strings* font)))
|
|---|
| 1105 | (unwind-protect
|
|---|
| 1106 | (progn
|
|---|
| 1107 | (device-write-string (car font-strings))
|
|---|
| 1108 | (device-write-string string posn new-posn))
|
|---|
| 1109 | (device-write-string (cdr font-strings)))
|
|---|
| 1110 | (setf posn new-posn))))
|
|---|
| 1111 | (when (< posn end)
|
|---|
| 1112 | (device-write-string string posn end)))
|
|---|
| 1113 | (setf (tty-device-cursor-x (device-hunk-device hunk))
|
|---|
| 1114 | (the fixnum (+ x (the fixnum (- end start))))))
|
|---|
| 1115 |
|
|---|
| 1116 | ;;; DISPLAY-STRING-CHECKING-UNDERLINES is used for terminals that special
|
|---|
| 1117 | ;;; case underlines doing an overstrike when they don't otherwise overstrike.
|
|---|
| 1118 | ;;; Note: we do not know in this code whether the terminal can backspace (or
|
|---|
| 1119 | ;;; what the sequence is), whether the terminal has insert-mode, or whether
|
|---|
| 1120 | ;;; the terminal has delete-mode.
|
|---|
| 1121 | ;;;
|
|---|
| 1122 | (defun display-string-checking-underlines (hunk x y string font-info
|
|---|
| 1123 | &optional (start 0)
|
|---|
| 1124 | (end (strlen string)))
|
|---|
| 1125 | (declare (ignore font-info))
|
|---|
| 1126 | (declare (fixnum x y start end) (simple-string string))
|
|---|
| 1127 | (update-cursor hunk x y)
|
|---|
| 1128 | (let ((upos (position #\_ string :test #'char= :start start :end end))
|
|---|
| 1129 | (device (device-hunk-device hunk)))
|
|---|
| 1130 | (if upos
|
|---|
| 1131 | (let ((previous start)
|
|---|
| 1132 | (after-pos 0))
|
|---|
| 1133 | (declare (fixnum previous after-pos))
|
|---|
| 1134 | (loop (device-write-string string previous upos)
|
|---|
| 1135 | (setf after-pos (do ((i (1+ upos) (1+ i)))
|
|---|
| 1136 | ((or (= i end)
|
|---|
| 1137 | (char/= (schar string i) #\_)) i)
|
|---|
| 1138 | (declare (fixnum i))))
|
|---|
| 1139 | (let ((ulen (the fixnum (- after-pos upos)))
|
|---|
| 1140 | (cursor-x (the fixnum (+ x (the fixnum
|
|---|
| 1141 | (- after-pos start))))))
|
|---|
| 1142 | (declare (fixnum ulen))
|
|---|
| 1143 | (dotimes (i ulen) (tty-write-char #\space))
|
|---|
| 1144 | (setf (tty-device-cursor-x device) cursor-x)
|
|---|
| 1145 | (update-cursor hunk upos y)
|
|---|
| 1146 | (dotimes (i ulen) (tty-write-char #\_))
|
|---|
| 1147 | (setf (tty-device-cursor-x device) cursor-x))
|
|---|
| 1148 | (setf previous after-pos)
|
|---|
| 1149 | (setf upos (position #\_ string :test #'char=
|
|---|
| 1150 | :start previous :end end))
|
|---|
| 1151 | (unless upos
|
|---|
| 1152 | (device-write-string string previous end)
|
|---|
| 1153 | (return))))
|
|---|
| 1154 | (device-write-string string start end))
|
|---|
| 1155 | (setf (tty-device-cursor-x device)
|
|---|
| 1156 | (the fixnum (+ x (the fixnum (- end start)))))))
|
|---|
| 1157 |
|
|---|
| 1158 |
|
|---|
| 1159 | ;;; DEVICE-WRITE-STRING is used to shove a string at the terminal regardless
|
|---|
| 1160 | ;;; of cursor position.
|
|---|
| 1161 | ;;;
|
|---|
| 1162 | (defun device-write-string (string &optional (start 0) (end (strlen string)))
|
|---|
| 1163 | (declare (fixnum start end))
|
|---|
| 1164 | (unless (= start end)
|
|---|
| 1165 | (tty-write-string string start (the fixnum (- end start)))))
|
|---|
| 1166 |
|
|---|
| 1167 |
|
|---|
| 1168 | ;;; Clearing lines (TTY-DEVICE-CLEAR-TO-EOL, DEVICE-CLEAR-LINES, and
|
|---|
| 1169 | ;;; TTY-DEVICE-CLEAR-TO-EOW functions.)
|
|---|
| 1170 |
|
|---|
| 1171 | (defun clear-to-eol (hunk x y)
|
|---|
| 1172 | (update-cursor hunk x y)
|
|---|
| 1173 | (device-write-string
|
|---|
| 1174 | (tty-device-clear-to-eol-string (device-hunk-device hunk))))
|
|---|
| 1175 |
|
|---|
| 1176 | (defun space-to-eol (hunk x y)
|
|---|
| 1177 | (declare (fixnum x))
|
|---|
| 1178 | (update-cursor hunk x y)
|
|---|
| 1179 | (let* ((device (device-hunk-device hunk))
|
|---|
| 1180 | (num (- (the fixnum (tty-device-columns device))
|
|---|
| 1181 | x)))
|
|---|
| 1182 | (declare (fixnum num))
|
|---|
| 1183 | (dotimes (i num) (tty-write-char #\space))
|
|---|
| 1184 | (setf (tty-device-cursor-x device) (+ x num))))
|
|---|
| 1185 |
|
|---|
| 1186 | (defun clear-lines (hunk x y n)
|
|---|
| 1187 | (let* ((device (device-hunk-device hunk))
|
|---|
| 1188 | (clear-to-eol (tty-device-clear-to-eol device)))
|
|---|
| 1189 | (funcall clear-to-eol hunk x y)
|
|---|
| 1190 | (do ((y (1+ y) (1+ y))
|
|---|
| 1191 | (count (1- n) (1- count)))
|
|---|
| 1192 | ((zerop count)
|
|---|
| 1193 | (setf (tty-device-cursor-x device) 0)
|
|---|
| 1194 | (setf (tty-device-cursor-y device) (1- y)))
|
|---|
| 1195 | (declare (fixnum count y))
|
|---|
| 1196 | (funcall clear-to-eol hunk 0 y))))
|
|---|
| 1197 |
|
|---|
| 1198 | (defun clear-to-eow (hunk x y)
|
|---|
| 1199 | (declare (fixnum x y))
|
|---|
| 1200 | (funcall (tty-device-clear-lines (device-hunk-device hunk))
|
|---|
| 1201 | hunk x y
|
|---|
| 1202 | (the fixnum (- (the fixnum (tty-hunk-text-height hunk)) y))))
|
|---|
| 1203 |
|
|---|
| 1204 |
|
|---|
| 1205 | ;;; Opening and Deleting lines (TTY-DEVICE-OPEN-LINE and TTY-DEVICE-DELETE-LINE)
|
|---|
| 1206 |
|
|---|
| 1207 | (defun open-tty-line (hunk x y &optional (n 1))
|
|---|
| 1208 | (update-cursor hunk x y)
|
|---|
| 1209 | (dotimes (i n)
|
|---|
| 1210 | (device-write-string (tty-device-open-line-string (device-hunk-device hunk)))))
|
|---|
| 1211 |
|
|---|
| 1212 | (defun delete-tty-line (hunk x y &optional (n 1))
|
|---|
| 1213 | (update-cursor hunk x y)
|
|---|
| 1214 | (dotimes (i n)
|
|---|
| 1215 | (device-write-string (tty-device-delete-line-string (device-hunk-device hunk)))))
|
|---|
| 1216 |
|
|---|
| 1217 |
|
|---|
| 1218 | ;;; Insert and Delete modes (TTY-DEVICE-INSERT-STRING and TTY-DEVICE-DELETE-CHAR)
|
|---|
| 1219 |
|
|---|
| 1220 | (defun tty-insert-string (hunk x y string
|
|---|
| 1221 | &optional (start 0) (end (strlen string)))
|
|---|
| 1222 | (declare (fixnum x y start end))
|
|---|
| 1223 | (update-cursor hunk x y)
|
|---|
| 1224 | (let* ((device (device-hunk-device hunk))
|
|---|
| 1225 | (init-string (tty-device-insert-init-string device))
|
|---|
| 1226 | (char-init-string (tty-device-insert-char-init-string device))
|
|---|
| 1227 | (char-end-string (tty-device-insert-char-end-string device))
|
|---|
| 1228 | (end-string (tty-device-insert-end-string device)))
|
|---|
| 1229 | (declare (type (or simple-string null) char-init-string char-end-string))
|
|---|
| 1230 | (when init-string (device-write-string init-string))
|
|---|
| 1231 | (if char-init-string
|
|---|
| 1232 | (let ((cis-len (length char-init-string))
|
|---|
| 1233 | (ces-len (length char-end-string)))
|
|---|
| 1234 | (do ((i start (1+ i)))
|
|---|
| 1235 | ((= i end))
|
|---|
| 1236 | (device-write-string char-init-string 0 cis-len)
|
|---|
| 1237 | (tty-write-char (schar string i))
|
|---|
| 1238 | (when char-end-string
|
|---|
| 1239 | (device-write-string char-end-string 0 ces-len))))
|
|---|
| 1240 | (device-write-string string start end))
|
|---|
| 1241 | (when end-string (device-write-string end-string))
|
|---|
| 1242 | (setf (tty-device-cursor-x device)
|
|---|
| 1243 | (the fixnum (+ x (the fixnum (- end start)))))))
|
|---|
| 1244 |
|
|---|
| 1245 | (defun worth-using-insert-mode (device insert-char-num chars-saved)
|
|---|
| 1246 | (let* ((init-string (tty-device-insert-init-string device))
|
|---|
| 1247 | (char-init-string (tty-device-insert-char-init-string device))
|
|---|
| 1248 | (char-end-string (tty-device-insert-char-end-string device))
|
|---|
| 1249 | (end-string (tty-device-insert-end-string device))
|
|---|
| 1250 | (cost 0))
|
|---|
| 1251 | (when init-string (incf cost (length (the simple-string init-string))))
|
|---|
| 1252 | (when char-init-string
|
|---|
| 1253 | (incf cost (* insert-char-num (+ (length (the simple-string
|
|---|
| 1254 | char-init-string))
|
|---|
| 1255 | (if char-end-string
|
|---|
| 1256 | (length (the simple-string
|
|---|
| 1257 | char-end-string))
|
|---|
| 1258 | 0)))))
|
|---|
| 1259 | (when end-string (incf cost (length (the simple-string end-string))))
|
|---|
| 1260 | (< cost chars-saved)))
|
|---|
| 1261 |
|
|---|
| 1262 | (defun delete-char (hunk x y &optional (n 1))
|
|---|
| 1263 | (declare (fixnum x y n))
|
|---|
| 1264 | (update-cursor hunk x y)
|
|---|
| 1265 | (let* ((device (device-hunk-device hunk))
|
|---|
| 1266 | (init-string (tty-device-delete-init-string device))
|
|---|
| 1267 | (end-string (tty-device-delete-end-string device))
|
|---|
| 1268 | (delete-char-string (tty-device-delete-char-string device)))
|
|---|
| 1269 | (when init-string (device-write-string init-string))
|
|---|
| 1270 | (dotimes (i n)
|
|---|
| 1271 | (device-write-string delete-char-string))
|
|---|
| 1272 | (when end-string (device-write-string end-string))))
|
|---|
| 1273 |
|
|---|
| 1274 | (defun worth-using-delete-mode (device delete-char-num clear-char-num)
|
|---|
| 1275 | (declare (fixnum delete-char-num clear-char-num))
|
|---|
| 1276 | (let ((init-string (tty-device-delete-init-string device))
|
|---|
| 1277 | (end-string (tty-device-delete-end-string device))
|
|---|
| 1278 | (delete-char-string (tty-device-delete-char-string device))
|
|---|
| 1279 | (clear-to-eol-string (tty-device-clear-to-eol-string device))
|
|---|
| 1280 | (cost 0))
|
|---|
| 1281 | (declare (type (or simple-string null) init-string end-string
|
|---|
| 1282 | delete-char-string)
|
|---|
| 1283 | (fixnum cost))
|
|---|
| 1284 | (when init-string (incf cost (the fixnum (length init-string))))
|
|---|
| 1285 | (when end-string (incf cost (the fixnum (length end-string))))
|
|---|
| 1286 | (incf cost (the fixnum
|
|---|
| 1287 | (* (the fixnum (length delete-char-string))
|
|---|
| 1288 | delete-char-num)))
|
|---|
| 1289 | (< cost (+ delete-char-num
|
|---|
| 1290 | (if clear-to-eol-string
|
|---|
| 1291 | (length clear-to-eol-string)
|
|---|
| 1292 | clear-char-num)))))
|
|---|
| 1293 |
|
|---|
| 1294 |
|
|---|
| 1295 | ;;; Standout mode (TTY-DEVICE-STANDOUT-INIT and TTY-DEVICE-STANDOUT-END)
|
|---|
| 1296 |
|
|---|
| 1297 | (defun standout-init (hunk)
|
|---|
| 1298 | (device-write-string
|
|---|
| 1299 | (tty-device-standout-init-string (device-hunk-device hunk))))
|
|---|
| 1300 |
|
|---|
| 1301 | (defun standout-end (hunk)
|
|---|
| 1302 | (device-write-string
|
|---|
| 1303 | (tty-device-standout-end-string (device-hunk-device hunk))))
|
|---|